Skip to content

perf: migrate WHERE subqueries to unnest - #2023

Merged
jkaczman merged 5 commits into
mainfrom
jk-subqueries-where-unnest
Nov 13, 2026
Merged

jkaczman merged 5 commits into
mainfrom
jk-subqueries-where-unnest

Conversation

@jkaczman

Copy link
Copy Markdown
Contributor

Follow up to #2003 to additionally migrate WHERE subqueries to use unnest instead of inlining the data within the SQL query (e.g., previously, IN ('Data Row 1', 'Data Row 2', 'Data Row 3')). Now, they're specified within a Bind parameter array via unnest (massive speedup).

@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.90164% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pgdog/src/frontend/router/parser/statement.rs 97.22% 5 Missing ⚠️
...end/client/query_engine/multi_step/subquery/mod.rs 81.81% 4 Missing ⚠️
...frontend/router/parser/rewrite/statement/insert.rs 96.42% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (arm64) passed. All 517 measures within bounds.

suite throughput cpu/txn user cycles/txn user instr/txn kernel cycles/txn kernel instr/txn ctx/txn
pooler 18.92 (+0.5% ± 1.0%) 18,182 (+0.1% ± 0.9%) 31,919 (-0.0% ± 0.05%) 30,239 (+0.6% ± 1.5%) 51,130 (-0.3% ± 0.4%)
lb 19.54 (-0.2% ± 0.9%) 18,843 (+0.0% ± 0.4%) 32,823 (+0.0% ± 0.09%) 30,973 (-0.3% ± 1.5%) 52,250 (+0.0% ± 0.3%)
sharding-w2 33.92 (+0.8% ± 1.3%) 46,834 (+0.1% ± 1.1%) 97,345 (+0.0% ± 0.07%) 41,916 (+1.2% ± 1.3%) 53,646 (+0.0% ± 0.1%) 1.537 (+0.1% ± 0.2%)
sharding-w8 238,214 (-0.6% ± 1.9%) 30.3 (+0.7% ± 2.0%) 46,504 (+0.0% ± 2.4%) 52,876 (+0.0% ± 0.1%) 37,276 (+1.5% ± 3.4%) 42,392 (+0.0% ± 0.2%) 0.1601 (-0.5% ± 3.2%)
Counters per txn
suite frontend stall l1i refill backend stall
pooler 7,577 (+0.6% ± 2.9%) 2,618 (+0.5% ± 0.9%)
lb 7,967 (+0.1% ± 1.3%) 2,684 (+0.4% ± 0.6%)
sharding-w2 20,966 (-0.4% ± 2.6%) 4,409 (+0.2% ± 2.2%)
sharding-w8 22,608 (+0.7% ± 5.2%) 4,356 (+0.9% ± 3.8%)

Microbench: all 504 measures within bounds.

Hot code per txn
path base head change
pooler 110.1 KB 110.0 KB -0.1 KB
sharding-w2 165.5 KB 165.9 KB +0.4 KB

pooler:

crate base head change
pgdog::frontend::client::query_engine 19.8 KB 19.6 KB -0.2 KB
tokio 18.2 KB 18.2 KB +0.1 KB
pgdog::backend::pool 17.5 KB 17.6 KB +0.1 KB
aws-lc (TLS crypto) 9.9 KB 10.2 KB +0.3 KB
rustls (TLS) 8.4 KB 8.4 KB -0.1 KB
pgdog::frontend (other) 7.5 KB 7.5 KB +0.0 KB
pgdog::backend::server 7.2 KB 7.1 KB -0.1 KB
other 6.0 KB 6.0 KB +0.0 KB
everything else 15.7 KB 15.4 KB -0.2 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 5.2 KB -0.1 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 5.2 KB -0.2 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.1 KB +0.1 KB
tokio::runtime::task::raw::poll 3.1 KB +0.1 KB
pgdog::backend::server::Server::read::{{closure}} 2.8 KB +0.0 KB

sharding-w2:

