Repeating the PostgreSQL Lab: What Held Up, What Changed

Repeating the PostgreSQL Lab: What Held Up, What Changed

Consider an illustrative open-orders dashboard. It returns a count and a total amount for one account. As more orders accumulate, the page can ask the same question and receive the same shaped response while the database processes more matching rows.

For performance planning, the decision is straightforward: include representative data sizes in the test, and inspect how results vary before using today's latency to support a growth commitment.

A small PostgreSQL lab makes that distinction visible. Its repeat preserved the overall size ordering, but exposed variation that the headline medians concealed.

The same request had more work behind it

The first lab counted open orders and summed their amounts for tenant 42. Three generated tables used the same schema, query template and index definitions. The response was always one aggregate row; the count and sum changed as the data grew.

Both runs took place on October 11, 2026, using PostgreSQL 18.4 on the same shared Apple M4 desktop. Each recorded 540 ordinary queries per size, with zero recorded errors, timeouts or result mismatches.

Total rows
Matching rows
Original median, ms
Fresh median, ms
10,000
20
0.383
0.546
100,000
200
0.634
0.888
1,000,000
2,000
2.464
2.424

Separately captured execution plans showed 20, 200 and 2,000 exact heap blocks visited. These are pages holding table rows. In this fixture, each matching row occupied a distinct page. The broad access path stayed the same while qualifying input and page visitation grew 100-fold.

This explains the growing work behind the query. Because matching input and table footprint increased together, the experiment does not isolate a physical table-size penalty.

The median hid variation within the run

Each run tested all three sizes in 18 comparison blocks. Each point below summarizes 30 queries for one size; the sizes were tested sequentially within a block.

Every whole-cycle median retained 10k < 100k < 1m. But in fresh-run blocks 9 and 16, the 100k median was below the 10k median. Across the fresh blocks, 100k medians ranged from 0.109 to 1.028 ms, and million-row medians from 1.178 to 3.238 ms.

Client-time medians across 18 comparison blocks in the original and fresh PostgreSQL runs. The fresh run varies more, with the 100k median below the 10k median in blocks 9 and 16.

Each point summarizes 30 queries. Shaded blocks reverse the 10k/100k ordering. Lines show recorded order; they are not uncertainty bounds or evidence of a cause. This grouping was examined after the runs, with all observations retained.

The similar overall million-row medians concealed different timing variation. A summary can preserve the expected ordering without showing whether behavior was stable through the measurement window.

Review also found a pacing detail: warmups ran back-to-back, while recorded queries had 10 ms pauses. First-call group medians were lower than subsequent-call group medians in both runs. Variation also appeared among subsequent calls. These observations identify controls to examine; they do not establish a scheduler, power-state or cache cause.

What to ask before using the numbers

Engineering leaders: include data growth alongside request volume in performance planning. Before making a latency or capacity commitment, ask which workflow, data sizes and operating conditions the evidence covers. This lab supports a question to investigate, rather than a production forecast.

Engineering managers: ask the team three concrete questions: what grew inside the request, what did the timer include, and where did the result repeat? Give the next test an owner and a decision to resolve before collecting more samples.

Senior and staff engineers: inspect matching rows, pages visited and actual plans alongside time-ordered observations. Repeat complete runs across separate windows, apply consistent pacing to warmups and measured calls, and record actual gaps. Keep correctness checks and changed plans in the evidence.

Engineers developing this skill: start with one familiar workflow. Identify what a successful response means, then distinguish the response's size from the work required to produce it. A one-row total can depend on thousands of underlying rows.

The boundary and the next test

These were two short, warm, serial runs of approximately 24 seconds on one shared desktop. The client timer included server processing, local communication and scheduling until the complete result arrived. Hundreds of calls inside one window are repeated observations, rather than hundreds of independent experiments. Longer, repeated tests are needed for dependable timing predictions. PostgreSQL benchmarking guidance

The prepared next comparison holds the exact same 20 matching rows fixed while adding nonmatching data. It has not run. That controls logical input, while selectivity, estimates, plans and layout can still change. Its pacing and repetition design should be settled before execution.

For a growing workflow, choose representative data volumes, measure the relevant completion boundary, and inspect variation before turning a lab result into a performance promise.

PostgreSQL Reproduction: Methods and Detailed Results

Read the methods and detailed results · Use the data-growth comparison guide

Download the recorded evidence and recomputation package — raw results, plans, chart data and an offline checker.

postgresql-reproduction-evidence.zip753.6 KiB