Skip to content

Spring Data Jdbc findAll low performance for native application #1683

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Ferioney opened this issue Dec 2, 2023 · 8 comments
Closed

Spring Data Jdbc findAll low performance for native application #1683

Ferioney opened this issue Dec 2, 2023 · 8 comments
Assignees
Labels
for: external-project For an external project and not something we can fix

Comments

@Ferioney
Copy link

Ferioney commented Dec 2, 2023

Hi,

I faced a performance issue with Spring Data Jdbc with native application. It isn't easy to prepare a demo cause I found this issue in the production code. But I will try to explain.

Let's say I have a simple Spring Data repository:

public interface DemoJdbcRepository extends CrudRepository<DemoEntity, Long> {
        @Query("select d.* from demo_table d where d.status in (:statuses)")
        List<DemoEntity> getDemoByStatusId(@Param("statuses") Set<Integer> statuses);
}

In demo_table I have 600,000 records for searched statuses. For Java applications, this method takes an average of 5 sec. When I switched to the native application, this method took more than 100 sec.
I prepared a flame graph for native application:
perf-native-spring-data

Could you please explain if it is expected behavior for native? and maybe we can improve the performance of Spring Data somehow

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 2, 2023
@odrotbohm
Copy link
Member

TypeAndPath spending so much time in equals(…) looks suspicious, especially the fact that it's apparently using MethodHandles under the covers. TAP is a Java record, which means that we don't control how it's implemented. I'll forward this to the GraalVM folks.

@mp911de
Copy link
Member

mp911de commented Dec 4, 2023

Here's the related GraalVM issue: oracle/graal#4348

@Ferioney
Copy link
Author

Ferioney commented Dec 5, 2023

thanks for the answers!

I have changed TypeAndPath from record to class:

    static class TypeAndPath {

        private final TypeInformation<?> type;
        private final String path;

        private TypeAndPath(TypeInformation<?> type, String path) {
            this.type = type;
            this.path = path;
        }

        public TypeInformation<?> type() {
            return type;
        }

        public String path() {
            return path;
        }

        public static TypeAndPath of(TypeInformation<?> type, String path) {
            return new TypeAndPath(type, path);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            TypeAndPath that = (TypeAndPath) o;
            return Objects.equals(type, that.type) && Objects.equals(path, that.path);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, path);
        }
    }

and run test again (the same condition as in first comment). I see a huge performance increase (from 100sed to 11 sec):

  • JVM: ~ 5 sec
  • Native: ~ 100 sec
  • Native (TypeAndPath as class): ~ 11 sec

I prepared flame graph as well:
perf-native-spring-data-tar-class

@odrotbohm
Copy link
Member

Thanks for the input, that's very helpful. Can you clarify whether you saw the original decreased performance on a GraalVM for JDK 17 or 21?

@Ferioney
Copy link
Author

Ferioney commented Dec 5, 2023

Originally we found it in 17.
Then I tried 21 (I want to try with G1) but results were almost the same

@odrotbohm
Copy link
Member

Would you mind giving the latest snapshots (3.1 or 3.2) a try? I've resolved spring-data-commons#2997, which should also solve the bottleneck in EntityCallbackDiscoverer.

@Ferioney
Copy link
Author

Ferioney commented Dec 5, 2023

@odrotbohm thank you so much!

I tried spring-data-commons:3.1.7-SNAPSHOT and got time decrease to ~ 8 sec.

Flame graph:
perf-native-data-SNAPSHOT

@odrotbohm odrotbohm added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged labels Dec 5, 2023
@odrotbohm
Copy link
Member

Alright, I consider this fixed then for now. We're going to continue investigating how to reduce the overhead introduced by the PersistentPropertyPath creation, but that doesn't seem to particularly affect the native scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

4 participants