Skip to content

perf: use one null-aware mark join for hashable IN subqueries in projections - #25338

Open
adriangb wants to merge 5 commits into
apache:mainfrom
pydantic:in-exists-subquery-projection
Open

adriangb wants to merge 5 commits into
apache:mainfrom
pydantic:in-exists-subquery-projection

Conversation

@adriangb

@adriangb adriangb commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

This PR supersedes #21363 by @crm26. It reuses the single mark join approach from that PR, and @crm26 is a co-author of the main commit.

It also builds on #24972, which added the decorrelation of IN subqueries in a projection.

Rationale for this change

An IN or NOT IN subquery in a SELECT list gives correct results today, but the plan is quadratic. The optimizer builds three mark joins for each subquery. Two of them have no join predicate, so they run as nested loop joins over all outer rows and all inner rows. COALESCE duplicates the expression, so that shape gets six mark joins.

This PR keeps one hash mark join for each subquery when the join filter is hashable. The three join fallback stays only for a non-equality correlation (Q6 below), which is not changed by this PR and is tracked separately in #25336.

Shape Query main this PR Result rows identical
Q1 Bare IN in the SELECT list 190.730 s 0.034 s yes
Q2 COALESCE((x IN (...))::boolean, false) 351.579 s 0.054 s yes
Q3 Correlated IN with an equality predicate 1.372 s 0.091 s yes
Q4 Two IN subqueries in separate columns 296.676 s 0.063 s yes
Q5 Correlated EXISTS 0.021 s 0.021 s yes
Q6 Correlated IN with a non-equality predicate (fallback path, unchanged) 307.565 s 261.582 s yes

PR to add these as benchmarks: #25346

Reproduction with datafusion-cli: script, plans and timings for each shape

Run the script with datafusion-cli -f mre.sql. It creates two tables with 200000 rows each, then for each shape it prints EXPLAIN and runs the query. datafusion-cli prints the elapsed time after each statement. The numbers above come from one run of this script on an Apple Silicon laptop, main at 22651d2 and this PR built with cargo build -p datafusion-cli --profile ci. The result rows of every query are identical between the two builds.

SET datafusion.execution.target_partitions = 4;
CREATE TABLE outer_t AS SELECT CAST(v AS INT) AS id, CAST(v % 1000 AS INT) AS z FROM (SELECT unnest(generate_series(1, 200000)) AS v);
CREATE TABLE inner_t AS SELECT CASE WHEN v % 97 = 0 THEN NULL ELSE CAST(v * 2 AS INT) END AS id, CAST(v % 1000 AS INT) AS z FROM (SELECT unnest(generate_series(1, 200000)) AS v);
SELECT 'Q1' AS shape;
EXPLAIN SELECT id, id IN (SELECT id FROM inner_t) AS m FROM outer_t;
SELECT count(*) FILTER (WHERE m), count(*) FILTER (WHERE m IS NULL) FROM (SELECT id, id IN (SELECT id FROM inner_t) AS m FROM outer_t);
SELECT 'Q2' AS shape;
EXPLAIN SELECT id, COALESCE((id IN (SELECT id FROM inner_t))::boolean, false) AS m FROM outer_t;
SELECT count(*) FILTER (WHERE m) FROM (SELECT id, COALESCE((id IN (SELECT id FROM inner_t))::boolean, false) AS m FROM outer_t);
SELECT 'Q3' AS shape;
EXPLAIN SELECT id, id IN (SELECT i.id FROM inner_t i WHERE i.z = o.z) AS m FROM outer_t o;
SELECT count(*) FILTER (WHERE m), count(*) FILTER (WHERE m IS NULL) FROM (SELECT id, id IN (SELECT i.id FROM inner_t i WHERE i.z = o.z) AS m FROM outer_t o);
SELECT 'Q4' AS shape;
EXPLAIN SELECT id IN (SELECT id FROM inner_t) AS a, id IN (SELECT id FROM inner_t WHERE z < 500) AS b FROM outer_t;
SELECT count(*) FILTER (WHERE a), count(*) FILTER (WHERE b) FROM (SELECT id IN (SELECT id FROM inner_t) AS a, id IN (SELECT id FROM inner_t WHERE z < 500) AS b FROM outer_t);
SELECT 'Q5' AS shape;
EXPLAIN SELECT id, EXISTS (SELECT 1 FROM inner_t i WHERE i.id = o.id) AS e FROM outer_t o;
SELECT count(*) FILTER (WHERE e) FROM (SELECT id, EXISTS (SELECT 1 FROM inner_t i WHERE i.id = o.id) AS e FROM outer_t o);
SELECT 'Q6' AS shape;
EXPLAIN SELECT id, id IN (SELECT i.id FROM inner_t i WHERE i.z < o.z) AS m FROM outer_t o;
SELECT count(*) FILTER (WHERE m), count(*) FILTER (WHERE m IS NULL) FROM (SELECT id, id IN (SELECT i.id FROM inner_t i WHERE i.z < o.z) AS m FROM outer_t o);
Q1: Bare `IN` in the SELECT list, plans on main and on this PR

main, query time 190.730 s

logical_plan
Projection: outer_t.id, __correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR outer_t.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS m
  LeftMark Join:
    LeftMark Join:
      LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
        TableScan: outer_t projection=[id]
        SubqueryAlias: __correlated_sq_1
          TableScan: inner_t projection=[id]
      SubqueryAlias: __correlated_sq_2
        Filter: inner_t.id IS NULL
          TableScan: inner_t projection=[id]
    SubqueryAlias: __correlated_sq_3
      TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL as m]
  NestedLoopJoinExec: join_type=LeftMark
    CoalescePartitionsExec
      NestedLoopJoinExec: join_type=RightMark
        CoalescePartitionsExec
          FilterExec: id@0 IS NULL
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
          CoalescePartitionsExec
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 0.034 s

logical_plan
Projection: outer_t.id, __correlated_sq_1.mark AS m
  LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
    TableScan: outer_t projection=[id]
    SubqueryAlias: __correlated_sq_1
      TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 as m]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
    CoalescePartitionsExec
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

Q2: `COALESCE((x IN (...))::boolean, false)`, plans on main and on this PR

main, query time 351.579 s

logical_plan
Projection: outer_t.id, CAST(__correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR outer_t.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS Boolean) IS NOT NULL AND CAST(__correlated_sq_4.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_5.mark OR outer_t.id IS NULL AND __correlated_sq_6.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_4.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS Boolean) AS m
  LeftMark Join:
    LeftMark Join:
      LeftMark Join: outer_t.id = __correlated_sq_4.id null_aware
        LeftMark Join:
          LeftMark Join:
            LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
              TableScan: outer_t projection=[id]
              SubqueryAlias: __correlated_sq_1
                TableScan: inner_t projection=[id]
            SubqueryAlias: __correlated_sq_2
              Filter: inner_t.id IS NULL
                TableScan: inner_t projection=[id]
          SubqueryAlias: __correlated_sq_3
            TableScan: inner_t projection=[id]
        SubqueryAlias: __correlated_sq_4
          TableScan: inner_t projection=[id]
      SubqueryAlias: __correlated_sq_5
        Filter: inner_t.id IS NULL
          TableScan: inner_t projection=[id]
    SubqueryAlias: __correlated_sq_6
      TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL IS NOT NULL AND (mark@4 IS NOT DISTINCT FROM true OR (mark@5 OR id@0 IS NULL AND mark@6) IS NOT DISTINCT FROM true AND mark@4 IS DISTINCT FROM true AND NULL) as m]
  NestedLoopJoinExec: join_type=LeftMark
    CoalescePartitionsExec
      NestedLoopJoinExec: join_type=RightMark
        CoalescePartitionsExec
          FilterExec: id@0 IS NULL
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
          CoalescePartitionsExec
            NestedLoopJoinExec: join_type=LeftMark
              CoalescePartitionsExec
                NestedLoopJoinExec: join_type=RightMark
                  CoalescePartitionsExec
                    FilterExec: id@0 IS NULL
                      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
                  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
                    CoalescePartitionsExec
                      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
                    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
              DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 0.054 s

logical_plan
Projection: outer_t.id, CAST(__correlated_sq_1.mark AS Boolean) IS NOT NULL AND CAST(__correlated_sq_2.mark AS Boolean) AS m
  LeftMark Join: outer_t.id = __correlated_sq_2.id null_aware
    LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
      TableScan: outer_t projection=[id]
      SubqueryAlias: __correlated_sq_1
        TableScan: inner_t projection=[id]
    SubqueryAlias: __correlated_sq_2
      TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT NULL AND mark@2 as m]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
    CoalescePartitionsExec
      HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
        CoalescePartitionsExec
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

Q3: Correlated `IN` with an equality predicate, plans on main and on this PR

main, query time 1.372 s

logical_plan
Projection: o.id, __correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR o.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS m
  LeftMark Join: o.z = __correlated_sq_3.z
    LeftMark Join: o.z = __correlated_sq_2.z
      LeftMark Join: o.id = __correlated_sq_1.id, o.z = __correlated_sq_1.z null_aware
        SubqueryAlias: o
          TableScan: outer_t projection=[id, z]
        SubqueryAlias: __correlated_sq_1
          SubqueryAlias: i
            TableScan: inner_t projection=[id, z]
      SubqueryAlias: __correlated_sq_2
        SubqueryAlias: i
          Projection: inner_t.z
            Filter: inner_t.id IS NULL
              TableScan: inner_t projection=[id, z]
    SubqueryAlias: __correlated_sq_3
      SubqueryAlias: i
        TableScan: inner_t projection=[z]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL as m]
  HashJoinExec: mode=CollectLeft, join_type=RightMark, on=[(z@0, z@1)], projection=[id@0, mark@2, mark@3, mark@4]
    CoalescePartitionsExec
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    HashJoinExec: mode=CollectLeft, join_type=RightMark, on=[(z@0, z@1)]
      CoalescePartitionsExec
        FilterExec: id@0 IS NULL, projection=[z@1]
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
      HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0), (z@1, z@1)], null_aware
        CoalescePartitionsExec
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 0.091 s

logical_plan
Projection: o.id, __correlated_sq_1.mark AS m
  LeftMark Join: o.id = __correlated_sq_1.id, o.z = __correlated_sq_1.z null_aware
    SubqueryAlias: o
      TableScan: outer_t projection=[id, z]
    SubqueryAlias: __correlated_sq_1
      SubqueryAlias: i
        TableScan: inner_t projection=[id, z]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 as m]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0), (z@1, z@1)], projection=[id@0, mark@2], null_aware
    CoalescePartitionsExec
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

Q4: Two `IN` subqueries in separate columns, plans on main and on this PR

main, query time 296.676 s

logical_plan
Projection: __correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR outer_t.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS a, __correlated_sq_4.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_5.mark OR outer_t.id IS NULL AND __correlated_sq_6.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_4.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS b
  LeftMark Join:
    LeftMark Join:
      LeftMark Join: outer_t.id = __correlated_sq_4.id null_aware
        LeftMark Join:
          LeftMark Join:
            LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
              TableScan: outer_t projection=[id]
              SubqueryAlias: __correlated_sq_1
                TableScan: inner_t projection=[id]
            SubqueryAlias: __correlated_sq_2
              Filter: inner_t.id IS NULL
                TableScan: inner_t projection=[id]
          SubqueryAlias: __correlated_sq_3
            TableScan: inner_t projection=[id]
        SubqueryAlias: __correlated_sq_4
          Projection: inner_t.id
            Filter: inner_t.z < Int32(500)
              TableScan: inner_t projection=[id, z]
      SubqueryAlias: __correlated_sq_5
        Projection: inner_t.id
          Filter: inner_t.z < Int32(500) AND inner_t.id IS NULL
            TableScan: inner_t projection=[id, z]
    SubqueryAlias: __correlated_sq_6
      Projection: inner_t.id
        Filter: inner_t.z < Int32(500)
          TableScan: inner_t projection=[id, z]
physical_plan
ProjectionExec: expr=[mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL as a, mark@4 IS NOT DISTINCT FROM true OR (mark@5 OR id@0 IS NULL AND mark@6) IS NOT DISTINCT FROM true AND mark@4 IS DISTINCT FROM true AND NULL as b]
  NestedLoopJoinExec: join_type=LeftMark
    CoalescePartitionsExec
      NestedLoopJoinExec: join_type=RightMark
        CoalescePartitionsExec
          FilterExec: z@1 < 500 AND id@0 IS NULL, projection=[id@0]
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
          CoalescePartitionsExec
            NestedLoopJoinExec: join_type=LeftMark
              CoalescePartitionsExec
                NestedLoopJoinExec: join_type=RightMark
                  CoalescePartitionsExec
                    FilterExec: id@0 IS NULL
                      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
                  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
                    CoalescePartitionsExec
                      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
                    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
              DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
          FilterExec: z@1 < 500, projection=[id@0]
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    FilterExec: z@1 < 500, projection=[id@0]
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 0.063 s

