Skip to content

Comments

perf: eliminate program/trackedentitytype joins from enrollment data query DHIS2-20921#22979

Merged
teleivo merged 3 commits intomasterfrom
DHIS2-20921-eliminate-program-join-data
Feb 18, 2026
Merged

perf: eliminate program/trackedentitytype joins from enrollment data query DHIS2-20921#22979
teleivo merged 3 commits intomasterfrom
DHIS2-20921-eliminate-program-join-data

Conversation

@teleivo
Copy link
Contributor

@teleivo teleivo commented Feb 17, 2026

Follow-up to #22972. Eliminates program and trackedentitytype joins from the enrollment data query when a specific program is requested (/enrollments?program=...), which is the standard usage from Capture app, Android SDK, etc. Requests without a program filter are unaffected and keep the original query.

The mapper already loads the full Program entity (including its TrackedEntityType) during validation. This PR reuses that entity in the RowMapper instead of reconstructing it from SQL result columns, removing two joins and ~15 SELECT columns from the data query.

SQL

Data query (when program is specified) -- program and trackedentitytype joins removed:

-- before (#22972)
select e.*, p.*, tet.*, te.uid, en_ou.uid, notes.*, coc.uid
from enrollment e
inner join program p on p.programid = e.programid
inner join trackedentity te on te.trackedentityid = e.trackedentityid
inner join trackedentitytype tet on tet.trackedentitytypeid = p.trackedentitytypeid
inner join trackedentityprogramowner po on ...
inner join organisationunit ou on ...
inner join organisationunit en_ou on ...
inner join (...) as coc on ...
where e.programid = :programId ...

-- after
select e.*, te.uid, en_ou.uid, notes.*, coc.uid
from enrollment e
inner join trackedentity te on te.trackedentityid = e.trackedentityid
inner join trackedentityprogramowner po on ...
inner join organisationunit ou on ...
inner join organisationunit en_ou on ...
inner join (...) as coc on ...
where e.programid = :programId ...

Database Performance

Sierra Leone DB with 10M tracked entities (10.9M enrollments). EXPLAIN ANALYZE on the generated SQL queries, 4 warmup runs.

Planning time halved from ~11ms to ~6ms across all 24 tested data queries. Execution time unchanged. For queries that execute in under 20ms (the majority), the ~5ms planning time saving is 20-35% of total DB time.

Planning time
Before (#22972) 7-12ms
After 5-6ms

The count query is not affected since #22972 already eliminated these joins from it.

When a specific program is provided, resolve its ID in Java and filter
with e.programid = :programId instead of joining the program table and
filtering on p.uid/p.type. The program type check is already validated
by EnrollmentOperationParamsMapper before reaching the store.

This removes one inner join from the count query for the common case
(program specified). The data query still joins program for SELECT
columns.
…20921

When the program is known and its access level is OPEN, AUDITED, or
CLOSED, the trackedentity join is unnecessary in the count query. The
join was only needed for the PROTECTED temp owner check in the
ownership clause, which references te.trackedentityid.

For tracked entity UID filters, uses a subquery instead of a join to
avoid hashing all 10M rows.
…ata query DHIS2-20921

When program is known (which is the common case for all clients), skip
the program and trackedentitytype table joins from the data query.
The Program entity is already loaded by the mapper, so we reuse it in
the RowMapper instead of reconstructing it from the ResultSet.

This halves SQL planning time from ~12ms to ~6ms.
@teleivo teleivo force-pushed the DHIS2-20921-eliminate-program-join-data branch from e6a4dae to 4e828cd Compare February 18, 2026 06:14
@teleivo teleivo marked this pull request as ready for review February 18, 2026 06:15
@sonarqubecloud
Copy link

@teleivo teleivo enabled auto-merge (squash) February 18, 2026 08:41
@teleivo teleivo merged commit 1e153e7 into master Feb 18, 2026
16 checks passed
@teleivo teleivo deleted the DHIS2-20921-eliminate-program-join-data branch February 18, 2026 08:45
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.

3 participants