Profile representative workloads with repeatable evidence

Profile Representative BI/Ad-Hoc/ELT Workloads by Scan, Join, Shuffle, Spill, Queue, and Tail Latency

Build a representative workload profile before changing indexes, SQL, materializations, or concurrency policy.

Intermediate → Advanced150–190 minutesWorkload profiling labp50/p95/p99 + plans + queue evidenceLast reviewed: September 2026

Learning outcomes

01

Define scan, join, shuffle, spill, queue wait, service time, throughput, and p50/p95/p99 tail latency without conflating them.

02

Construct a representative BI/ad-hoc/ELT benchmark corpus and hold semantics, data, cache disclosure, and environment constant across comparisons.

03

Read SQLite EXPLAIN QUERY PLAN evidence while distinguishing what this local engine can and cannot measure.

04

Reject cherry-picked averages and performance claims that silently change metric semantics.

05

Tie every performance signal to a consumer, SLO, resource/cost consequence, and rollback decision.

Continuity: performance engineering must preserve the governed warehouse

Chapter 26 begins from the accepted AtlasMart state established through Chapters 01–25: 10 current paid lines, 8 orders, 12 units, 820 USD gross revenue, 495 USD cost, and 325 USD gross profit. Source progress remains committed through sequence 208; Chapter 20 metric contracts, Chapter 21 certified marts, Chapter 22 security controls, Chapter 23 lineage/ownership, Chapter 24 tests, and Chapter 25 SLO/incident practices remain authoritative. The 360,000-row benchmark below is a clearly labeled scale fixture for performance mechanics only; it never replaces these business control totals.

Executed local benchmark assumptions

Runtime: Python 3.13.5 + SQLite 3.46.1. Benchmark grain: one synthetic paid sales line per row. Scale fixture: 360,000 rows across 180 dates, 100 products, and 5,000 customers; product 1 intentionally receives about 30% of rows and North receives about 50% of customer-linked rows. Storage: a local SQLite database, WAL journal mode, temporary structures configured in memory. Timing: 3 warm-up executions then 17 measured executions; reported cache state is warm. The operating-system cold cache is not forcibly cleared, so no “cold-cache” claim is made. Security: synthetic identifiers only. Distributed limitations: SQLite does not expose distributed shuffle bytes, warehouse queues, or hardware SIMD counters; those mechanisms are explained conceptually and, where useful, modeled explicitly rather than mislabeled as SQLite measurements.

1. Realistic problem: the dashboard is fast alone and slow at 09:00

AtlasMart’s finance dashboard looks healthy in a developer’s single-query test, yet its 09:00 UTC p95 latency rises when an ELT rebuild and exploratory analyst query run concurrently. The business decision is whether certified revenue can be explored within its interactive latency objective without delaying the morning transformation. The data source is the same governed paid-line fact; the grain does not change. What changes is workload mix and resource contention.

Performance engineering is the controlled process of measuring representative work, locating resource-consuming mechanisms, changing one justified mechanism, and proving both correctness and workload-wide consequences. A fast answer with a different population, stale aggregate, hidden filter, or approximate metric is not an optimization of the same query—it is a different contract.

2. Define the signals before collecting them

Signal Exact meaning in this chapter Local evidence / limitation
Scan Rows/pages/bytes a query must inspect before predicates/projection eliminate work. SQLite plan shows SCAN vs SEARCH/index use; exact per-query bytes are not exposed by this harness.
Join Combining rows from two inputs under a relationship. EXPLAIN QUERY PLAN shows nested searches; SQLite does not label broadcast/hash/merge joins.
Shuffle Network redistribution by key in a distributed engine. Not present in single-node SQLite; Chapter 26 models skew consequences instead of inventing shuffle bytes.
Spill Intermediate state exceeds memory budget and is written to temporary storage. Plan may show temporary B-trees; with temp_store=MEMORY, spill bytes are unavailable—not “zero.”
Queue wait Time between admission request and execution start because capacity is occupied. Measured by the explicit two-slot Python scheduler; not an SQLite internal queue metric.
Tail latency Slow end of the distribution, such as p95/p99. 17 measured warm runs after 3 warmups; p50/p95/p99 all reported.

3. Representative query corpus

A representative corpus must include materially different consumers. If you tune only the finance dashboard, you can accidentally regress ELT or ad-hoc exploration.

ID Workload class Question Output grain
BI_7D_CATEGORY BI Seven-day gross revenue by product category one category
ADHOC_30D_SEGMENT_CATEGORY Ad-hoc Thirty-day lines/revenue by customer segment × category one segment-category
POINT_HOT_PRODUCT_7D BI/detail Seven-day lines/revenue for intentionally hot product 1 one product
ELT_DAILY_PRODUCT ELT Rebuild daily-product counts, units, revenue, and cost one date-product
Benchmark timing harness
def bench(sql, runs=17, warmup=3):    for _ in range(warmup):        execute(sql)            # warm-cache disclosure    samples_ms = []    for _ in range(runs):        t0 = perf_counter()        rows = execute(sql)        samples_ms.append((perf_counter() - t0) * 1000)    return p50(samples_ms), p95(samples_ms), p99(samples_ms), checksum(rows)