crate base head change
pgdog::frontend::router 28.9 KB 28.9 KB +0.0 KB
pgdog::frontend::client::query_engine 20.6 KB 20.9 KB +0.3 KB
tokio 18.6 KB 18.9 KB +0.2 KB
pgdog::backend::pool 18.4 KB 18.3 KB -0.1 KB
aws-lc (TLS crypto) 13.2 KB 13.2 KB -0.1 KB
other 9.6 KB 9.9 KB +0.3 KB
pgdog::frontend (other) 8.6 KB 8.8 KB +0.2 KB
rustls (TLS) 8.3 KB 8.1 KB -0.2 KB
everything else 39.1 KB 38.9 KB -0.2 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 6.2 KB +0.1 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 5.0 KB -0.1 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.1 KB +0.0 KB
pgdog::frontend::router::parser::query::select::<impl pgdog::frontend::router::parser::que 3.4 KB +0.0 KB
tokio::runtime::task::raw::poll 3.2 KB +0.0 KB
lb flamegraph vs 6d7adec

lb

Open interactive for hover, zoom and search.

lb removed

Open interactive.

microbench flamegraph vs 6d7adec

microbench

Open interactive for hover, zoom and search.

microbench removed

Open interactive.

pooler flamegraph vs 6d7adec

pooler

Open interactive for hover, zoom and search.

pooler removed

Open interactive.

sharding-w2 flamegraph vs 6d7adec

sharding-w2

Open interactive for hover, zoom and search.

sharding-w2 removed

Open interactive.

sharding-w8 flamegraph vs 6d7adec

sharding-w8

Open interactive for hover, zoom and search.

sharding-w8 removed

Open interactive.

Logs

lb, microbench, pooler, sharding-w2, sharding-w8, verdict.json

Compared 01843f6 with 6d7adec on m8g.metal-24xl (spot).

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (x86) passed. All 517 measures within bounds.

suite throughput cpu/txn user cycles/txn user instr/txn kernel cycles/txn kernel instr/txn ctx/txn
pooler 25.97 (-0.1% ± 0.4%) 18,915 (-0.1% ± 0.07%) 33,807 (+0.0% ± 0.05%) 33,719 (-0.1% ± 0.9%) 36,523 (-0.0% ± 0.5%)
lb 26.38 (+0.1% ± 0.4%) 19,456 (-0.0% ± 0.2%) 34,793 (+0.0% ± 0.09%) 33,871 (+0.3% ± 1.0%) 37,267 (-0.1% ± 0.3%)
sharding-w2 41.87 (-0.2% ± 1.5%) 47,000 (-0.0% ± 0.9%) 101,242 (-0.0% ± 0.08%) 38,503 (-0.4% ± 3.6%) 40,121 (+0.0% ± 0.08%) 1.529 (+0.0% ± 0.6%)
sharding-w8 209,575 (-0.1% ± 0.4%) 32.54 (+0.0% ± 0.2%) 45,467 (+0.1% ± 0.5%) 55,533 (-0.0% ± 0.2%) 30,932 (-0.1% ± 0.4%) 32,533 (-0.0% ± 0.1%) 0.1709 (+0.1% ± 1.0%)
Counters per txn
suite frontend stall l1i refill backend stall
pooler 3,746 (-0.1% ± 0.6%) 1,217 (+0.2% ± 1.0%) 36,326 (-0.1% ± 0.4%)
lb 3,852 (+0.1% ± 0.2%) 1,248 (+0.4% ± 0.4%) 37,422 (-0.3% ± 0.6%)
sharding-w2 6,501 (+0.6% ± 1.6%) 1,711 (+1.0% ± 1.4%) 110,484 (-0.3% ± 2.7%)
sharding-w8 3,529 (+1.2% ± 1.2%) 1,026 (+0.4% ± 1.7%) 170,670 (+0.1% ± 0.4%)

Microbench: all 504 measures within bounds.

