Skip to content

APP-925: optimize sp_d_labtest_result_postprocessing - #987

Merged
nullflux merged 5 commits into
rel-7.13from
aw/app-925/optimize-labtest-result-sp
Aug 11, 2026
Merged

APP-925: optimize sp_d_labtest_result_postprocessing#987
nullflux merged 5 commits into
rel-7.13from
aw/app-925/optimize-labtest-result-sp

Conversation

@nullflux

Copy link
Copy Markdown
Contributor

Description

Optimizes sp_d_labtest_result_postprocessing's "Update Inactive LAB_TEST_RESULT Records" step
(line ~1785), which scanned LAB_TEST and the LAB_TEST_RESULT heap. Two RDB_MODERN changes:

  1. New covering index IX_LAB_TEST_type_status_root on LAB_TEST(LAB_TEST_TYPE, RECORD_STATUS_CD) INCLUDE(ROOT_ORDERED_TEST_PNTR) — the plan's 77%-impact missing-index hint; turns the
    inactive-Order subquery scan into a seek (changeset tables/264-…).
  2. SP content: #Inactive_Obs is now SELECT DISTINCT + a clustered PK on LAB_TEST_UID, so the
    three downstream status UPDATEs seek the temp instead of scan-joining a heap.

~29% faster under parallelism on a 2M/2M worst-case repro (4.40s → 3.11s); larger in steady state,
where the line-1785 scan dominates. Output byte-identical.

Related Issue

APP-925

Additional Notes

  • This step is write-bound (it flips ~600k rows to INACTIVE across three tables in the worst
    case), so the win is modest vs a scan-bound query — the index helps most in steady state.
  • The plan's second hint (LAB_TEST_RESULT(RECORD_STATUS_CD)) is deliberately not added: it
    is maintained on the very column the UPDATE flips, and measured net-negative (930k vs 256k reads
    on that UPDATE).
  • Equivalence proven as final-state comparison (this SP mutates status): the RECORD_STATUS_CD of
    LAB_TEST_RESULT / LAB_RESULT_VAL / LAB_RESULT_COMMENT is byte-identical original-vs-optimized.
  • SP migration is runOnChange: true. Index changeset is numbered 264 (sits above the 263
    used by the sibling APP-926 PR APP-926: optimize sp_morbidity_report_datamart_postprocessing #980, so the two don't collide).

Checklist

  • Manageable size
  • Reviewed — clear and documented
  • Documentation — n/a
  • Tests added — 3 DataDrivenUnitTests cases (inactive-order flip, active-order stays,
    already-inactive idempotent), passing 3/3, goldens validated against the original SP.

The 'Update Inactive LAB_TEST_RESULT Records' step (line ~1785) scanned LAB_TEST and the
LAB_TEST_RESULT heap. Two changes, RDB_MODERN:

1. New covering index IX_LAB_TEST_type_status_root on LAB_TEST(LAB_TEST_TYPE, RECORD_STATUS_CD)
   INCLUDE(ROOT_ORDERED_TEST_PNTR) - the plan's 77%-impact missing-index hint; turns the
   inactive-Order subquery scan into a seek. New changeset tables/263-... The plan's OTHER hint
   (LAB_TEST_RESULT(RECORD_STATUS_CD)) is deliberately NOT added: it is maintained on the column
   the downstream UPDATE flips, measured net-negative (930k vs 256k reads on that UPDATE).

2. SP content: #Inactive_Obs is now SELECT DISTINCT + a clustered PK on LAB_TEST_UID (with an
   ALTER COLUMN ... NOT NULL first, since SELECT INTO infers it nullable and a bare ADD PRIMARY
   KEY throws Msg 8111). This lets the three downstream status UPDATEs seek the temp instead of
   scan-joining a heap, and DISTINCT avoids write-amplification under LAB_TEST_UID fan-out.

~29% faster under parallelism on a 2M/2M worst-case repro (4.40s -> 3.11s); larger in steady
state where the scan dominates. Output byte-identical (final RECORD_STATUS_CD state of
LAB_TEST_RESULT/LAB_RESULT_VAL/LAB_RESULT_COMMENT, original vs optimized). SP is runOnChange:true.
Three golden-file cases asserting the final RECORD_STATUS_CD state (this SP mutates status):
- app925_labtest_inactive_order: inactive Order -> its active Result + LAB_RESULT_VAL/COMMENT flip to INACTIVE
- app925_labtest_active_order: active Order -> Result stays ACTIVE (no false inactivation)
- app925_labtest_already_inactive: already-inactive -> unchanged (idempotent, guarded)
Goldens validated byte-identical against the original SP; suite passes 3/3. Distinct key bands per
case (SP commits internally), sentinel @pLabResultList so upstream key-gen stays a no-op.
…ze-labtest-result-sp

# Conflicts:
#	reporting-pipeline-service/src/main/resources/db/changelog/migrations/v7.13/rdb/rdb.changelog-7.13.yaml
@nullflux
nullflux requested a review from a team as a code owner August 10, 2026 18:06
nullflux and others added 2 commits August 11, 2026 13:19
…rations/v7.13/rdb/rdb.changelog-7.13.yaml

Co-authored-by: Eric Nagel <eric.nagel@skylight.digital>
Resolve rdb.changelog-7.13.yaml conflict: rel-7.13 added changesets 263,
264-lab100-index, 371-sp_lab100_cleanup and 265 at the same append point.
Keep all of them and renumber the APP-925 index migration 264 -> 266 to
clear the filename collision with 264-lab100-index.sql.
@nullflux
nullflux requested a review from ericnagel August 11, 2026 20:26
@nullflux
nullflux merged commit 3e3362e into rel-7.13 Aug 11, 2026
3 of 5 checks passed
@nullflux
nullflux deleted the aw/app-925/optimize-labtest-result-sp branch August 11, 2026 21: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.

2 participants