Repository navigation
feat(core): refacto graph query for perf improvement - #165
Conversation
Code Coverage OverviewLanguages: Java Java / code-coverage/jacocoThe overall line coverage in commit 3693dd9 in the Show a line coverage summary of the most impacted files.
Updated |
There was a problem hiding this comment.
🟡 Changes recommended
The implementation ignores property-loading controls, permits recursive path multiplication, and changes established validation and ordering behavior.
6 open findings
Restore null and empty-input guard before CTE execution · New Restore fail-fast template validation · New Honor includeProperties to avoid unnecessary property aggregation · New Preserve canonical ordering in JSON projections · New Deduplicate recursive frontier with UNION · New Add adapter tests for JSON projections and property loading · New
What changed in this PR
Optimizes entity graph retrieval through UUID summaries, recursive SQL traversal, and native JSONB projection mapping.
Changes:
- Reworks graph traversal and entity loading for fewer database round trips.
- Adds UUIDs to entity summaries and uses summaries for root lookup.
- Reduces mapping allocations and removes unused logging.
| File | Description |
|---|---|
RelationValidationServiceTest.java |
Updates summary fixtures with UUIDs. |
EntityServiceTest.java |
Updates summary construction. |
EntityGraphServiceTest.java |
Adapts graph tests to summary-based root lookup. |
application.yml |
Adds whitespace. |
application-local.yml |
Enables local SQL logging. |
JpaEntityRepository.java |
Adds UUID projections, optimized CTE, and JSONB query. |
PostgresEntityGraphAdapter.java |
Maps native JSON projections into domain entities. |
EntityGraphJsonProjection.java |
Defines the native graph projection. |
HmacSha256SecurityValidator.java |
Removes unused logging support. |
DecodingProcessor.java |
Removes unused logging support. |
EntityDtoOutMapper.java |
Removes unused logging support. |
EntityDtoOutFromEntityNodeMapper.java |
Removes unused logging support. |
EntityGraphFlatDtoOutMapper.java |
Uses imperative property mapping. |
EntityGraphController.java |
Removes redundant whitespace. |
SecurityConfiguration.java |
Removes unused logging support. |
EntityGraphService.java |
Uses lightweight summaries for graph roots. |
EntitySummary.java |
Adds the entity UUID. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Domain validation, CI formatting, and native traversal test coverage issues remain unresolved.
3 open findings
6 resolved since last review
Restore null and empty-input guard before CTE execution Deduplicate recursive frontier with UNION Preserve canonical ordering in JSON projections Honor includeProperties to avoid unnecessary property aggregation Restore fail-fast template validation Add adapter tests for JSON projections and property loading
🧠 Review effort: Balanced
|






PR Description
What this PR Provides
This PR adds several optimizations that enable a low response time for the graph and get entity endpoint
Refactored Graph UUID Discovery via Recursive CTE
UNION ALLconnecting the entire anchor set to the recursive set, eliminating the recursive term ordering conflict.CROSS JOIN LATERALforces PostgreSQL to perform direct, index-driven lookups (er.entity_id = eg.idandrte.target_entity_uuid = eg.id) for each node at the current graph frontier.Drop Defensive Pre-Validation for Entity Template Existence
Skipped the initial template existence pre-check (
SELECT et FROM entity_template...) to query theentitytable directly. If the template or entity does not exist, the domain exception is thrown immediately without wasting an initial SQL roundtrip.Move to
EntitySummaryfor Graph Root Entity & Eliminate 2 Database CallsRefactored the root entity lookup to fetch only essential entity metadata using the lightweight
EntitySummarydomain model. This eliminates 2 redundant SQL roundtrip calls previously used to fetch properties and relations.Bypass JPA Entity Mapping with PostgreSQL Native JSONB
Added
EntityGraphJsonProjectionsubqueries to aggregate nested array structures directly inside PostgreSQL memory before network transmission, preventing Cartesian explosion in exactly 1 SQL statement. Jackson parses the JSON directly into the domain model, completely skipping Hibernate entity lifecycle overhead and lazy-loading triggers.Optimize Jackson Deserialization in
PostgresEntityGraphAdapterReplaced the instantiation of
TypeReferenceobjects inside per-entity loops with pre-compiledObjectReaderstatic instances created during Spring bean initialization. Reusing thread-safeObjectReaderinstances across concurrent requests eliminates Jackson reflection setup overhead during array parsing.Replace Java Streams with Direct
forLoops in Hot Mapping CodeRefactored hot mapping paths in
EntityDtoOutFromEntityNodeMapper(which previously spent 66 ms assembling DTO trees) from functional streams (.stream().map(...).toList()) to standardforloops with pre-sized collections. This eliminates thousands of temporary iterator, stream, and lambda allocations during 1,000+ entity graph traversals, directly protecting Cloud Run containers from garbage collection CPU pauses.Added a new optional query parameter, includeEntityRootProperties to the GraphService
This optimizes response time by changing defaults around property inclusion: includeProperties is now false by default, while includeEntityRootProperties is true by default. This keeps the root entity informative for common API consumers, but avoids loading/mapping properties across related graph nodes unless explicitly requested. In practice, this significantly reduces query/mapping overhead and payload size for graph traversals, improving average latency and tail percentiles (p90/p95) while preserving backward-friendly behavior at the root level.
Optimization results
Baseline:
Load Test Comparison: Baseline vs. Optimized
Infrastructure: 1 vCPU Cloud 2GB RAM
PostgreSQL instance in Aiven: 1 vCPU 4GB RAM
URL: api/v1/entities/supportgroup/CE-IDP?relations_depth=1
baseline-depth1-c1)opt--depth1-c1)Load Test Comparison (Concurrency = 50, 10 calls)
baseline-product-depth4-c50)opt-product-depth4-c50)Large graph results
On a single 1 vCPU Cloud Run container, processing, parsing, and mapping 1,589 full entities in memory dropped from ~300–600 ms down to just 35 ms total.
Step-by-Step Breakdown of the 993 ms Server Request
JitProvisioningFilterPostgresEntityAdapterPostgresEntityGraphAdapterPostgresEntityGraphAdapterjsonb_aggquery for 1,589 entitiesPostgresEntityGraphAdapterObjectReaderparses 1,589 entity payloads in JVM RAMEntityDtoOutFromEntityNodeMapperentity_templateEntityDtoOutFromEntityNodeMapperHashMap& imperativeforloop graph assemblyEntityControllerEntityControllerFixes
Review
The reviewer must double-check these points:
!after the type/scope to identify the breakingchange in the release note and ensure we will release a major version.
How to test
Please refer (copy/paste) the test section from the User Story. This should include
Breaking changes (if any)
Context of the Breaking Change
For example: we redefined the component types list in the DPAC referential
Result of the Breaking Change
For example: your component of type xxx will migrate to the type yyy