Hot code per txn
path base head change
pooler 110.7 KB 110.9 KB +0.2 KB
sharding-w2 164.3 KB 163.8 KB -0.6 KB

pooler:

crate base head change
pgdog::frontend::client::query_engine 21.3 KB 21.1 KB -0.2 KB
tokio 18.6 KB 18.4 KB -0.2 KB
pgdog::backend::pool 18.2 KB 18.2 KB +0.1 KB
pgdog::frontend (other) 9.4 KB 9.3 KB -0.1 KB
aws-lc (TLS crypto) 8.8 KB 9.0 KB +0.2 KB
rustls (TLS) 7.9 KB 7.8 KB -0.1 KB
pgdog::backend::server 6.9 KB 6.9 KB +0.1 KB
other 5.6 KB 5.8 KB +0.2 KB
everything else 14.1 KB 14.3 KB +0.2 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 7.1 KB -0.1 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 6.4 KB +0.0 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.7 KB -0.1 KB
tokio::runtime::task::raw::poll 3.6 KB -0.1 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 3.2 KB +0.1 KB

sharding-w2:

crate base head change
pgdog::frontend::router 28.8 KB 28.3 KB -0.5 KB
pgdog::frontend::client::query_engine 22.6 KB 22.4 KB -0.2 KB
pgdog::backend::pool 18.9 KB 18.8 KB -0.1 KB
tokio 18.7 KB 18.4 KB -0.3 KB
pgdog::frontend (other) 10.4 KB 10.5 KB +0.1 KB
aws-lc (TLS crypto) 10.3 KB 10.3 KB +0.0 KB
other 9.9 KB 9.8 KB -0.2 KB
pgdog::backend::server 7.9 KB 7.9 KB -0.1 KB
everything else 36.8 KB 37.5 KB +0.8 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 8.1 KB +0.1 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 6.1 KB -0.1 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.6 KB +0.0 KB
pgdog::frontend::router::parser::query::select::<impl pgdog::frontend::router::parser::que 4.2 KB -0.1 KB
tokio::runtime::task::raw::poll 4.0 KB +0.0 KB
lb flamegraph vs 6d7adec

lb

Open interactive for hover, zoom and search.

lb removed

Open interactive.

microbench flamegraph vs 6d7adec

microbench

Open interactive for hover, zoom and search.

microbench removed

Open interactive.

pooler flamegraph vs 6d7adec

pooler

Open interactive for hover, zoom and search.

pooler removed

Open interactive.

sharding-w2 flamegraph vs 6d7adec

sharding-w2

Open interactive for hover, zoom and search.

sharding-w2 removed

Open interactive.

sharding-w8 flamegraph vs 6d7adec

sharding-w8

Open interactive for hover, zoom and search.

sharding-w8 removed

Open interactive.

Logs

lb, microbench, pooler, sharding-w2, sharding-w8, verdict.json

Compared 01843f6 with 6d7adec on c7i.metal-48xl (on-demand).

jkaczman added a commit that referenced this pull request Nov 13, 2026
…2024)

When we send CTE subselects to be evaluated separately from the
top-level query, sometimes the subselects reference earlier executed
CTEs (e.g., CTE b references CTE a). When we send CTE b, we need to
include the values that CTE a previously returned; this is done via
re-writing the CTE b subselect to include a WITH clause with CTE a's
returned values, so that when we execute it separately from the
top-level query, it has everything it needs to return the values it
should. Right now, this is done with a VALUES clause with all the
DataRows inlined as tuples. Example,

> WITH a (id, status) AS (VALUES (1::bigint, 'VIP'::text), (2,
'regular')) SELECT x.id, y.id FROM a x JOIN a y ON x.status = y.status

This migrates those from VALUES to unnest (via Bind param array) for
massive speedup (follow up to #2003, #2023).
@jkaczman
jkaczman merged commit 2131844 into main Nov 13, 2026
47 checks passed
@jkaczman
jkaczman deleted the jk-subqueries-where-unnest branch November 13, 2026 19:56
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.

1 participant