logical_plan
Projection: __correlated_sq_1.mark AS a, __correlated_sq_2.mark AS b
  LeftMark Join: outer_t.id = __correlated_sq_2.id null_aware
    LeftMark Join: outer_t.id = __correlated_sq_1.id null_aware
      TableScan: outer_t projection=[id]
      SubqueryAlias: __correlated_sq_1
        TableScan: inner_t projection=[id]
    SubqueryAlias: __correlated_sq_2
      Projection: inner_t.id
        Filter: inner_t.z < Int32(500)
          TableScan: inner_t projection=[id, z]
physical_plan
ProjectionExec: expr=[mark@0 as a, mark@1 as b]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], projection=[mark@1, mark@2], null_aware
    CoalescePartitionsExec
      HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], null_aware
        CoalescePartitionsExec
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    FilterExec: z@1 < 500, projection=[id@0]
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

Q5: Correlated `EXISTS`, plans on main and on this PR

main, query time 0.021 s

logical_plan
Projection: o.id, __correlated_sq_1.mark AS e
  LeftMark Join: o.id = __correlated_sq_1.id
    SubqueryAlias: o
      TableScan: outer_t projection=[id]
    SubqueryAlias: __correlated_sq_1
      SubqueryAlias: i
        TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 as e]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)]
    CoalescePartitionsExec
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 0.021 s

logical_plan
Projection: o.id, __correlated_sq_1.mark AS e
  LeftMark Join: o.id = __correlated_sq_1.id
    SubqueryAlias: o
      TableScan: outer_t projection=[id]
    SubqueryAlias: __correlated_sq_1
      SubqueryAlias: i
        TableScan: inner_t projection=[id]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 as e]
  HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)]
    CoalescePartitionsExec
      DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

Q6: Correlated `IN` with a non-equality predicate (fallback path, unchanged), plans on main and on this PR

main, query time 307.565 s

logical_plan
Projection: o.id, __correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR o.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS m
  LeftMark Join:  Filter: __correlated_sq_3.z < o.z
    LeftMark Join:  Filter: __correlated_sq_2.z < o.z
      LeftMark Join: o.id = __correlated_sq_1.id Filter: __correlated_sq_1.z < o.z
        SubqueryAlias: o
          TableScan: outer_t projection=[id, z]
        SubqueryAlias: __correlated_sq_1
          SubqueryAlias: i
            TableScan: inner_t projection=[id, z]
      SubqueryAlias: __correlated_sq_2
        SubqueryAlias: i
          Projection: inner_t.z
            Filter: inner_t.id IS NULL
              TableScan: inner_t projection=[id, z]
    SubqueryAlias: __correlated_sq_3
      SubqueryAlias: i
        TableScan: inner_t projection=[z]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL as m]
  NestedLoopJoinExec: join_type=LeftMark, filter=z@1 < z@0, projection=[id@0, mark@2, mark@3, mark@4]
    CoalescePartitionsExec
      NestedLoopJoinExec: join_type=RightMark, filter=z@1 < z@0
        CoalescePartitionsExec
          FilterExec: id@0 IS NULL, projection=[z@1]
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], filter=z@1 < z@0
          CoalescePartitionsExec
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

this PR, query time 261.582 s

logical_plan
Projection: o.id, __correlated_sq_1.mark IS NOT DISTINCT FROM Boolean(true) OR (__correlated_sq_2.mark OR o.id IS NULL AND __correlated_sq_3.mark) IS NOT DISTINCT FROM Boolean(true) AND __correlated_sq_1.mark IS DISTINCT FROM Boolean(true) AND Boolean(NULL) AS m
  LeftMark Join:  Filter: __correlated_sq_3.z < o.z
    LeftMark Join:  Filter: __correlated_sq_2.z < o.z
      LeftMark Join: o.id = __correlated_sq_1.id Filter: __correlated_sq_1.z < o.z
        SubqueryAlias: o
          TableScan: outer_t projection=[id, z]
        SubqueryAlias: __correlated_sq_1
          SubqueryAlias: i
            TableScan: inner_t projection=[id, z]
      SubqueryAlias: __correlated_sq_2
        SubqueryAlias: i
          Projection: inner_t.z
            Filter: inner_t.id IS NULL
              TableScan: inner_t projection=[id, z]
    SubqueryAlias: __correlated_sq_3
      SubqueryAlias: i
        TableScan: inner_t projection=[z]
physical_plan
ProjectionExec: expr=[id@0 as id, mark@1 IS NOT DISTINCT FROM true OR (mark@2 OR id@0 IS NULL AND mark@3) IS NOT DISTINCT FROM true AND mark@1 IS DISTINCT FROM true AND NULL as m]
  NestedLoopJoinExec: join_type=LeftMark, filter=z@1 < z@0, projection=[id@0, mark@2, mark@3, mark@4]
    CoalescePartitionsExec
      NestedLoopJoinExec: join_type=RightMark, filter=z@1 < z@0
        CoalescePartitionsExec
          FilterExec: id@0 IS NULL, projection=[z@1]
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
        HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(id@0, id@0)], filter=z@1 < z@0
          CoalescePartitionsExec
            DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
          DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]
    DataSourceExec: partitions=4, partition_sizes=[7, 6, 6, 6]

What changes are included in this PR?

  1. build_join now reports whether the mark column of the LeftMark join is exact under three-valued logic. It is exact when the join filter is hashable only. The join is null aware when the keys can be NULL.

  2. in_subquery_value_mark_join in datafusion/optimizer/src/decorrelate_predicate_subquery.rs now builds the matched join first. If that join is exact, it returns the mark column alone, or NOT mark for NOT IN. The three join materialization is kept only when a residual non-equality filter remains, because the hash join cannot mark UNKNOWN for a residual predicate.

  3. The regression test for fix: scan subqueries when advancing the extracted-alias generator #24574 in projection_pushdown.slt now uses a correlated subquery with LIMIT 1. The subquery then still reaches ExtractLeafExpressions, and the alias generator still starts at 2 inside it. The earlier version of the test let the subquery be flattened, so it no longer exercised the scan inside a subquery path.

  4. New sqllogictest cases in subquery_projection.slt:

    • an EXPLAIN guard that shows one hash mark join for each subquery,
    • an EXPLAIN guard that shows the three join fallback when a residual filter remains,
    • NULL semantics cases: IN and NOT IN with a NULL in the subquery, a NULL outer value, NOT inside CASE, a projection over an aggregate, the COALESCE and cast shape, and results for the residual filter shape.

    All of these were checked against DuckDB and PostgreSQL.

  5. join_keys_may_be_null now decides null-awareness from the equijoin key expressions, not from the columns they reference. A key such as NULLIF(id, 1) or TRY_CAST(s AS INT) can be NULL over a NOT NULL column. Before this change such a key gave a plain mark join, so the projected IN returned false instead of NULL. The same helper feeds the LeftAnti path, so WHERE NULLIF(id, 1) NOT IN (SELECT ...) on main kept a row that it must drop. Both paths now plan a null-aware join for these keys. The residual filter keeps the older column-based check, so no case is less conservative than before.

What is the testing strategy for this PR?

  • Unit tests in datafusion/optimizer/src/decorrelate_predicate_subquery.rs. The updated snapshots now show a single mark join. There are new tests for the residual filter fallback and for NOT IN.
  • The new sqllogictest cases in subquery_projection.slt listed above, checked against DuckDB and PostgreSQL.
  • The existing subquery_projection.slt cases pass without any change.
  • New unit tests and a new subquery_projection.slt section cover nullable key expressions over non-nullable columns: a NULLIF left key, a TRY_CAST left key, a NULLIF right key, NOT IN, and the WHERE form. The expected values agree with DuckDB and PostgreSQL.
  • The full sqllogictest suite and the optimizer crate are green locally.
  • The benchmark numbers above.

Are there any user-facing changes?

There are no changes to query results and no changes to any public API. Plans for projected IN and NOT IN subqueries are much faster. No documentation change is needed.

🤖 Generated with Claude Code

@github-actions github-actions Bot added optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) labels Sep 15, 2026
adriangb and others added 3 commits September 15, 2026 14:03
…ession test

The regression test for the extracted-alias generator relied on an IN subquery
in the SELECT list surviving until ExtractLeafExpressions runs. IN subqueries in
projections are now decorrelated, so make the subquery correlated with a LIMIT,
which DecorrelatePredicateSubquery cannot pull up. The generator still starts at
2 inside the subquery, so the test guards the same behaviour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ections

DecorrelatePredicateSubquery materialized every projected IN and NOT IN
subquery with three mark joins. Two of them have no join predicate for an
uncorrelated subquery and plan as nested-loop mark joins over outer x inner
rows. A single LeftMark join already carries SQL three-valued logic when its
filter is hashable-only: the join is null-aware when the keys may be NULL, and
exact otherwise. Use that join alone in the hashable case and keep the
three-join materialization only when a residual non-equality filter remains.

Co-Authored-By: Christian McArthur <christian@energywell.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… subqueries

Add plan guards for the two paths of a projected IN subquery: one null-aware
LeftMark join per subquery when the join filter is hashable only, and the
three-join materialization when a non-equality correlation stays as a residual
join filter. Add result tests for IN, NOT IN, EXISTS, an aggregate probe, a
CASE wrapper and a COALESCE wrapper over tables that hold NULL keys. The
expected values agree with DuckDB 1.5.2 and PostgreSQL 17.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@adriangb
adriangb force-pushed the in-exists-subquery-projection branch from 9e94b59 to 04f3d7d Compare September 15, 2026 19:17
@adriangb adriangb changed the title feat: support InSubquery and Exists in Projection expressions perf: use one null-aware mark join for hashable IN subqueries in projections Sep 15, 2026
@codecov-commenter

codecov-commenter commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.21547% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.93%. Comparing base (22651d2) to head (fe408e3).
⚠️ Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
...on/optimizer/src/decorrelate_predicate_subquery.rs 81.21% 9 Missing and 25 partials ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             main   #25338     +/-   ##
=========================================
  Coverage   81.92%   81.93%             
=========================================
  Files        1135     1136      +1     
  Lines      427772   428919   +1147     
  Branches   427772   428919   +1147     
=========================================
+ Hits       350456   351420    +964     
- Misses      56373    56463     +90     
- Partials    20943    21036     +93     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@adriangb

Copy link
Copy Markdown
Contributor Author

@kosiew since you reviewed #24972 would you mind taking a look here? cc @neilconway since you were involved in #21363

@adriangb

Copy link
Copy Markdown
Contributor Author

run benchmarks

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5687257997-2377-hfl77 6.12.94+ #1 SMP Tue Aug 4 08:44:15 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5687257997-2378-jf2f2 6.12.94+ #1 SMP Tue Aug 4 08:44:15 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark tpcds

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5687257997-2379-szrcx 6.12.94+ #1 SMP Tue Aug 4 08:44:15 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark tpch

Results will be posted here when complete


File an issue against this benchmark runner

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Expression-level nullability can be missed, causing projected IN to return false instead of UNKNOWN.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Optimizes projected IN/NOT IN subqueries by using a single null-aware mark join when possible.

Changes:

  • Tracks whether mark joins preserve three-valued logic.
  • Retains three-join fallback for residual predicates.
  • Adds plan and NULL-semantics regression tests.
File summaries
File Description
datafusion/optimizer/src/decorrelate_predicate_subquery.rs Implements single-mark-join optimization.
datafusion/sqllogictest/test_files/subquery_projection.slt Tests plans and NULL semantics.
datafusion/sqllogictest/test_files/projection_pushdown.slt Updates alias-collision regression coverage.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