4. Executed baseline and indexed evidence

Query Base p50 ms Base p95 Base p99 Indexed p50 Indexed p95 Indexed p99 p95 change
BI 7-day category 22.90 24.93 25.34 8.81 10.19 10.93 59.1%
Ad-hoc 30-day 79.13 85.27 85.89 71.58 79.03 84.40 7.3%
Hot product 7-day 17.28 18.58 18.82 3.89 4.14 4.22 77.7%
ELT daily-product 241.92 256.02 264.06 153.39 162.26 165.14 36.6%

The physical change added two date-leading composite indexes. Every before/after query returned the same SHA-256-normalized result checksum. The benchmark therefore demonstrates a performance change without changing output semantics on this fixture. It does not prove the same gain on another engine, data distribution, cache state, or concurrency level.

5. Read plan evidence, not folklore

BI plan before indexes
SCAN fSEARCH p USING INTEGER PRIMARY KEY (rowid=?)USE TEMP B-TREE FOR GROUP BY
BI plan after indexes
SEARCH f USING INDEX ix_fact_sales_date_customer (order_date>? AND order_date<?)SEARCH p USING INTEGER PRIMARY KEY (rowid=?)USE TEMP B-TREE FOR GROUP BY

The baseline performs a full fact scan. After indexing, SQLite reports a date-range index search. Both plans still use a temporary B-tree for grouping; the index does not eliminate every cost. Plan text is useful diagnostic evidence but SQLite explicitly warns that EXPLAIN QUERY PLAN output format can change between releases, so tests should assert query results and measurable behavior rather than parsing plan strings as a permanent API.

6. Controlled failure: optimize the one query that was already on your screen

A practitioner tests only POINT_HOT_PRODUCT_7D, sees a roughly 78% p95 reduction, and declares the warehouse “optimized.” That is incomplete: the protected workload also includes BI aggregates, ad-hoc exploration, and an ELT rebuild. The repair is to benchmark the corpus, preserve checksums, disclose warm/cold state, and inspect p95/p99—not merely one average.

Checkpoint

Why is the mean alone insufficient?

Show answer

A few slow runs can hurt interactive consumers while barely moving the mean. Tail percentiles make slow-end behavior visible; the percentile definition and sample size still need to be disclosed.

7. Concurrency makes queueing visible

Task Observed scheduler queue ms Observed service ms Observed elapsed ms
ADHOC1 54.69 427.35 482.04
BI1 0.00 57.04 57.05
BI2 0.00 54.79 54.80
BI3 482.19 51.05 533.24
ELT1 56.45 1007.88 1064.33
POINT1 535.72 34.95 570.66

This is an explicit two-slot harness around independent SQLite connections. It proves that even unchanged query service time can produce high user-visible elapsed time when work waits for admission. It does not claim SQLite itself implements a two-slot warehouse queue.

8. Production judgment and bridge

Accept a performance change only after result semantics, security policy, freshness/history behavior, retry/replay behavior, and reconciliation still pass. Performance evidence must name the workload, dataset, engine/version, cache state, concurrency, physical layout, and percentile—not just “faster.” Treat any cost or latency number in this chapter as fixture-specific, not a universal target. Keep rollback simple: indexes/materializations can be removed, query rewrites reverted, and workload-pool assignments restored while the logical model and governed metric contracts remain unchanged.

Next: Join Strategies and Dimensional Modeling Benefits: Broadcast/Hash/Merge Concepts, Cardinality, and Skew.

9. Verification checklist

  • Same query text/semantics and dataset are used before/after.
  • Every result checksum matches after the physical change.
  • Cache state is disclosed as warm; cold-cache behavior is not invented.
  • p50, p95, and p99 are reported instead of averages only.
  • Unsupported local metrics—distributed shuffle, internal spill bytes, hardware SIMD—are labeled unavailable.
  • The four workload classes are retained in regression tests.

Knowledge check

Acceptance questions

  1. If a dashboard query drops from 25 ms to 10 ms but revenue changes from 820 USD to 665 USD, is that an optimization?
  2. What additional evidence would you require before claiming a cache-sensitive gain?
  3. Why can queue wait dominate latency even when service time is unchanged?

Authoritative references

  • SQLite — EXPLAIN QUERY PLANOfficial interpretation of scan/search operators, index use, temporary B-trees, and the warning that plan-output format is not a stable application API.
  • SQLite — Query PlanningOfficial background on table scans, multi-column indexes, sorting, and why the planner chooses among semantically equivalent algorithms.
  • SQLite — EXPLAINOfficial semantics and limitations of EXPLAIN/EXPLAIN QUERY PLAN used by the local lab.
  • Python — statisticsUsed for deterministic latency summaries in the local benchmark harness.
  • BigQuery — Understand reservationsNon-prerequisite vendor example showing how a cloud warehouse can isolate workloads with resource pools; the Chapter 26 concepts do not require BigQuery.

10. Lab cleanup/reset

The mandatory lab is local and synthetic. Delete ch26_lab/atlasmart_perf.sqlite and the generated benchmark JSON, then rerun the setup script to restore the deterministic 360,000-row fixture. No cloud resources, accounts, paid services, or production credentials are created.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.