Tuning & diagnostics
Performance analysis
How I approach a slow workload: quantify where database time goes, read the plan rather than guess, change one thing, and measure again. The statements below are fabricated case studies written to mirror problems I have actually solved.
Peak window 12:00–15:00 UTC drives the tuning priorities below.
Tuning case studies
Execution plan (before)
SELECT STATEMENT
HASH GROUP BY
HASH JOIN
TABLE ACCESS FULL DIM_CUSTOMER
PARTITION RANGE ALL
TABLE ACCESS FULL FACT_BILLINGFinding
Predicate on BILL_MONTH was wrapped in TRUNC(), disabling partition pruning across 28 partitions.
Remediation
Rewrote the predicate as a half-open range so the optimiser prunes to a single partition; added a local index on CUSTOMER_SK.
Before
18.42s
After
1.24s
Speedup
14.9x
Execution plan (before)
MERGE STATEMENT
MERGE DIM_CUSTOMER
VIEW
NESTED LOOPS OUTER
TABLE ACCESS FULL STG_CUSTOMER
INDEX RANGE SCAN UX_DIM_CUSTOMER_CURRENTFinding
Row-by-row nested loops on a 60k-row staging set; stale statistics on the staging table.
Remediation
Gathered stats after load and hinted a hash outer join, converting the merge to a set-based operation.
Before
9.31s
After
1.87s
Speedup
5x
Execution plan (before)
MERGE STATEMENT
MERGE AGG_DEVICE_HOURLY
HASH JOIN OUTER
TABLE ACCESS FULL STG_TELEMETRY
PARTITION RANGE SINGLE
INDEX UNIQUE SCAN PK_AGG_DEVICE_HOURLYFinding
Acceptable, but commit frequency per micro-batch caused log file sync waits.
Remediation
Single commit per micro-batch and larger array size reduced redo waits.
Before
3.08s
After
1.42s
Speedup
2.2x