return Ok(Some(new_plan));
return Ok(Some(BuiltJoin {
plan: new_plan,
mark_is_three_valued_exact: mark_filter_is_hashable_only,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, confirmed. With id INT NOT NULL, NULLIF(id, 1) IN (SELECT ...) returned false and NULLIF(id, 1) NOT IN (SELECT ...) returned true where SQL gives NULL. DuckDB and PostgreSQL both give NULL.

Fixed in b44d847. join_keys_may_be_null now takes the equijoin key expressions from split_eq_and_noneq_join_predicate and asks ExprSchemable::nullable for each key against the schema of its own side. That covers NULLIF, TRY_CAST, a CASE with no ELSE, and a key that a cast wraps. The residual filter keeps the older column-based check, so no case is less conservative than before. For these keys the projection path stays one null-aware mark join, so the plan shape and the timings do not change.

The same helper feeds the LeftAnti path. On main, SELECT id FROM nn WHERE NULLIF(id, 1) NOT IN (SELECT id FROM r3) keeps the id = 1 row that it must drop. The same commit fixes that too.

Tests: two unit tests with a nullable key expression over a non-nullable column, one for IN in a projection and one for NOT IN in a filter, both plan null_aware. A new section in subquery_projection.slt runs the NULLIF left key, the TRY_CAST left key, a NULLIF right key, NOT IN, and the WHERE form, and pins the single-join EXPLAIN.

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark tpch
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃     HEAD ┃ in-exists-subquery-projection ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 1  │ 38.63 ms │                      38.67 ms │ no change │
│ QQuery 2  │ 18.88 ms │                      18.89 ms │ no change │
│ QQuery 3  │ 29.09 ms │                      28.70 ms │ no change │
│ QQuery 4  │ 17.61 ms │                      17.66 ms │ no change │
│ QQuery 5  │ 35.97 ms │                      35.89 ms │ no change │
│ QQuery 6  │ 16.11 ms │                      16.08 ms │ no change │
│ QQuery 7  │ 41.79 ms │                      42.43 ms │ no change │
│ QQuery 8  │ 41.38 ms │                      41.02 ms │ no change │
│ QQuery 9  │ 49.43 ms │                      50.09 ms │ no change │
│ QQuery 10 │ 42.28 ms │                      42.51 ms │ no change │
│ QQuery 11 │ 13.59 ms │                      13.64 ms │ no change │
│ QQuery 12 │ 24.12 ms │                      23.91 ms │ no change │
│ QQuery 13 │ 39.91 ms │                      39.40 ms │ no change │
│ QQuery 14 │ 24.47 ms │                      24.49 ms │ no change │
│ QQuery 15 │ 30.82 ms │                      30.91 ms │ no change │
│ QQuery 16 │ 13.81 ms │                      13.74 ms │ no change │
│ QQuery 17 │ 71.46 ms │                      71.66 ms │ no change │
│ QQuery 18 │ 61.89 ms │                      61.37 ms │ no change │
│ QQuery 19 │ 33.16 ms │                      32.94 ms │ no change │
│ QQuery 20 │ 31.88 ms │                      31.82 ms │ no change │
│ QQuery 21 │ 56.05 ms │                      56.27 ms │ no change │
│ QQuery 22 │ 14.02 ms │                      14.35 ms │ no change │
└───────────┴──────────┴───────────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                            ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 746.36ms │
│ Total Time (in-exists-subquery-projection)   │ 746.43ms │
│ Average Time (HEAD)                          │  33.93ms │
│ Average Time (in-exists-subquery-projection) │  33.93ms │
│ Queries Faster                               │        0 │
│ Queries Slower                               │        0 │
│ Queries with No Change                       │       22 │
│ Queries with Failure                         │        0 │
└──────────────────────────────────────────────┴──────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃                           HEAD ┃  in-exists-subquery-projection ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 1  │ 38.63 / 39.52 ±1.16 / 41.67 ms │ 38.67 / 39.77 ±1.30 / 41.53 ms │ no change │
│ QQuery 2  │ 18.88 / 19.34 ±0.37 / 19.82 ms │ 18.89 / 19.20 ±0.25 / 19.54 ms │ no change │
│ QQuery 3  │ 29.09 / 29.24 ±0.15 / 29.53 ms │ 28.70 / 29.08 ±0.39 / 29.83 ms │ no change │
│ QQuery 4  │ 17.61 / 18.03 ±0.53 / 19.08 ms │ 17.66 / 18.11 ±0.50 / 19.05 ms │ no change │
│ QQuery 5  │ 35.97 / 36.48 ±0.37 / 37.10 ms │ 35.89 / 36.88 ±0.89 / 38.48 ms │ no change │
│ QQuery 6  │ 16.11 / 16.79 ±1.02 / 18.81 ms │ 16.08 / 17.25 ±0.85 / 18.41 ms │ no change │
│ QQuery 7  │ 41.79 / 42.52 ±0.42 / 42.99 ms │ 42.43 / 43.26 ±0.90 / 44.86 ms │ no change │
│ QQuery 8  │ 41.38 / 43.00 ±1.54 / 45.66 ms │ 41.02 / 41.31 ±0.24 / 41.66 ms │ no change │
│ QQuery 9  │ 49.43 / 50.56 ±1.33 / 52.85 ms │ 50.09 / 51.17 ±1.05 / 53.08 ms │ no change │
│ QQuery 10 │ 42.28 / 42.49 ±0.17 / 42.68 ms │ 42.51 / 43.24 ±0.57 / 43.98 ms │ no change │
│ QQuery 11 │ 13.59 / 13.81 ±0.16 / 14.02 ms │ 13.64 / 13.85 ±0.14 / 14.03 ms │ no change │
│ QQuery 12 │ 24.12 / 24.37 ±0.13 / 24.50 ms │ 23.91 / 24.41 ±0.37 / 24.93 ms │ no change │
│ QQuery 13 │ 39.91 / 41.31 ±1.53 / 43.35 ms │ 39.40 / 40.70 ±1.00 / 41.86 ms │ no change │
│ QQuery 14 │ 24.47 / 25.13 ±0.96 / 27.01 ms │ 24.49 / 24.67 ±0.15 / 24.93 ms │ no change │
│ QQuery 15 │ 30.82 / 31.39 ±0.59 / 32.26 ms │ 30.91 / 31.13 ±0.27 / 31.62 ms │ no change │
│ QQuery 16 │ 13.81 / 13.95 ±0.13 / 14.14 ms │ 13.74 / 13.97 ±0.12 / 14.06 ms │ no change │
│ QQuery 17 │ 71.46 / 74.32 ±1.63 / 76.08 ms │ 71.66 / 73.25 ±1.21 / 75.02 ms │ no change │
│ QQuery 18 │ 61.89 / 62.58 ±0.41 / 63.17 ms │ 61.37 / 62.17 ±0.73 / 63.50 ms │ no change │
│ QQuery 19 │ 33.16 / 33.49 ±0.22 / 33.81 ms │ 32.94 / 33.69 ±0.74 / 35.10 ms │ no change │
│ QQuery 20 │ 31.88 / 32.55 ±0.64 / 33.64 ms │ 31.82 / 32.57 ±0.59 / 33.33 ms │ no change │
│ QQuery 21 │ 56.05 / 57.28 ±1.38 / 59.30 ms │ 56.27 / 57.90 ±1.34 / 60.13 ms │ no change │
│ QQuery 22 │ 14.02 / 14.14 ±0.12 / 14.36 ms │ 14.35 / 14.60 ±0.21 / 14.98 ms │ no change │
└───────────┴────────────────────────────────┴────────────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                            ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 762.27ms │
│ Total Time (in-exists-subquery-projection)   │ 762.16ms │
│ Average Time (HEAD)                          │  34.65ms │
│ Average Time (in-exists-subquery-projection) │  34.64ms │
│ Queries Faster                               │        0 │
│ Queries Slower                               │        0 │
│ Queries with No Change                       │       22 │
│ Queries with Failure                         │        0 │
└──────────────────────────────────────────────┴──────────┘

Resource Usage

tpch — base (merge-base)

Metric Value
Wall time 5.0s
Peak memory 1.2 GiB
Avg memory 479.8 MiB
CPU user 21.3s
CPU sys 1.8s
Peak spill 0 B

tpch — branch

Metric Value
Wall time 5.0s
Peak memory 1.2 GiB
Avg memory 502.6 MiB
CPU user 21.5s
CPU sys 1.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark tpcds
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │    5.60 ms │                       5.65 ms │     no change │
│ QQuery 2  │   80.59 ms │                      81.35 ms │     no change │
│ QQuery 3  │   28.90 ms │                      29.26 ms │     no change │
│ QQuery 4  │  487.96 ms │                     478.89 ms │     no change │
│ QQuery 5  │   51.85 ms │                      52.23 ms │     no change │
│ QQuery 6  │   35.91 ms │                      36.32 ms │     no change │
│ QQuery 7  │   74.41 ms │                      74.97 ms │     no change │
│ QQuery 8  │   36.57 ms │                      36.57 ms │     no change │
│ QQuery 9  │   52.90 ms │                      50.12 ms │ +1.06x faster │
│ QQuery 10 │   61.39 ms │                      62.18 ms │     no change │
│ QQuery 11 │  294.53 ms │                     294.07 ms │     no change │
│ QQuery 12 │   28.45 ms │                      28.62 ms │     no change │
│ QQuery 13 │  118.07 ms │                     117.72 ms │     no change │
│ QQuery 14 │  417.71 ms │                     419.36 ms │     no change │
│ QQuery 15 │   56.68 ms │                      56.43 ms │     no change │
│ QQuery 16 │    6.49 ms │                       6.75 ms │     no change │
│ QQuery 17 │   80.44 ms │                      80.63 ms │     no change │
│ QQuery 18 │  104.14 ms │                     104.49 ms │     no change │
│ QQuery 19 │   41.05 ms │                      41.38 ms │     no change │
│ QQuery 20 │   35.48 ms │                      35.63 ms │     no change │
│ QQuery 21 │   17.37 ms │                      17.41 ms │     no change │
│ QQuery 22 │   62.65 ms │                      62.65 ms │     no change │
│ QQuery 23 │  311.45 ms │                     313.55 ms │     no change │
│ QQuery 24 │  193.56 ms │                     195.97 ms │     no change │
│ QQuery 25 │  111.06 ms │                     110.98 ms │     no change │
│ QQuery 26 │   47.98 ms │                      48.59 ms │     no change │
│ QQuery 27 │    6.17 ms │                       6.04 ms │     no change │
│ QQuery 28 │   60.84 ms │                      55.74 ms │ +1.09x faster │
│ QQuery 29 │   96.72 ms │                      98.50 ms │     no change │
│ QQuery 30 │   32.34 ms │                      32.48 ms │     no change │
│ QQuery 31 │  109.82 ms │                     110.34 ms │     no change │
│ QQuery 32 │   19.87 ms │                      20.13 ms │     no change │
│ QQuery 33 │   37.80 ms │                      37.68 ms │     no change │
│ QQuery 34 │    9.98 ms │                       9.78 ms │     no change │
│ QQuery 35 │   71.39 ms │                      71.49 ms │     no change │
│ QQuery 36 │    5.76 ms │                       5.79 ms │     no change │
│ QQuery 37 │    6.80 ms │                       6.82 ms │     no change │
│ QQuery 38 │   61.31 ms │                      62.27 ms │     no change │
│ QQuery 39 │   89.18 ms │                      88.89 ms │     no change │
│ QQuery 40 │   23.34 ms │                      23.42 ms │     no change │
│ QQuery 41 │   11.06 ms │                      11.15 ms │     no change │
│ QQuery 42 │   23.47 ms │                      23.93 ms │     no change │
│ QQuery 43 │    5.00 ms │                       5.17 ms │     no change │
│ QQuery 44 │    9.21 ms │                       9.38 ms │     no change │
│ QQuery 45 │   38.37 ms │                      38.71 ms │     no change │
│ QQuery 46 │   11.83 ms │                      12.07 ms │     no change │
│ QQuery 47 │  229.49 ms │                     227.91 ms │     no change │
│ QQuery 48 │   95.49 ms │                      95.66 ms │     no change │
│ QQuery 49 │   71.02 ms │                      70.97 ms │     no change │
│ QQuery 50 │   59.20 ms │                      59.06 ms │     no change │
│ QQuery 51 │   90.14 ms │                      90.72 ms │     no change │
│ QQuery 52 │   24.36 ms │                      23.78 ms │     no change │
│ QQuery 53 │   29.03 ms │                      28.95 ms │     no change │
│ QQuery 54 │   54.51 ms │                      53.91 ms │     no change │
│ QQuery 55 │   23.29 ms │                      23.24 ms │     no change │
│ QQuery 56 │   39.13 ms │                      38.56 ms │     no change │
│ QQuery 57 │  175.70 ms │                     175.83 ms │     no change │
│ QQuery 58 │  112.64 ms │                     112.07 ms │     no change │
│ QQuery 59 │  117.56 ms │                     117.71 ms │     no change │
│ QQuery 60 │   39.96 ms │                      38.77 ms │     no change │
│ QQuery 61 │   12.07 ms │                      12.07 ms │     no change │
│ QQuery 62 │   46.26 ms │                      46.11 ms │     no change │
│ QQuery 63 │   29.16 ms │                      29.36 ms │     no change │
│ QQuery 64 │  367.34 ms │                     369.03 ms │     no change │
│ QQuery 65 │  123.86 ms │                     123.68 ms │     no change │
│ QQuery 66 │   79.04 ms │                      78.56 ms │     no change │
│ QQuery 67 │  243.99 ms │                     238.00 ms │     no change │
│ QQuery 68 │   11.88 ms │                      11.84 ms │     no change │
│ QQuery 69 │   55.58 ms │                      56.02 ms │     no change │
│ QQuery 70 │  104.47 ms │                     104.34 ms │     no change │
│ QQuery 71 │   35.03 ms │                      35.19 ms │     no change │
│ QQuery 72 │ 1822.26 ms │                    1777.64 ms │     no change │
│ QQuery 73 │   10.17 ms │                       9.71 ms │     no change │
│ QQuery 74 │  170.78 ms │                     168.81 ms │     no change │
│ QQuery 75 │  146.05 ms │                     146.55 ms │     no change │
│ QQuery 76 │   34.72 ms │                      35.14 ms │     no change │
│ QQuery 77 │   61.54 ms │                      61.06 ms │     no change │
│ QQuery 78 │  220.73 ms │                     222.09 ms │     no change │
│ QQuery 79 │   66.84 ms │                      66.69 ms │     no change │
│ QQuery 80 │   98.23 ms │                      98.75 ms │     no change │
│ QQuery 81 │   25.74 ms │                      25.78 ms │     no change │
│ QQuery 82 │   16.12 ms │                      16.12 ms │     no change │
│ QQuery 83 │   33.86 ms │                      34.05 ms │     no change │
│ QQuery 84 │   29.25 ms │                      29.34 ms │     no change │
│ QQuery 85 │  103.62 ms │                     102.10 ms │     no change │
│ QQuery 86 │   24.73 ms │                      24.96 ms │     no change │
│ QQuery 87 │   61.25 ms │                      61.30 ms │     no change │
│ QQuery 88 │   63.01 ms │                      63.01 ms │     no change │
│ QQuery 89 │   35.78 ms │                      35.44 ms │     no change │
│ QQuery 90 │   16.72 ms │                      16.78 ms │     no change │
│ QQuery 91 │   44.40 ms │                      45.11 ms │     no change │
│ QQuery 92 │   28.51 ms │                      28.62 ms │     no change │
│ QQuery 93 │   49.61 ms │                      49.59 ms │     no change │
│ QQuery 94 │   37.29 ms │                      37.34 ms │     no change │
│ QQuery 95 │   79.36 ms │                      80.77 ms │     no change │
│ QQuery 96 │   23.56 ms │                      23.77 ms │     no change │
│ QQuery 97 │   50.68 ms │                      51.16 ms │     no change │
│ QQuery 98 │   42.82 ms │                      42.27 ms │     no change │
│ QQuery 99 │   70.10 ms │                      70.21 ms │     no change │
└───────────┴────────────┴───────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 9311.40ms │
│ Total Time (in-exists-subquery-projection)   │ 9257.05ms │
│ Average Time (HEAD)                          │   94.05ms │
│ Average Time (in-exists-subquery-projection) │   93.51ms │
│ Queries Faster                               │         2 │
│ Queries Slower                               │         0 │
│ Queries with No Change                       │        97 │
│ Queries with Failure                         │         0 │
└──────────────────────────────────────────────┴───────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃         in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │           5.60 / 6.16 ±0.94 / 8.03 ms │           5.65 / 6.18 ±0.91 / 7.99 ms │     no change │
│ QQuery 2  │        80.59 / 80.93 ±0.23 / 81.18 ms │        81.35 / 81.73 ±0.25 / 82.02 ms │     no change │
│ QQuery 3  │        28.90 / 29.35 ±0.33 / 29.80 ms │        29.26 / 29.34 ±0.06 / 29.43 ms │     no change │
│ QQuery 4  │     487.96 / 496.44 ±5.70 / 505.73 ms │    478.89 / 502.16 ±29.50 / 560.43 ms │     no change │
│ QQuery 5  │        51.85 / 52.25 ±0.40 / 52.85 ms │        52.23 / 52.50 ±0.40 / 53.30 ms │     no change │
│ QQuery 6  │        35.91 / 36.43 ±0.48 / 37.22 ms │        36.32 / 36.52 ±0.22 / 36.95 ms │     no change │
│ QQuery 7  │        74.41 / 74.75 ±0.27 / 75.06 ms │        74.97 / 75.34 ±0.39 / 75.95 ms │     no change │
│ QQuery 8  │        36.57 / 37.64 ±1.90 / 41.44 ms │        36.57 / 37.00 ±0.42 / 37.76 ms │     no change │
│ QQuery 9  │        52.90 / 54.38 ±1.50 / 56.45 ms │        50.12 / 53.16 ±1.82 / 55.86 ms │     no change │
│ QQuery 10 │        61.39 / 61.75 ±0.23 / 62.04 ms │        62.18 / 62.51 ±0.26 / 62.93 ms │     no change │
│ QQuery 11 │     294.53 / 301.47 ±4.35 / 307.29 ms │     294.07 / 298.31 ±2.82 / 302.62 ms │     no change │
│ QQuery 12 │        28.45 / 28.88 ±0.30 / 29.17 ms │        28.62 / 29.09 ±0.37 / 29.54 ms │     no change │
│ QQuery 13 │     118.07 / 118.83 ±0.43 / 119.26 ms │     117.72 / 118.29 ±0.42 / 118.86 ms │     no change │
│ QQuery 14 │     417.71 / 419.98 ±2.38 / 424.01 ms │     419.36 / 423.04 ±1.92 / 424.71 ms │     no change │
│ QQuery 15 │        56.68 / 57.25 ±0.46 / 58.07 ms │        56.43 / 57.25 ±0.86 / 58.58 ms │     no change │
│ QQuery 16 │           6.49 / 6.69 ±0.25 / 7.18 ms │           6.75 / 6.88 ±0.19 / 7.26 ms │     no change │
│ QQuery 17 │        80.44 / 82.48 ±1.96 / 85.25 ms │        80.63 / 82.40 ±2.19 / 86.71 ms │     no change │
│ QQuery 18 │     104.14 / 105.33 ±0.87 / 106.77 ms │     104.49 / 105.68 ±0.89 / 107.05 ms │     no change │
│ QQuery 19 │        41.05 / 41.44 ±0.31 / 41.85 ms │        41.38 / 41.88 ±0.66 / 43.15 ms │     no change │
│ QQuery 20 │        35.48 / 36.25 ±0.47 / 36.93 ms │        35.63 / 36.12 ±0.27 / 36.41 ms │     no change │
│ QQuery 21 │        17.37 / 17.62 ±0.29 / 18.14 ms │        17.41 / 18.16 ±0.80 / 19.43 ms │     no change │
│ QQuery 22 │        62.65 / 63.70 ±0.61 / 64.49 ms │        62.65 / 64.16 ±1.48 / 66.81 ms │     no change │
│ QQuery 23 │     311.45 / 313.16 ±1.07 / 314.32 ms │     313.55 / 316.48 ±2.56 / 321.14 ms │     no change │
│ QQuery 24 │     193.56 / 197.05 ±3.40 / 203.40 ms │     195.97 / 200.42 ±4.43 / 208.12 ms │     no change │
│ QQuery 25 │     111.06 / 111.40 ±0.31 / 111.83 ms │     110.98 / 114.24 ±2.96 / 118.79 ms │     no change │
│ QQuery 26 │        47.98 / 48.72 ±0.40 / 49.09 ms │        48.59 / 49.01 ±0.22 / 49.22 ms │     no change │
│ QQuery 27 │           6.17 / 6.35 ±0.22 / 6.77 ms │           6.04 / 6.34 ±0.31 / 6.94 ms │     no change │
│ QQuery 28 │        60.84 / 62.11 ±1.90 / 65.87 ms │        55.74 / 61.02 ±4.23 / 68.69 ms │     no change │
│ QQuery 29 │        96.72 / 98.38 ±0.99 / 99.76 ms │      98.50 / 100.69 ±1.48 / 102.68 ms │     no change │
│ QQuery 30 │        32.34 / 32.47 ±0.12 / 32.66 ms │        32.48 / 32.76 ±0.16 / 32.93 ms │     no change │
│ QQuery 31 │     109.82 / 112.21 ±2.49 / 116.93 ms │     110.34 / 112.85 ±2.42 / 117.05 ms │     no change │
│ QQuery 32 │        19.87 / 20.89 ±1.15 / 23.11 ms │        20.13 / 20.37 ±0.25 / 20.81 ms │     no change │
│ QQuery 33 │        37.80 / 38.04 ±0.13 / 38.17 ms │        37.68 / 38.03 ±0.28 / 38.46 ms │     no change │
│ QQuery 34 │         9.98 / 10.16 ±0.17 / 10.39 ms │         9.78 / 10.06 ±0.22 / 10.38 ms │     no change │
│ QQuery 35 │        71.39 / 71.98 ±0.53 / 72.66 ms │        71.49 / 71.97 ±0.34 / 72.53 ms │     no change │
│ QQuery 36 │          5.76 / 6.64 ±1.71 / 10.06 ms │           5.79 / 5.93 ±0.16 / 6.24 ms │ +1.12x faster │
│ QQuery 37 │           6.80 / 6.92 ±0.11 / 7.12 ms │          6.82 / 7.78 ±1.73 / 11.23 ms │  1.12x slower │
│ QQuery 38 │        61.31 / 62.30 ±0.95 / 63.95 ms │        62.27 / 62.71 ±0.26 / 63.01 ms │     no change │
│ QQuery 39 │        89.18 / 89.90 ±0.54 / 90.66 ms │        88.89 / 89.44 ±0.66 / 90.73 ms │     no change │
│ QQuery 40 │        23.34 / 23.77 ±0.31 / 24.18 ms │        23.42 / 23.87 ±0.33 / 24.44 ms │     no change │
│ QQuery 41 │        11.06 / 11.18 ±0.18 / 11.53 ms │        11.15 / 11.33 ±0.13 / 11.49 ms │     no change │
│ QQuery 42 │        23.47 / 24.23 ±0.90 / 25.97 ms │        23.93 / 24.48 ±0.38 / 25.10 ms │     no change │
│ QQuery 43 │           5.00 / 5.14 ±0.18 / 5.51 ms │           5.17 / 5.27 ±0.14 / 5.55 ms │     no change │
│ QQuery 44 │           9.21 / 9.30 ±0.08 / 9.45 ms │           9.38 / 9.51 ±0.09 / 9.64 ms │     no change │
│ QQuery 45 │        38.37 / 39.46 ±1.60 / 42.63 ms │        38.71 / 40.02 ±1.17 / 41.86 ms │     no change │
│ QQuery 46 │        11.83 / 12.09 ±0.22 / 12.40 ms │        12.07 / 12.39 ±0.25 / 12.74 ms │     no change │
│ QQuery 47 │     229.49 / 229.84 ±0.39 / 230.59 ms │     227.91 / 231.32 ±3.68 / 236.85 ms │     no change │
│ QQuery 48 │        95.49 / 96.22 ±1.12 / 98.46 ms │        95.66 / 96.09 ±0.30 / 96.52 ms │     no change │
│ QQuery 49 │        71.02 / 72.42 ±2.22 / 76.83 ms │        70.97 / 71.43 ±0.51 / 72.33 ms │     no change │
│ QQuery 50 │        59.20 / 59.93 ±0.45 / 60.52 ms │        59.06 / 59.43 ±0.44 / 60.28 ms │     no change │
│ QQuery 51 │        90.14 / 93.55 ±2.19 / 96.44 ms │        90.72 / 93.26 ±2.37 / 97.03 ms │     no change │
│ QQuery 52 │        24.36 / 24.51 ±0.13 / 24.74 ms │        23.78 / 24.36 ±0.49 / 25.28 ms │     no change │
│ QQuery 53 │        29.03 / 29.74 ±1.00 / 31.74 ms │        28.95 / 29.19 ±0.19 / 29.54 ms │     no change │
│ QQuery 54 │        54.51 / 54.73 ±0.14 / 54.89 ms │        53.91 / 54.74 ±0.82 / 56.30 ms │     no change │
│ QQuery 55 │        23.29 / 23.84 ±0.44 / 24.47 ms │        23.24 / 23.48 ±0.15 / 23.71 ms │     no change │
│ QQuery 56 │        39.13 / 40.53 ±2.61 / 45.74 ms │        38.56 / 39.15 ±0.37 / 39.64 ms │     no change │
│ QQuery 57 │     175.70 / 176.94 ±0.77 / 177.83 ms │     175.83 / 178.58 ±4.36 / 187.26 ms │     no change │
│ QQuery 58 │     112.64 / 114.34 ±2.16 / 118.54 ms │     112.07 / 114.55 ±2.93 / 120.15 ms │     no change │
│ QQuery 59 │     117.56 / 118.76 ±1.20 / 120.90 ms │     117.71 / 119.23 ±2.49 / 124.19 ms │     no change │
│ QQuery 60 │        39.96 / 40.21 ±0.20 / 40.48 ms │        38.77 / 40.32 ±0.86 / 41.37 ms │     no change │
│ QQuery 61 │        12.07 / 12.24 ±0.22 / 12.68 ms │        12.07 / 12.33 ±0.24 / 12.78 ms │     no change │
│ QQuery 62 │        46.26 / 47.40 ±0.81 / 48.62 ms │        46.11 / 46.46 ±0.30 / 46.86 ms │     no change │
│ QQuery 63 │        29.16 / 29.73 ±0.34 / 30.20 ms │        29.36 / 29.60 ±0.29 / 30.14 ms │     no change │
│ QQuery 64 │     367.34 / 369.85 ±1.93 / 372.82 ms │     369.03 / 372.54 ±3.36 / 378.10 ms │     no change │
│ QQuery 65 │     123.86 / 127.59 ±3.45 / 133.86 ms │     123.68 / 127.02 ±3.06 / 132.52 ms │     no change │
│ QQuery 66 │        79.04 / 80.44 ±0.99 / 81.61 ms │        78.56 / 79.56 ±0.75 / 80.79 ms │     no change │
│ QQuery 67 │     243.99 / 246.65 ±2.21 / 249.38 ms │     238.00 / 244.23 ±3.54 / 248.33 ms │     no change │
│ QQuery 68 │        11.88 / 12.09 ±0.17 / 12.37 ms │        11.84 / 12.01 ±0.21 / 12.43 ms │     no change │
│ QQuery 69 │        55.58 / 57.93 ±3.22 / 64.33 ms │        56.02 / 58.98 ±4.83 / 68.58 ms │     no change │
│ QQuery 70 │     104.47 / 106.04 ±1.75 / 109.44 ms │     104.34 / 105.75 ±1.69 / 108.94 ms │     no change │
│ QQuery 71 │        35.03 / 35.98 ±0.84 / 37.55 ms │        35.19 / 35.49 ±0.29 / 35.97 ms │     no change │
│ QQuery 72 │ 1822.26 / 1889.88 ±46.85 / 1965.09 ms │ 1777.64 / 1857.20 ±66.62 / 1958.83 ms │     no change │
│ QQuery 73 │        10.17 / 11.29 ±1.23 / 13.67 ms │         9.71 / 10.24 ±0.59 / 11.34 ms │ +1.10x faster │
│ QQuery 74 │     170.78 / 173.90 ±1.96 / 176.02 ms │     168.81 / 171.31 ±2.04 / 174.88 ms │     no change │
│ QQuery 75 │     146.05 / 147.30 ±0.79 / 148.33 ms │     146.55 / 147.64 ±1.04 / 148.95 ms │     no change │
│ QQuery 76 │        34.72 / 37.13 ±4.19 / 45.50 ms │        35.14 / 35.49 ±0.24 / 35.83 ms │     no change │
│ QQuery 77 │        61.54 / 62.66 ±1.74 / 66.12 ms │        61.06 / 64.43 ±3.93 / 71.92 ms │     no change │
│ QQuery 78 │     220.73 / 224.58 ±4.49 / 233.34 ms │     222.09 / 226.55 ±4.05 / 232.90 ms │     no change │
│ QQuery 79 │        66.84 / 67.59 ±1.24 / 70.05 ms │        66.69 / 66.93 ±0.26 / 67.43 ms │     no change │
│ QQuery 80 │       98.23 / 99.75 ±0.85 / 100.60 ms │      98.75 / 101.43 ±3.38 / 107.61 ms │     no change │
│ QQuery 81 │        25.74 / 26.01 ±0.15 / 26.19 ms │        25.78 / 26.74 ±1.48 / 29.67 ms │     no change │
│ QQuery 82 │        16.12 / 16.30 ±0.13 / 16.48 ms │        16.12 / 16.66 ±0.62 / 17.79 ms │     no change │
│ QQuery 83 │        33.86 / 34.38 ±0.29 / 34.74 ms │        34.05 / 34.23 ±0.22 / 34.60 ms │     no change │
│ QQuery 84 │        29.25 / 29.51 ±0.18 / 29.68 ms │        29.34 / 29.54 ±0.13 / 29.69 ms │     no change │
│ QQuery 85 │     103.62 / 107.00 ±3.48 / 113.45 ms │     102.10 / 106.56 ±6.19 / 118.60 ms │     no change │
│ QQuery 86 │        24.73 / 25.36 ±0.35 / 25.64 ms │        24.96 / 25.32 ±0.23 / 25.67 ms │     no change │
│ QQuery 87 │        61.25 / 62.04 ±0.42 / 62.48 ms │        61.30 / 62.29 ±0.61 / 63.21 ms │     no change │
│ QQuery 88 │        63.01 / 65.74 ±5.13 / 75.99 ms │        63.01 / 63.47 ±0.35 / 63.80 ms │     no change │
│ QQuery 89 │        35.78 / 36.76 ±1.14 / 38.89 ms │        35.44 / 37.45 ±2.92 / 43.21 ms │     no change │
│ QQuery 90 │        16.72 / 17.01 ±0.17 / 17.23 ms │        16.78 / 17.39 ±0.97 / 19.32 ms │     no change │
│ QQuery 91 │        44.40 / 44.65 ±0.22 / 44.95 ms │        45.11 / 45.49 ±0.38 / 46.22 ms │     no change │
│ QQuery 92 │        28.51 / 29.06 ±0.57 / 29.94 ms │        28.62 / 29.18 ±0.32 / 29.50 ms │     no change │
│ QQuery 93 │        49.61 / 50.91 ±1.13 / 52.59 ms │        49.59 / 50.24 ±0.66 / 51.31 ms │     no change │
│ QQuery 94 │        37.29 / 37.81 ±0.56 / 38.62 ms │        37.34 / 38.63 ±1.88 / 42.35 ms │     no change │
│ QQuery 95 │        79.36 / 81.62 ±2.26 / 85.74 ms │        80.77 / 81.47 ±0.59 / 82.29 ms │     no change │
│ QQuery 96 │        23.56 / 23.89 ±0.25 / 24.32 ms │        23.77 / 24.03 ±0.29 / 24.59 ms │     no change │
│ QQuery 97 │        50.68 / 52.93 ±2.62 / 57.77 ms │        51.16 / 51.52 ±0.53 / 52.57 ms │     no change │
│ QQuery 98 │        42.82 / 43.53 ±0.54 / 44.06 ms │        42.27 / 45.53 ±5.68 / 56.87 ms │     no change │
│ QQuery 99 │        70.10 / 71.05 ±0.64 / 71.87 ms │        70.21 / 71.15 ±0.67 / 72.23 ms │     no change │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 9495.00ms │
│ Total Time (in-exists-subquery-projection)   │ 9481.85ms │
│ Average Time (HEAD)                          │   95.91ms │
│ Average Time (in-exists-subquery-projection) │   95.78ms │
│ Queries Faster                               │         2 │
│ Queries Slower                               │         1 │
│ Queries with No Change                       │        96 │
│ Queries with Failure                         │         0 │
└──────────────────────────────────────────────┴───────────┘

Resource Usage

tpcds — base (merge-base)

Metric Value
Wall time 50.0s
Peak memory 2.1 GiB
Avg memory 1.4 GiB
CPU user 205.7s
CPU sys 5.6s
Peak spill 0 B

tpcds — branch

Metric Value
Wall time 50.0s
Peak memory 1.9 GiB
Avg memory 1.3 GiB
CPU user 204.4s
CPU sys 5.5s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │    1.20 ms │                       1.31 ms │  1.09x slower │
│ QQuery 1  │   11.64 ms │                      11.99 ms │     no change │
│ QQuery 2  │   36.24 ms │                      37.10 ms │     no change │
│ QQuery 3  │   33.09 ms │                      32.32 ms │     no change │
│ QQuery 4  │  235.57 ms │                     223.59 ms │ +1.05x faster │
│ QQuery 5  │  307.17 ms │                     274.83 ms │ +1.12x faster │
│ QQuery 6  │    1.41 ms │                       1.26 ms │ +1.12x faster │
│ QQuery 7  │   14.21 ms │                      13.09 ms │ +1.09x faster │
│ QQuery 8  │  384.07 ms │                     328.91 ms │ +1.17x faster │
│ QQuery 9  │  531.68 ms │                     465.07 ms │ +1.14x faster │
│ QQuery 10 │   74.56 ms │                      70.59 ms │ +1.06x faster │
│ QQuery 11 │   87.69 ms │                      81.76 ms │ +1.07x faster │
│ QQuery 12 │  276.65 ms │                     267.67 ms │     no change │
│ QQuery 13 │  360.99 ms │                     377.83 ms │     no change │
│ QQuery 14 │  282.98 ms │                     284.88 ms │     no change │
│ QQuery 15 │  268.82 ms │                     272.32 ms │     no change │
│ QQuery 16 │  623.33 ms │                     698.89 ms │  1.12x slower │
│ QQuery 17 │  624.35 ms │                     712.99 ms │  1.14x slower │
│ QQuery 18 │ 1260.58 ms │                    1297.29 ms │     no change │
│ QQuery 19 │   27.38 ms │                      27.29 ms │     no change │
│ QQuery 20 │  516.29 ms │                     518.94 ms │     no change │
│ QQuery 21 │  516.38 ms │                     518.17 ms │     no change │
│ QQuery 22 │  980.60 ms │                     992.06 ms │     no change │
│ QQuery 23 │ 3060.41 ms │                    3123.45 ms │     no change │
│ QQuery 24 │   41.52 ms │                      41.76 ms │     no change │
│ QQuery 25 │  110.19 ms │                     110.86 ms │     no change │
│ QQuery 26 │   41.57 ms │                      41.77 ms │     no change │
│ QQuery 27 │  512.95 ms │                     516.16 ms │     no change │
│ QQuery 28 │ 2899.49 ms │                    2927.52 ms │     no change │
│ QQuery 29 │   40.72 ms │                      40.95 ms │     no change │
│ QQuery 30 │  307.03 ms │                     313.55 ms │     no change │
│ QQuery 31 │  286.59 ms │                     289.87 ms │     no change │
│ QQuery 32 │  973.30 ms │                    1099.92 ms │  1.13x slower │
│ QQuery 33 │ 1485.01 ms │                    1492.82 ms │     no change │
│ QQuery 34 │ 1482.14 ms │                    1512.53 ms │     no change │
│ QQuery 35 │  278.49 ms │                     280.70 ms │     no change │
│ QQuery 36 │   67.55 ms │                      72.38 ms │  1.07x slower │
│ QQuery 37 │   35.31 ms │                      37.67 ms │  1.07x slower │
│ QQuery 38 │   40.35 ms │                      41.42 ms │     no change │
│ QQuery 39 │  138.13 ms │                     138.14 ms │     no change │
│ QQuery 40 │   13.81 ms │                      14.30 ms │     no change │
│ QQuery 41 │   13.55 ms │                      13.70 ms │     no change │
│ QQuery 42 │   13.03 ms │                      13.19 ms │     no change │
└───────────┴────────────┴───────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19298.00ms │
│ Total Time (in-exists-subquery-projection)   │ 19632.82ms │
│ Average Time (HEAD)                          │   448.79ms │
│ Average Time (in-exists-subquery-projection) │   456.58ms │
│ Queries Faster                               │          8 │
│ Queries Slower                               │          6 │
│ Queries with No Change                       │         29 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃         in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │          1.20 / 3.99 ±5.47 / 14.92 ms │          1.31 / 4.37 ±5.88 / 16.11 ms │  1.10x slower │
│ QQuery 1  │        11.64 / 11.84 ±0.10 / 11.92 ms │        11.99 / 12.47 ±0.39 / 12.96 ms │  1.05x slower │
│ QQuery 2  │        36.24 / 36.69 ±0.27 / 37.08 ms │        37.10 / 37.36 ±0.35 / 38.05 ms │     no change │
│ QQuery 3  │        33.09 / 34.03 ±0.74 / 35.06 ms │        32.32 / 32.89 ±0.39 / 33.30 ms │     no change │
│ QQuery 4  │    235.57 / 260.85 ±12.68 / 268.45 ms │    223.59 / 242.06 ±14.51 / 259.98 ms │ +1.08x faster │
│ QQuery 5  │     307.17 / 311.87 ±3.56 / 317.60 ms │     274.83 / 282.01 ±6.29 / 293.35 ms │ +1.11x faster │
│ QQuery 6  │           1.41 / 1.59 ±0.21 / 1.99 ms │           1.26 / 1.42 ±0.21 / 1.84 ms │ +1.11x faster │
│ QQuery 7  │        14.21 / 14.34 ±0.12 / 14.53 ms │        13.09 / 13.35 ±0.20 / 13.67 ms │ +1.07x faster │
│ QQuery 8  │     384.07 / 389.42 ±3.79 / 395.56 ms │     328.91 / 332.68 ±3.79 / 339.13 ms │ +1.17x faster │
│ QQuery 9  │    531.68 / 545.39 ±10.55 / 564.30 ms │     465.07 / 476.24 ±8.69 / 487.26 ms │ +1.15x faster │
│ QQuery 10 │        74.56 / 75.68 ±1.11 / 77.78 ms │        70.59 / 72.92 ±2.88 / 78.30 ms │     no change │
│ QQuery 11 │        87.69 / 88.16 ±0.47 / 88.89 ms │        81.76 / 82.95 ±0.88 / 84.23 ms │ +1.06x faster │
│ QQuery 12 │    276.65 / 289.47 ±15.63 / 319.97 ms │     267.67 / 276.85 ±7.80 / 289.63 ms │     no change │
│ QQuery 13 │    360.99 / 374.63 ±10.24 / 385.15 ms │    377.83 / 388.21 ±12.07 / 410.08 ms │     no change │
│ QQuery 14 │     282.98 / 287.98 ±4.44 / 295.34 ms │     284.88 / 289.43 ±3.88 / 295.69 ms │     no change │
│ QQuery 15 │     268.82 / 275.63 ±4.21 / 280.65 ms │    272.32 / 284.96 ±10.60 / 303.59 ms │     no change │
│ QQuery 16 │    623.33 / 672.83 ±31.05 / 715.89 ms │    698.89 / 716.77 ±13.10 / 739.28 ms │  1.07x slower │
│ QQuery 17 │    624.35 / 638.11 ±17.47 / 669.64 ms │     712.99 / 727.49 ±8.53 / 739.22 ms │  1.14x slower │
│ QQuery 18 │ 1260.58 / 1293.90 ±34.40 / 1357.34 ms │ 1297.29 / 1357.92 ±66.03 / 1479.93 ms │     no change │
│ QQuery 19 │        27.38 / 31.10 ±6.13 / 43.31 ms │        27.29 / 29.74 ±3.82 / 37.35 ms │     no change │
│ QQuery 20 │    516.29 / 535.09 ±14.36 / 555.11 ms │    518.94 / 532.31 ±14.30 / 558.85 ms │     no change │
│ QQuery 21 │     516.38 / 525.79 ±6.21 / 533.41 ms │    518.17 / 538.28 ±10.56 / 548.29 ms │     no change │
│ QQuery 22 │  980.60 / 1007.40 ±17.01 / 1024.98 ms │  992.06 / 1003.90 ±12.29 / 1026.88 ms │     no change │
│ QQuery 23 │ 3060.41 / 3110.25 ±54.40 / 3201.96 ms │ 3123.45 / 3148.97 ±15.75 / 3165.81 ms │     no change │
│ QQuery 24 │        41.52 / 42.18 ±0.40 / 42.64 ms │       41.76 / 48.91 ±11.10 / 70.62 ms │  1.16x slower │
│ QQuery 25 │     110.19 / 112.79 ±4.02 / 120.76 ms │     110.86 / 113.56 ±4.05 / 121.59 ms │     no change │
│ QQuery 26 │        41.57 / 42.55 ±0.60 / 43.23 ms │        41.77 / 42.86 ±1.25 / 45.23 ms │     no change │
│ QQuery 27 │     512.95 / 520.09 ±5.10 / 528.45 ms │     516.16 / 524.93 ±7.59 / 536.02 ms │     no change │
│ QQuery 28 │ 2899.49 / 3042.84 ±80.83 / 3116.48 ms │ 2927.52 / 2954.34 ±23.04 / 2996.84 ms │     no change │
│ QQuery 29 │        40.72 / 43.40 ±4.65 / 52.68 ms │        40.95 / 41.61 ±0.89 / 43.28 ms │     no change │
│ QQuery 30 │    307.03 / 324.18 ±13.77 / 343.86 ms │     313.55 / 318.15 ±3.37 / 322.72 ms │     no change │
│ QQuery 31 │    286.59 / 314.60 ±17.59 / 337.62 ms │    289.87 / 318.48 ±21.92 / 352.77 ms │     no change │
│ QQuery 32 │  973.30 / 1000.58 ±29.59 / 1047.55 ms │ 1099.92 / 1137.87 ±26.16 / 1173.81 ms │  1.14x slower │
│ QQuery 33 │ 1485.01 / 1530.88 ±57.27 / 1631.87 ms │ 1492.82 / 1624.01 ±94.04 / 1752.34 ms │  1.06x slower │
│ QQuery 34 │ 1482.14 / 1526.91 ±40.79 / 1603.25 ms │ 1512.53 / 1583.94 ±55.35 / 1675.37 ms │     no change │
│ QQuery 35 │    278.49 / 318.32 ±60.53 / 437.89 ms │    280.70 / 306.97 ±28.11 / 344.62 ms │     no change │
│ QQuery 36 │        67.55 / 76.26 ±6.34 / 84.64 ms │        72.38 / 81.78 ±8.00 / 93.60 ms │  1.07x slower │
│ QQuery 37 │        35.31 / 35.84 ±0.49 / 36.47 ms │        37.67 / 38.99 ±1.65 / 42.20 ms │  1.09x slower │
│ QQuery 38 │        40.35 / 43.80 ±2.29 / 47.11 ms │        41.42 / 45.46 ±3.00 / 50.73 ms │     no change │
│ QQuery 39 │     138.13 / 148.09 ±7.76 / 158.89 ms │     138.14 / 154.05 ±9.14 / 163.14 ms │     no change │
│ QQuery 40 │        13.81 / 14.15 ±0.39 / 14.83 ms │        14.30 / 14.74 ±0.40 / 15.39 ms │     no change │
│ QQuery 41 │        13.55 / 14.38 ±1.32 / 17.00 ms │        13.70 / 14.56 ±1.17 / 16.87 ms │     no change │
│ QQuery 42 │        13.03 / 13.76 ±1.07 / 15.87 ms │        13.19 / 13.82 ±0.85 / 15.50 ms │     no change │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19981.62ms │
│ Total Time (in-exists-subquery-projection)   │ 20264.57ms │
│ Average Time (HEAD)                          │   464.69ms │
│ Average Time (in-exists-subquery-projection) │   471.27ms │
│ Queries Faster                               │          7 │
│ Queries Slower                               │          9 │
│ Queries with No Change                       │         27 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

Metric Value
Wall time 105.0s
Peak memory 12.5 GiB
Avg memory 4.4 GiB
CPU user 1021.7s
CPU sys 71.6s
Peak spill 0 B

clickbench_partitioned — branch

Metric Value
Wall time 105.0s
Peak memory 11.4 GiB
Avg memory 4.4 GiB
CPU user 1033.5s
CPU sys 77.3s
Peak spill 0 B

File an issue against this benchmark runner

@adriangb

Copy link
Copy Markdown
Contributor Author

run benchmark clickbench_partitioned
changed:
ref: 22651d2

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5688276356-2381-j7bvc 6.12.94+ #1 SMP Tue Aug 4 08:44:15 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing 22651d2 (22651d2) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned
changed:
  ref: "22651d24cc8196f3206e09a36a437eda9e766b87"

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing 22651d2 (22651d2) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned
changed:
  ref: "22651d24cc8196f3206e09a36a437eda9e766b87"
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ in-exists-subquery-projection ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 0  │    1.23 ms │                       1.25 ms │ no change │
│ QQuery 1  │   11.80 ms │                      12.12 ms │ no change │
│ QQuery 2  │   36.51 ms │                      36.42 ms │ no change │
│ QQuery 3  │   31.66 ms │                      31.24 ms │ no change │
│ QQuery 4  │  230.28 ms │                     232.46 ms │ no change │
│ QQuery 5  │  281.64 ms │                     283.62 ms │ no change │
│ QQuery 6  │    1.28 ms │                       1.29 ms │ no change │
│ QQuery 7  │   13.58 ms │                      13.50 ms │ no change │
│ QQuery 8  │  344.46 ms │                     337.76 ms │ no change │
│ QQuery 9  │  478.66 ms │                     467.02 ms │ no change │
│ QQuery 10 │   70.88 ms │                      70.85 ms │ no change │
│ QQuery 11 │   82.35 ms │                      81.44 ms │ no change │
│ QQuery 12 │  280.50 ms │                     277.76 ms │ no change │
│ QQuery 13 │  373.65 ms │                     390.72 ms │ no change │
│ QQuery 14 │  293.06 ms │                     292.45 ms │ no change │
│ QQuery 15 │  280.03 ms │                     279.83 ms │ no change │
│ QQuery 16 │  632.03 ms │                     638.69 ms │ no change │
│ QQuery 17 │  642.74 ms │                     640.74 ms │ no change │
│ QQuery 18 │ 1302.01 ms │                    1296.72 ms │ no change │
│ QQuery 19 │   27.73 ms │                      27.74 ms │ no change │
│ QQuery 20 │  521.43 ms │                     520.87 ms │ no change │
│ QQuery 21 │  524.12 ms │                     517.74 ms │ no change │
│ QQuery 22 │  995.97 ms │                     994.55 ms │ no change │
│ QQuery 23 │ 3077.88 ms │                    3092.56 ms │ no change │
│ QQuery 24 │   41.22 ms │                      41.75 ms │ no change │
│ QQuery 25 │  111.05 ms │                     111.86 ms │ no change │
│ QQuery 26 │   41.72 ms │                      41.84 ms │ no change │
│ QQuery 27 │  517.27 ms │                     514.51 ms │ no change │
│ QQuery 28 │ 2935.48 ms │                    2986.02 ms │ no change │
│ QQuery 29 │   41.56 ms │                      41.62 ms │ no change │
│ QQuery 30 │  320.24 ms │                     322.06 ms │ no change │
│ QQuery 31 │  285.33 ms │                     292.75 ms │ no change │
│ QQuery 32 │  980.39 ms │                     977.72 ms │ no change │
│ QQuery 33 │ 1549.25 ms │                    1522.71 ms │ no change │
│ QQuery 34 │ 1518.11 ms │                    1530.72 ms │ no change │
│ QQuery 35 │  298.07 ms │                     295.86 ms │ no change │
│ QQuery 36 │   67.73 ms │                      67.14 ms │ no change │
│ QQuery 37 │   37.42 ms │                      37.35 ms │ no change │
│ QQuery 38 │   42.89 ms │                      42.16 ms │ no change │
│ QQuery 39 │  151.46 ms │                     145.43 ms │ no change │
│ QQuery 40 │   14.82 ms │                      14.92 ms │ no change │
│ QQuery 41 │   14.32 ms │                      14.31 ms │ no change │
│ QQuery 42 │   13.99 ms │                      13.88 ms │ no change │
└───────────┴────────────┴───────────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19517.83ms │
│ Total Time (in-exists-subquery-projection)   │ 19553.94ms │
│ Average Time (HEAD)                          │   453.90ms │
│ Average Time (in-exists-subquery-projection) │   454.74ms │
│ Queries Faster                               │          0 │
│ Queries Slower                               │          0 │
│ Queries with No Change                       │         43 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃         in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │          1.23 / 4.14 ±5.69 / 15.52 ms │          1.25 / 4.11 ±5.60 / 15.30 ms │     no change │
│ QQuery 1  │        11.80 / 12.28 ±0.24 / 12.47 ms │        12.12 / 12.39 ±0.24 / 12.78 ms │     no change │
│ QQuery 2  │        36.51 / 37.00 ±0.37 / 37.63 ms │        36.42 / 36.82 ±0.40 / 37.57 ms │     no change │
│ QQuery 3  │        31.66 / 32.17 ±0.60 / 33.29 ms │        31.24 / 31.73 ±0.43 / 32.32 ms │     no change │
│ QQuery 4  │     230.28 / 236.21 ±3.14 / 238.78 ms │     232.46 / 235.23 ±1.96 / 237.89 ms │     no change │
│ QQuery 5  │     281.64 / 284.45 ±2.94 / 288.70 ms │     283.62 / 285.58 ±3.04 / 291.63 ms │     no change │
│ QQuery 6  │           1.28 / 1.44 ±0.22 / 1.87 ms │           1.29 / 1.44 ±0.22 / 1.86 ms │     no change │
│ QQuery 7  │        13.58 / 13.68 ±0.10 / 13.84 ms │        13.50 / 13.74 ±0.14 / 13.88 ms │     no change │
│ QQuery 8  │     344.46 / 349.07 ±3.26 / 354.56 ms │     337.76 / 342.88 ±2.79 / 345.76 ms │     no change │
│ QQuery 9  │     478.66 / 484.98 ±4.52 / 490.45 ms │    467.02 / 487.49 ±11.49 / 499.46 ms │     no change │
│ QQuery 10 │        70.88 / 72.21 ±1.37 / 73.91 ms │        70.85 / 71.83 ±0.94 / 73.48 ms │     no change │
│ QQuery 11 │        82.35 / 83.14 ±0.67 / 84.20 ms │        81.44 / 81.78 ±0.24 / 82.12 ms │     no change │
│ QQuery 12 │     280.50 / 287.61 ±5.10 / 295.64 ms │     277.76 / 281.25 ±3.21 / 285.28 ms │     no change │
│ QQuery 13 │    373.65 / 390.12 ±13.85 / 411.36 ms │    390.72 / 402.02 ±13.15 / 427.49 ms │     no change │
│ QQuery 14 │     293.06 / 298.84 ±6.45 / 310.29 ms │     292.45 / 298.29 ±3.67 / 303.15 ms │     no change │
│ QQuery 15 │     280.03 / 287.86 ±5.98 / 295.17 ms │    279.83 / 301.78 ±26.76 / 354.12 ms │     no change │
│ QQuery 16 │     632.03 / 638.63 ±5.99 / 649.40 ms │     638.69 / 648.68 ±7.73 / 659.31 ms │     no change │
│ QQuery 17 │     642.74 / 647.91 ±2.97 / 651.19 ms │    640.74 / 654.68 ±11.60 / 673.53 ms │     no change │
│ QQuery 18 │ 1302.01 / 1327.64 ±16.19 / 1344.13 ms │ 1296.72 / 1341.55 ±35.85 / 1405.11 ms │     no change │
│ QQuery 19 │       27.73 / 34.07 ±10.87 / 55.72 ms │        27.74 / 31.57 ±6.75 / 45.04 ms │ +1.08x faster │
│ QQuery 20 │    521.43 / 532.23 ±11.01 / 548.89 ms │     520.87 / 529.17 ±5.58 / 537.94 ms │     no change │
│ QQuery 21 │     524.12 / 527.09 ±3.91 / 534.73 ms │     517.74 / 521.50 ±2.94 / 525.48 ms │     no change │
│ QQuery 22 │  995.97 / 1013.62 ±11.92 / 1032.13 ms │   994.55 / 1006.62 ±8.04 / 1019.90 ms │     no change │
│ QQuery 23 │ 3077.88 / 3134.16 ±45.41 / 3212.40 ms │ 3092.56 / 3136.31 ±41.13 / 3198.64 ms │     no change │
│ QQuery 24 │        41.22 / 45.78 ±3.86 / 50.97 ms │        41.75 / 46.60 ±5.60 / 55.88 ms │     no change │
│ QQuery 25 │     111.05 / 115.05 ±5.04 / 124.83 ms │     111.86 / 120.61 ±6.71 / 129.57 ms │     no change │
│ QQuery 26 │        41.72 / 43.41 ±3.00 / 49.40 ms │        41.84 / 42.89 ±0.83 / 43.89 ms │     no change │
│ QQuery 27 │    517.27 / 528.97 ±11.52 / 550.82 ms │    514.51 / 530.78 ±15.70 / 559.80 ms │     no change │
│ QQuery 28 │ 2935.48 / 2994.83 ±31.60 / 3027.39 ms │ 2986.02 / 3015.90 ±24.81 / 3050.03 ms │     no change │
│ QQuery 29 │        41.56 / 45.52 ±7.33 / 60.17 ms │       41.62 / 52.73 ±14.35 / 77.88 ms │  1.16x slower │
│ QQuery 30 │     320.24 / 325.66 ±5.35 / 333.56 ms │     322.06 / 324.19 ±2.37 / 328.37 ms │     no change │
│ QQuery 31 │    285.33 / 305.41 ±11.08 / 318.18 ms │    292.75 / 307.88 ±12.24 / 323.59 ms │     no change │
│ QQuery 32 │  980.39 / 1000.01 ±13.94 / 1021.61 ms │  977.72 / 1002.94 ±20.72 / 1040.38 ms │     no change │
│ QQuery 33 │  1549.25 / 1563.12 ±9.94 / 1574.46 ms │ 1522.71 / 1574.68 ±78.87 / 1730.83 ms │     no change │
│ QQuery 34 │ 1518.11 / 1553.66 ±25.06 / 1594.87 ms │ 1530.72 / 1581.90 ±44.50 / 1652.42 ms │     no change │
│ QQuery 35 │    298.07 / 329.39 ±51.57 / 432.33 ms │    295.86 / 345.71 ±83.32 / 512.00 ms │     no change │
│ QQuery 36 │        67.73 / 70.94 ±3.15 / 75.73 ms │        67.14 / 73.25 ±4.11 / 79.53 ms │     no change │
│ QQuery 37 │        37.42 / 43.44 ±4.53 / 50.52 ms │        37.35 / 44.63 ±5.37 / 50.99 ms │     no change │
│ QQuery 38 │        42.89 / 45.43 ±2.70 / 50.13 ms │        42.16 / 45.36 ±3.32 / 51.54 ms │     no change │
│ QQuery 39 │     151.46 / 161.45 ±8.09 / 171.66 ms │     145.43 / 155.55 ±5.12 / 158.78 ms │     no change │
│ QQuery 40 │        14.82 / 15.06 ±0.34 / 15.73 ms │        14.92 / 15.37 ±0.30 / 15.77 ms │     no change │
│ QQuery 41 │        14.32 / 14.66 ±0.36 / 15.15 ms │        14.31 / 14.49 ±0.12 / 14.67 ms │     no change │
│ QQuery 42 │        13.99 / 16.79 ±5.28 / 27.35 ms │        13.88 / 14.12 ±0.13 / 14.24 ms │ +1.19x faster │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19949.12ms │
│ Total Time (in-exists-subquery-projection)   │ 20068.00ms │
│ Average Time (HEAD)                          │   463.93ms │
│ Average Time (in-exists-subquery-projection) │   466.70ms │
│ Queries Faster                               │          2 │
│ Queries Slower                               │          1 │
│ Queries with No Change                       │         40 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

Metric Value
Wall time 105.0s
Peak memory 11.8 GiB
Avg memory 4.4 GiB
CPU user 1022.0s
CPU sys 73.1s
Peak spill 0 B

clickbench_partitioned — branch

Metric Value
Wall time 105.0s
Peak memory 11.9 GiB
Avg memory 4.5 GiB
CPU user 1019.1s
CPU sys 74.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangb

Copy link
Copy Markdown
Contributor Author

run benchmark clickbench_partitioned

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5688513263-2382-7p7sn 6.12.94+ #1 SMP Tue Aug 4 08:44:15 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned

Results will be posted here when complete


File an issue against this benchmark runner

@adriangb

Copy link
Copy Markdown
Contributor Author

I opened #25346 to add benchmarks

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing in-exists-subquery-projection (04f3d7d) to 22651d2 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ in-exists-subquery-projection ┃       Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ QQuery 0  │    1.23 ms │                       1.24 ms │    no change │
│ QQuery 1  │   12.21 ms │                      12.01 ms │    no change │
│ QQuery 2  │   36.32 ms │                      36.29 ms │    no change │
│ QQuery 3  │   31.15 ms │                      31.16 ms │    no change │
│ QQuery 4  │  234.75 ms │                     233.62 ms │    no change │
│ QQuery 5  │  278.75 ms │                     280.70 ms │    no change │
│ QQuery 6  │    1.27 ms │                       1.30 ms │    no change │
│ QQuery 7  │   13.59 ms │                      13.55 ms │    no change │
│ QQuery 8  │  341.48 ms │                     341.45 ms │    no change │
│ QQuery 9  │  481.47 ms │                     485.36 ms │    no change │
│ QQuery 10 │   70.57 ms │                      72.18 ms │    no change │
│ QQuery 11 │   82.05 ms │                      82.52 ms │    no change │
│ QQuery 12 │  276.59 ms │                     276.56 ms │    no change │
│ QQuery 13 │  381.07 ms │                     370.06 ms │    no change │
│ QQuery 14 │  297.10 ms │                     292.23 ms │    no change │
│ QQuery 15 │  284.37 ms │                     276.79 ms │    no change │
│ QQuery 16 │  632.54 ms │                     645.58 ms │    no change │
│ QQuery 17 │  637.24 ms │                     641.60 ms │    no change │
│ QQuery 18 │ 1315.39 ms │                    1318.01 ms │    no change │
│ QQuery 19 │   27.91 ms │                      27.82 ms │    no change │
│ QQuery 20 │  527.71 ms │                     518.94 ms │    no change │
│ QQuery 21 │  520.45 ms │                     520.10 ms │    no change │
│ QQuery 22 │ 1003.88 ms │                    1000.16 ms │    no change │
│ QQuery 23 │ 3123.06 ms │                    3147.83 ms │    no change │
│ QQuery 24 │   41.51 ms │                      41.59 ms │    no change │
│ QQuery 25 │  110.71 ms │                     112.05 ms │    no change │
│ QQuery 26 │   41.69 ms │                      41.88 ms │    no change │
│ QQuery 27 │  511.40 ms │                     523.35 ms │    no change │
│ QQuery 28 │ 2967.96 ms │                    2958.13 ms │    no change │
│ QQuery 29 │   41.70 ms │                      41.60 ms │    no change │
│ QQuery 30 │  324.31 ms │                     319.53 ms │    no change │
│ QQuery 31 │  296.24 ms │                     285.84 ms │    no change │
│ QQuery 32 │  965.73 ms │                     959.92 ms │    no change │
│ QQuery 33 │ 1511.77 ms │                    1509.37 ms │    no change │
│ QQuery 34 │ 1547.41 ms │                    1502.82 ms │    no change │
│ QQuery 35 │  298.56 ms │                     297.69 ms │    no change │
│ QQuery 36 │   69.13 ms │                      69.63 ms │    no change │
│ QQuery 37 │   37.05 ms │                      37.76 ms │    no change │
│ QQuery 38 │   41.41 ms │                      44.23 ms │ 1.07x slower │
│ QQuery 39 │  157.55 ms │                     162.07 ms │    no change │
│ QQuery 40 │   14.94 ms │                      15.39 ms │    no change │
│ QQuery 41 │   14.36 ms │                      14.12 ms │    no change │
│ QQuery 42 │   13.86 ms │                      13.77 ms │    no change │
└───────────┴────────────┴───────────────────────────────┴──────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19619.48ms │
│ Total Time (in-exists-subquery-projection)   │ 19577.80ms │
│ Average Time (HEAD)                          │   456.27ms │
│ Average Time (in-exists-subquery-projection) │   455.30ms │
│ Queries Faster                               │          0 │
│ Queries Slower                               │          1 │
│ Queries with No Change                       │         42 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and in-exists-subquery-projection
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃         in-exists-subquery-projection ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │          1.23 / 4.13 ±5.65 / 15.43 ms │          1.24 / 4.08 ±5.55 / 15.18 ms │     no change │
│ QQuery 1  │        12.21 / 12.42 ±0.13 / 12.56 ms │        12.01 / 12.28 ±0.20 / 12.54 ms │     no change │
│ QQuery 2  │        36.32 / 36.94 ±0.44 / 37.34 ms │        36.29 / 36.98 ±0.68 / 37.92 ms │     no change │
│ QQuery 3  │        31.15 / 32.10 ±0.96 / 33.93 ms │        31.16 / 31.52 ±0.31 / 31.86 ms │     no change │
│ QQuery 4  │     234.75 / 236.69 ±1.35 / 238.23 ms │     233.62 / 235.87 ±2.17 / 239.89 ms │     no change │
│ QQuery 5  │     278.75 / 286.39 ±4.20 / 291.21 ms │     280.70 / 283.73 ±2.28 / 286.99 ms │     no change │
│ QQuery 6  │           1.27 / 1.45 ±0.26 / 1.95 ms │           1.30 / 1.44 ±0.21 / 1.85 ms │     no change │
│ QQuery 7  │        13.59 / 13.80 ±0.16 / 13.96 ms │        13.55 / 13.66 ±0.07 / 13.75 ms │     no change │
│ QQuery 8  │     341.48 / 346.06 ±3.50 / 352.02 ms │     341.45 / 344.53 ±2.28 / 347.87 ms │     no change │
│ QQuery 9  │     481.47 / 490.01 ±7.89 / 502.20 ms │    485.36 / 499.58 ±11.62 / 513.15 ms │     no change │
│ QQuery 10 │        70.57 / 73.16 ±3.82 / 80.60 ms │        72.18 / 72.95 ±0.93 / 74.69 ms │     no change │
│ QQuery 11 │        82.05 / 82.64 ±0.75 / 84.07 ms │        82.52 / 83.42 ±0.59 / 83.98 ms │     no change │
│ QQuery 12 │     276.59 / 280.43 ±2.22 / 283.01 ms │     276.56 / 284.75 ±5.68 / 292.93 ms │     no change │
│ QQuery 13 │     381.07 / 388.29 ±5.62 / 394.64 ms │    370.06 / 402.27 ±26.16 / 444.88 ms │     no change │
│ QQuery 14 │     297.10 / 299.48 ±2.07 / 302.97 ms │    292.23 / 301.89 ±10.69 / 322.13 ms │     no change │
│ QQuery 15 │     284.37 / 289.72 ±5.41 / 297.55 ms │    276.79 / 299.44 ±20.23 / 332.03 ms │     no change │
│ QQuery 16 │     632.54 / 642.46 ±5.98 / 649.04 ms │     645.58 / 651.35 ±4.50 / 656.99 ms │     no change │
│ QQuery 17 │     637.24 / 650.23 ±8.66 / 664.53 ms │    641.60 / 659.72 ±14.45 / 681.17 ms │     no change │
│ QQuery 18 │  1315.39 / 1329.18 ±9.86 / 1342.01 ms │ 1318.01 / 1350.02 ±28.61 / 1393.93 ms │     no change │
│ QQuery 19 │        27.91 / 34.87 ±9.03 / 51.08 ms │        27.82 / 36.09 ±8.37 / 46.78 ms │     no change │
│ QQuery 20 │    527.71 / 537.95 ±12.72 / 560.51 ms │     518.94 / 525.46 ±5.01 / 533.81 ms │     no change │
│ QQuery 21 │     520.45 / 524.73 ±3.61 / 529.87 ms │     520.10 / 528.82 ±6.19 / 537.29 ms │     no change │
│ QQuery 22 │  1003.88 / 1015.29 ±9.23 / 1025.34 ms │ 1000.16 / 1016.75 ±11.77 / 1031.32 ms │     no change │
│ QQuery 23 │ 3123.06 / 3141.06 ±11.84 / 3156.16 ms │ 3147.83 / 3180.12 ±27.22 / 3226.68 ms │     no change │
│ QQuery 24 │        41.51 / 44.98 ±5.16 / 55.03 ms │       41.59 / 53.43 ±11.05 / 71.75 ms │  1.19x slower │
│ QQuery 25 │     110.71 / 113.06 ±1.91 / 116.17 ms │     112.05 / 112.98 ±0.85 / 114.19 ms │     no change │
│ QQuery 26 │        41.69 / 42.11 ±0.37 / 42.70 ms │        41.88 / 44.77 ±3.36 / 51.36 ms │  1.06x slower │
│ QQuery 27 │     511.40 / 528.32 ±8.82 / 535.36 ms │     523.35 / 533.02 ±9.66 / 549.69 ms │     no change │
│ QQuery 28 │ 2967.96 / 3002.02 ±24.68 / 3030.66 ms │ 2958.13 / 2971.94 ±19.53 / 3010.44 ms │     no change │
│ QQuery 29 │        41.70 / 43.88 ±3.61 / 51.04 ms │        41.60 / 46.63 ±9.49 / 65.60 ms │  1.06x slower │
│ QQuery 30 │     324.31 / 327.33 ±4.23 / 335.65 ms │     319.53 / 325.09 ±5.20 / 333.62 ms │     no change │
│ QQuery 31 │     296.24 / 300.97 ±4.50 / 308.38 ms │     285.84 / 296.33 ±7.51 / 309.04 ms │     no change │
│ QQuery 32 │   965.73 / 984.01 ±17.14 / 1005.78 ms │    959.92 / 981.30 ±12.20 / 998.02 ms │     no change │
│ QQuery 33 │ 1511.77 / 1538.27 ±21.78 / 1570.34 ms │ 1509.37 / 1541.23 ±24.15 / 1575.11 ms │     no change │
│ QQuery 34 │ 1547.41 / 1562.41 ±12.65 / 1583.33 ms │ 1502.82 / 1550.39 ±31.07 / 1591.96 ms │     no change │
│ QQuery 35 │     298.56 / 307.26 ±7.35 / 316.35 ms │    297.69 / 315.95 ±29.57 / 374.83 ms │     no change │
│ QQuery 36 │        69.13 / 79.22 ±7.37 / 88.32 ms │        69.63 / 75.64 ±4.59 / 82.57 ms │     no change │
│ QQuery 37 │        37.05 / 40.32 ±3.79 / 47.17 ms │        37.76 / 42.78 ±3.00 / 46.02 ms │  1.06x slower │
│ QQuery 38 │        41.41 / 46.22 ±3.94 / 53.03 ms │        44.23 / 47.60 ±5.67 / 58.87 ms │     no change │
│ QQuery 39 │     157.55 / 162.17 ±3.53 / 167.04 ms │     162.07 / 170.57 ±7.07 / 181.04 ms │  1.05x slower │
│ QQuery 40 │        14.94 / 15.28 ±0.34 / 15.89 ms │        15.39 / 15.62 ±0.17 / 15.81 ms │     no change │
│ QQuery 41 │        14.36 / 16.93 ±4.14 / 25.18 ms │        14.12 / 16.40 ±3.70 / 23.77 ms │     no change │
│ QQuery 42 │        13.86 / 18.11 ±4.63 / 24.06 ms │        13.77 / 13.94 ±0.13 / 14.08 ms │ +1.30x faster │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                            ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                            │ 19922.34ms │
│ Total Time (in-exists-subquery-projection)   │ 20012.34ms │
│ Average Time (HEAD)                          │   463.31ms │
│ Average Time (in-exists-subquery-projection) │   465.40ms │
│ Queries Faster                               │          1 │
│ Queries Slower                               │          5 │
│ Queries with No Change                       │         37 │
│ Queries with Failure                         │          0 │
└──────────────────────────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

Metric Value
Wall time 100.0s
Peak memory 12.1 GiB
Avg memory 4.7 GiB
CPU user 1018.3s
CPU sys 73.9s
Peak spill 0 B

clickbench_partitioned — branch

Metric Value
Wall time 105.0s
Peak memory 10.8 GiB
Avg memory 4.1 GiB
CPU user 1021.0s
CPU sys 75.4s
Peak spill 0 B

File an issue against this benchmark runner

`join_keys_may_be_null` decided whether a `LeftMark` or `LeftAnti` join must
be null-aware from the nullability of the columns that the join filter refers
to. A join key is an expression, not only a column, and an expression can be
NULL although all of its columns are not nullable. Examples are
`NULLIF(id, 1)`, `TRY_CAST(s AS INT)` and a `CASE` expression with no `ELSE`
branch.

With such a key the join was not null-aware, so the mark column was `false`
where SQL asks for NULL. Over a table with a column `id INT NOT NULL` that
holds 1, 2 and 4, and a subquery that gives 1 and 2:

- `NULLIF(id, 1) IN (SELECT id FROM r3)` gave `false` for `id = 1`. The
  correct answer is UNKNOWN.
- `TRY_CAST(s AS INT) IN (SELECT id FROM r3)` gave `false` where the text is
  not a number. The correct answer is UNKNOWN.

The `NOT IN` filter path has the same gap, which is older than the projection
path. `SELECT id FROM nn WHERE NULLIF(id, 1) NOT IN (SELECT id FROM r3)`
returned the row for `id = 1`, which UNKNOWN must remove.

The helper now takes the equijoin keys and the residual filter from
`split_eq_and_noneq_join_predicate` and asks each key expression for its
nullability against the schema of its own side. A cast around a key, such as
the `CAST(id AS Int64)` that type coercion adds, keeps the nullability of the
expression in it. For a residual filter there is no key expression, so the
helper keeps the older column test there and is never less conservative than
before.

The `LeftMark` path already split the filter to find out whether it is
hashable only. It now reuses that split instead of splitting twice. The
projection path thus stays one null-aware mark join, and remains as fast as
before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adriangb,

Thanks for working on this. Reusing the exact hashable LeftMark join for projected IN / NOT IN is a nice improvement, and the added NULL-semantics coverage is helpful.

I found one blocking issue in the correlated NOT IN path. The expression-level nullability change can now make a LeftAnti join null-aware when there is more than one hash key, but physical planning only supports a single key for null-aware LeftAnti joins. I left a repro and suggested adding an execution regression test below.

I also left one non-blocking suggestion for the empty-subquery boundary on the new single-mark-join path.

&& join_keys_may_be_null(&join_filter, left.schema(), sub_query_alias.schema())?;
// Additionally, if no join key can be NULL on either side, we don't need
// null-aware semantics because NULLs cannot exist in the keys.
let null_aware = if join_type == JoinType::LeftAnti && in_predicate_opt.is_some() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this introduces a planning failure for correlated NOT IN when the nullable expression key is combined with another correlated equality key.

For example, SELECT id FROM o WHERE NULLIF(id, 1) NOT IN (SELECT id FROM r WHERE r.grp = o.grp) with non-nullable o(id, grp) and r(id, grp) now makes the LeftAnti join null-aware because NULLIF(id, 1) is nullable. The correlation adds grp as a second hash key, so physical planning rejects the resulting join with null_aware LeftAnti joins only support single column join key, got 2 columns.

This looks newly reachable through the expression-level nullability change. Could we preserve the correct correlated NOT IN semantics using a supported fallback or plan shape here? It would also be good to add this query as an execution regression test and assert that only the SQL-true rows are returned.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, confirmed. The query failed with got 2 columns. It plans again in fe408e3: a LeftAnti join with more than one key keeps the column test from main.

This does not give the correct result for your NULLIF example. The join has two keys and is not null-aware, so the k = 1 row stays, the same as on main. The test in subquery_projection.slt records this, with a comment that links apache/datafusion#25347. A correct plan needs a null-aware LeftAnti join with more than one key. apache/datafusion#25339 (approved) adds that. When it merges, I will remove this special case and update the expected output to the correct rows. I did not want to add a second fallback plan here, because apache/datafusion#25339 is the fix for this.

05)----ProjectionExec: expr=[CAST(id@0 AS Int64) as r3.id]
06)------DataSourceExec: partitions=1, partition_sizes=[1]

# `NULLIF(id, 1)` is NULL for `id = 1`, and `r3` has no NULL, so the answer is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also add an empty-subquery case for the new single null-aware mark path using a typed nullable key expression, for example NULLIF(id, 1)?

In particular, it would be useful to assert that the NULL-key row produces false, not NULL, when the subquery is empty, and that the plan still uses a single mark join. The existing top-level NULL IN (empty) test covers the SQL result semantics, but it takes the legacy three-join path, so it does not protect this boundary of the new optimization.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in fe408e3

@jayzhan211

Copy link
Copy Markdown
Contributor

Thanks @adriangb , here is a suggestion:

Correlated NOT IN with a scalar-function key now fails to plan

The LeftAnti branch now reads nullability from the key expressions. Most scalar UDFs use the default return_field_from_args, which always says the result can be NULL (datafusion/expr/src/udf.rs). So a key like upper(s) over a NOT NULL column now turns on null_aware.

For a correlated NOT IN in WHERE, that join has 2+ keys (value + correlation). HashJoinExec rejects null-aware LeftAnti with more than one key, and null-aware joins can't fall back to a sort-merge join:

CREATE TABLE t1(k INT NOT NULL, s VARCHAR NOT NULL) AS VALUES (1, 'a');
CREATE TABLE t2(k INT NOT NULL, s VARCHAR NOT NULL) AS VALUES (1, 'B');
SELECT * FROM t1 WHERE upper(t1.s) NOT IN (SELECT t2.s FROM t2 WHERE t2.k = t1.k);
-- main: plans a plain LeftAnti and returns (1, 'a')
-- this PR: expected "null_aware LeftAnti joins only support single column join key"

Nullable columns already fail like this on main (#25347), but this change extends the failure to common function keys over non-nullable data. It also pins uncorrelated lower(s) NOT IN (...) over NOT NULL columns to a CollectLeft null-aware join for no correctness gain.

Suggest limiting the expression-level check on the LeftAnti path to the single-key case until #25347 is fixed:

     let null_aware = if join_type == JoinType::LeftAnti && in_predicate_opt.is_some() {
         let (equijoin_keys, residual_filter) = split_eq_and_noneq_join_predicate(
             join_filter.clone(),
             left.schema(),
             sub_query_alias.schema(),
         )?;
-        join_keys_may_be_null(
-            &equijoin_keys,
-            residual_filter.as_ref(),
-            left.schema(),
-            sub_query_alias.schema(),
-        )?
+        if equijoin_keys.len() == 1 {
+            join_keys_may_be_null(
+                &equijoin_keys,
+                residual_filter.as_ref(),
+                left.schema(),
+                sub_query_alias.schema(),
+            )?
+        } else {
+            // Null-aware LeftAnti supports a single key only (#25347); keep the
+            // previous column-based test so correlated NOT IN still plans.
+            join_filter_columns_may_be_null(&join_filter, left.schema(), sub_query_alias.schema())?
+        }
     } else {

Please also add an slt case with the correlated query above.

The previous commit made a `LeftAnti` join for `NOT IN` null-aware when a key
expression can be NULL. Most scalar functions report a nullable result, so a
key such as `upper(s)` over a `NOT NULL` column made the join null-aware. A
correlated `NOT IN` has two keys (the value and the correlation), and a
null-aware `LeftAnti` hash join supports one key only. Thus this query failed
to plan:

    SELECT * FROM t1 WHERE upper(t1.s) NOT IN (SELECT t2.s FROM t2 WHERE t2.k = t1.k);
    Error during planning: null_aware LeftAnti joins only support single column join key, got 2 columns

For a `LeftAnti` join with more than one key, use the column test on the whole
join filter again, as on `main`. The expression test stays for one key and for
all mark joins.

Also add tests for an empty subquery with a `NULLIF` key on the single mark
join path, and for the correlated `NOT IN` above.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@adriangb

Copy link
Copy Markdown
Contributor Author

Thanks @jayzhan211, good catch. I applied your suggestion in fe408e3.

@adriangb

Copy link
Copy Markdown
Contributor Author

@jayzhan211 @kosiew could we merge the benchmarks in #25346 before this change so we can look at perf numbers?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Projected IN subqueries plan two extra nested-loop mark joins per subquery and become quadratic

6 participants