Skip to content

perf: batch-fetch ProgramRule.programRuleActions to avoid per-rule N+1 - #24809

Draft
jason-p-pickering wants to merge 3 commits into
2.41from
fix/2.41-programrule-batch-fetch
Draft

perf: batch-fetch ProgramRule.programRuleActions to avoid per-rule N+1#24809
jason-p-pickering wants to merge 3 commits into
2.41from
fix/2.41-programrule-batch-fetch

Conversation

@jason-p-pickering

@jason-p-pickering jason-p-pickering commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Mapping ProgramRules to rule-engine Rules (DefaultProgramRuleEntityMapperService.toMappedProgramRules) lazily initializes the programRuleActions collection once per distinct ProgramRule it maps.
  • Live-traced as ~400 single-row SELECT ... FROM programruleaction WHERE programruleid = ? statements in one request (403 executions, ~1 row each) — each is a different rule, so the existing L2 collection cache (nonstrict-read-write/read-write) can't help: it only serves repeat lookups of the same rule's actions, not 403 distinct first-touches within one request.
  • batch-size="100" on the programRuleActions <set> folds pending collection initializations within one Hibernate session into WHERE programruleid IN (...) batches instead, cutting ~400 round trips down to ~5.
  • Same category as the existing CategoryOption/Option batch-size="100" precedent already in this codebase (ProgramRuleAction inherits BaseIdentifiableObject's UID-based equals/hashCode, no mutable-collection risk factor).
  • Purely additive mapping attribute — no behavior change, no cache-strategy change.

Test plan

  • mvn -pl dhis-services/dhis-service-core -am install -DskipTests — clean build
  • mvn spotless:check — passes
  • Re-run the traced workload and confirm the programruleaction query count drops from ~400 individual SELECTs to ~5 IN (...) batches

🤖 AI Assisted

jason-p-pickering and others added 2 commits August 8, 2026 07:33
Mapping ProgramRules to rule-engine Rules
(DefaultProgramRuleEntityMapperService.toMappedProgramRules) lazily
initializes the programRuleActions collection once per distinct
ProgramRule it maps. Live-traced as ~400 single-row
"WHERE programruleid = ?" SELECTs in one request. The L2 collection
cache doesn't help here since each rule is a first-touch within the
request, not a repeat lookup of the same rule.

batch-size="100" on the collection folds pending collection
initializations within one session into WHERE programruleid IN (...)
batches instead, same category as the existing CategoryOption/Option
batch-size="100" precedent in this codebase.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
XML comments can't contain a literal '--' anywhere in their content
(only as the closing '-->'). This one would have broken Hibernate's
HBM XML parsing on startup exactly like the earlier OptionSet/Option
incident (625b026): "String '--' not allowed in comment (missing
'>'?)", failing entityManagerFactory bean creation and the whole
webapp context startup. Replaced with a comma.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jason-p-pickering
jason-p-pickering requested a review from a team August 9, 2026 13:06
@jason-p-pickering
jason-p-pickering marked this pull request as draft August 10, 2026 19:28
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant