Skip to content

feat: Use NDV for equality filter selectivity calculation - #20789

Merged
alamb merged 8 commits into
apache:mainfrom
jonathanc-n:ndv-equality-filter
Apr 3, 2026
Merged

feat: Use NDV for equality filter selectivity calculation#20789
alamb merged 8 commits into
apache:mainfrom
jonathanc-n:ndv-equality-filter

Conversation

@jonathanc-n

@jonathanc-njonathanc-n commented Mar 7, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

Used NDV for equality filter selectivity calculation.

What changes are included in this PR?

Check if it is equality filter, and selectivity will be calculated using (1/NDV)

Are these changes tested?

Are there any user-facing changes?

@github-actionsgithub-actionsBot added the core Core DataFusion crate label Mar 7, 2026

@kosiewkosiew 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.

@jonathanc-n
Thanks for the working on this.

I do think there’s one correctness issue in the new singleton-selectivity branch that should be addressed before merge, and I left one small follow-up suggestion that could make the logic easier to read.

Comment threaddatafusion/physical-expr/src/analysis.rs Outdated
Comment threaddatafusion/physical-expr/src/analysis.rs Outdated
@Dandandan

Copy link
Copy Markdown
Contributor

run benchmarks

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Linux bench-c4116203614-505-rd62t 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing ndv-equality-filter (090f62c) to 92078d9 (merge-base) diff using: tpch
Results will be posted here when complete

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Linux bench-c4116203614-504-4kdqq 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing ndv-equality-filter (090f62c) to 92078d9 (merge-base) diff using: tpcds
Results will be posted here when complete

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Linux bench-c4116203614-503-xrxhm 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing ndv-equality-filter (090f62c) to 92078d9 (merge-base) diff using: clickbench_partitioned
Results will be posted here when complete

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Details

Comparing HEAD and ndv-equality-filter
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Query ┃ HEAD ┃ ndv-equality-filter ┃ Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ QQuery 1 │ 46.08 / 46.71 ±0.73 / 48.11 ms │ 46.05 / 46.77 ±0.80 / 48.28 ms │ no change │
│ QQuery 2 │ 24.12 / 24.38 ±0.26 / 24.79 ms │ 24.37 / 24.93 ±0.65 / 26.09 ms │ no change │
│ QQuery 3 │ 32.85 / 33.16 ±0.20 / 33.46 ms │ 33.06 / 33.30 ±0.14 / 33.45 ms │ no change │
│ QQuery 4 │ 21.63 / 22.09 ±0.28 / 22.40 ms │ 23.19 / 24.63 ±1.19 / 26.36 ms │ 1.11x slower │
│ QQuery 5 │ 49.48 / 52.22 ±1.99 / 54.01 ms │ 51.29 / 52.71 ±1.02 / 54.20 ms │ no change │
│ QQuery 6 │ 17.45 / 17.64 ±0.25 / 18.11 ms │ 17.43 / 17.69 ±0.19 / 17.93 ms │ no change │
│ QQuery 7 │ 56.09 / 58.13 ±1.91 / 61.09 ms │ 56.12 / 59.03 ±2.22 / 62.58 ms │ no change │
│ QQuery 8 │ 51.10 / 52.06 ±1.10 / 54.11 ms │ 50.91 / 51.66 ±0.90 / 53.39 ms │ no change │
│ QQuery 9 │ 55.80 / 57.26 ±0.80 / 57.99 ms │ 56.52 / 57.30 ±0.43 / 57.78 ms │ no change │
│ QQuery 10 │ 72.17 / 73.60 ±0.91 / 74.69 ms │ 73.15 / 74.29 ±0.85 / 75.54 ms │ no change │
│ QQuery 11 │ 15.71 / 16.26 ±0.42 / 16.92 ms │ 16.34 / 16.79 ±0.53 / 17.78 ms │ no change │
│ QQuery 12 │ 28.43 / 28.74 ±0.23 / 29.08 ms │ 28.43 / 28.87 ±0.57 / 29.97 ms │ no change │
│ QQuery 13 │ 39.88 / 40.54 ±0.67 / 41.74 ms │ 39.69 / 40.46 ±0.44 / 40.94 ms │ no change │
│ QQuery 14 │ 28.95 / 29.28 ±0.24 / 29.66 ms │ 29.14 / 29.29 ±0.16 / 29.54 ms │ no change │
│ QQuery 15 │ 35.92 / 36.39 ±0.42 / 36.98 ms │ 35.88 / 36.13 ±0.20 / 36.42 ms │ no change │
│ QQuery 16 │ 17.34 / 17.73 ±0.29 / 18.12 ms │ 17.47 / 17.80 ±0.27 / 18.25 ms │ no change │
│ QQuery 17 │ 73.78 / 74.57 ±0.58 / 75.33 ms │ 73.95 / 75.12 ±1.19 / 77.06 ms │ no change │
│ QQuery 18 │ 79.65 / 80.77 ±0.58 / 81.26 ms │ 79.94 / 80.94 ±0.97 / 82.70 ms │ no change │
│ QQuery 19 │ 38.10 / 38.54 ±0.27 / 38.82 ms │ 38.87 / 39.38 ±0.63 / 40.52 ms │ no change │
│ QQuery 20 │ 42.60 / 43.32 ±0.69 / 44.31 ms │ 42.36 / 43.13 ±0.89 / 44.63 ms │ no change │
│ QQuery 21 │ 68.42 / 70.11 ±1.22 / 72.15 ms │ 68.70 / 70.00 ±0.85 / 70.98 ms │ no change │
│ QQuery 22 │ 19.19 / 19.69 ±0.40 / 20.18 ms │ 19.51 / 19.84 ±0.34 / 20.34 ms │ no change │
└───────────┴────────────────────────────────┴────────────────────────────────┴──────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary ┃ ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD) │ 933.17ms │
│ Total Time (ndv-equality-filter) │ 940.07ms │
│ Average Time (HEAD) │ 42.42ms │
│ Average Time (ndv-equality-filter) │ 42.73ms │
│ Queries Faster │ 0 │
│ Queries Slower │ 1 │
│ Queries with No Change │ 21 │
│ Queries with Failure │ 0 │
└────────────────────────────────────┴──────────┘

Resource Usage

tpch — base (merge-base)

MetricValue
Wall time4.9s
Peak memory4.0 GiB
Avg memory3.5 GiB
CPU user33.8s
CPU sys3.0s
Disk read0 B
Disk write136.0 KiB

tpch — branch

MetricValue
Wall time4.9s
Peak memory4.0 GiB
Avg memory3.5 GiB
CPU user33.6s
CPU sys3.1s
Disk read0 B
Disk write68.0 KiB

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Details

Comparing HEAD and ndv-equality-filter
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Query ┃ HEAD ┃ ndv-equality-filter ┃ Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ QQuery 1 │ 49.69 / 50.77 ±0.85 / 52.18 ms │ 50.12 / 51.04 ±0.80 / 52.04 ms │ no change │
│ QQuery 2 │ 153.48 / 154.49 ±0.75 / 155.61 ms │ 156.73 / 157.40 ±0.47 / 158.11 ms │ no change │
│ QQuery 3 │ 120.09 / 120.60 ±0.46 / 121.32 ms │ 121.37 / 121.92 ±0.55 / 122.90 ms │ no change │
│ QQuery 4 │ 1347.88 / 1373.76 ±14.47 / 1391.74 ms │ 1385.82 / 1443.43 ±38.18 / 1488.34 ms │ 1.05x slower │
│ QQuery 5 │ 185.60 / 187.18 ±1.12 / 188.64 ms │ 186.70 / 189.73 ±2.23 / 192.79 ms │ no change │
│ QQuery 6 │ 990.29 / 1023.01 ±26.05 / 1069.72 ms │ 976.62 / 1010.73 ±29.91 / 1055.61 ms │ no change │
│ QQuery 7 │ 360.31 / 362.77 ±1.66 / 365.23 ms │ 359.10 / 364.78 ±5.08 / 374.02 ms │ no change │
│ QQuery 8 │ 123.95 / 125.08 ±1.16 / 127.11 ms │ 123.22 / 124.53 ±1.00 / 125.81 ms │ no change │
│ QQuery 9 │ 113.11 / 119.40 ±4.21 / 125.78 ms │ 120.25 / 121.85 ±2.78 / 127.40 ms │ no change │
│ QQuery 10 │ 115.59 / 116.62 ±1.08 / 118.56 ms │ 115.46 / 117.10 ±0.98 / 118.37 ms │ no change │
│ QQuery 11 │ 952.00 / 979.03 ±27.73 / 1028.25 ms │ 938.21 / 959.36 ±25.28 / 1007.13 ms │ no change │
│ QQuery 12 │ 48.12 / 49.49 ±1.30 / 51.64 ms │ 47.07 / 48.52 ±0.92 / 49.78 ms │ no change │
│ QQuery 13 │ 412.78 / 415.94 ±2.86 / 420.07 ms │ 410.07 / 413.77 ±2.12 / 416.40 ms │ no change │
│ QQuery 14 │ 1110.36 / 1122.94 ±8.43 / 1135.23 ms │ 1111.24 / 1114.92 ±3.00 / 1118.95 ms │ no change │
│ QQuery 15 │ 18.60 / 19.88 ±1.18 / 21.51 ms │ 18.93 / 20.32 ±0.73 / 20.88 ms │ no change │
│ QQuery 16 │ 47.12 / 47.97 ±0.86 / 49.13 ms │ 46.23 / 47.33 ±1.33 / 49.94 ms │ no change │
│ QQuery 17 │ 250.16 / 254.84 ±2.64 / 258.32 ms │ 253.32 / 254.54 ±1.43 / 257.24 ms │ no change │
│ QQuery 18 │ 133.04 / 135.22 ±1.48 / 137.34 ms │ 135.43 / 136.74 ±0.90 / 137.93 ms │ no change │
│ QQuery 19 │ 163.63 / 165.30 ±1.13 / 166.91 ms │ 162.78 / 165.09 ±1.83 / 168.16 ms │ no change │
│ QQuery 20 │ 16.32 / 17.17 ±0.65 / 18.29 ms │ 16.65 / 17.54 ±0.77 / 18.58 ms │ no change │
│ QQuery 21 │ 24.61 / 24.99 ±0.37 / 25.58 ms │ 24.73 / 25.26 ±0.45 / 25.92 ms │ no change │
│ QQuery 22 │ 517.77 / 521.74 ±3.69 / 528.60 ms │ 518.29 / 523.09 ±3.68 / 529.01 ms │ no change │
│ QQuery 23 │ 945.31 / 955.43 ±12.89 / 980.66 ms │ 950.19 / 966.64 ±9.81 / 979.84 ms │ no change │
│ QQuery 24 │ 437.04 / 440.40 ±3.32 / 446.38 ms │ 438.40 / 440.10 ±1.13 / 441.21 ms │ no change │
│ QQuery 25 │ 366.22 / 366.88 ±0.53 / 367.58 ms │ 368.59 / 369.53 ±0.85 / 370.87 ms │ no change │
│ QQuery 26 │ 84.62 / 87.45 ±1.99 / 90.43 ms │ 86.01 / 88.35 ±1.38 / 89.69 ms │ no change │
│ QQuery 27 │ 354.50 / 356.67 ±1.54 / 359.13 ms │ 353.91 / 359.05 ±3.01 / 362.73 ms │ no change │
│ QQuery 28 │ 153.57 / 156.45 ±1.81 / 158.53 ms │ 154.93 / 156.34 ±1.20 / 158.06 ms │ no change │
│ QQuery 29 │ 307.39 / 311.39 ±2.66 / 315.17 ms │ 310.20 / 314.34 ±2.54 / 317.67 ms │ no change │
│ QQuery 30 │ 49.40 / 51.41 ±1.59 / 53.52 ms │ 49.22 / 50.77 ±1.36 / 52.77 ms │ no change │
│ QQuery 31 │ 185.21 / 187.05 ±0.99 / 188.00 ms │ 186.46 / 188.88 ±1.51 / 190.54 ms │ no change │
│ QQuery 32 │ 62.83 / 63.87 ±1.46 / 66.69 ms │ 63.07 / 64.18 ±0.90 / 65.77 ms │ no change │
│ QQuery 33 │ 151.80 / 154.35 ±1.68 / 156.51 ms │ 155.65 / 156.80 ±1.00 / 158.21 ms │ no change │
│ QQuery 34 │ 111.48 / 113.56 ±1.28 / 114.68 ms │ 115.32 / 115.93 ±0.85 / 117.56 ms │ no change │
│ QQuery 35 │ 119.30 / 121.93 ±2.43 / 126.36 ms │ 119.02 / 121.28 ±1.38 / 122.78 ms │ no change │
│ QQuery 36 │ 223.27 / 231.22 ±4.13 / 234.52 ms │ 224.30 / 228.92 ±2.97 / 232.36 ms │ no change │
│ QQuery 37 │ 191.91 / 194.85 ±3.67 / 200.67 ms │ 196.51 / 197.71 ±1.31 / 200.16 ms │ no change │
│ QQuery 38 │ 92.85 / 96.18 ±2.17 / 99.72 ms │ 95.75 / 98.16 ±1.82 / 101.02 ms │ no change │
│ QQuery 39 │ 139.03 / 140.07 ±0.83 / 141.47 ms │ 142.60 / 144.69 ±1.39 / 146.52 ms │ no change │
│ QQuery 40 │ 119.44 / 124.51 ±4.80 / 131.98 ms │ 120.97 / 126.04 ±6.08 / 137.52 ms │ no change │
│ QQuery 41 │ 18.27 / 19.31 ±0.61 / 19.82 ms │ 18.37 / 20.35 ±1.28 / 22.38 ms │ 1.05x slower │
│ QQuery 42 │ 111.54 / 114.44 ±2.00 / 117.05 ms │ 114.31 / 115.82 ±1.63 / 117.82 ms │ no change │
│ QQuery 43 │ 88.88 / 90.07 ±0.74 / 90.82 ms │ 91.44 / 92.91 ±1.27 / 95.08 ms │ no change │
│ QQuery 44 │ 17.22 / 17.65 ±0.30 / 18.11 ms │ 17.76 / 18.47 ±0.60 / 19.51 ms │ no change │
│ QQuery 45 │ 56.26 / 57.62 ±1.36 / 59.92 ms │ 57.65 / 58.82 ±1.24 / 60.56 ms │ no change │
│ QQuery 46 │ 237.39 / 241.22 ±2.23 / 244.25 ms │ 238.75 / 243.63 ±3.12 / 247.23 ms │ no change │
│ QQuery 47 │ 729.60 / 740.10 ±8.01 / 752.45 ms │ 738.50 / 746.44 ±5.76 / 756.47 ms │ no change │
│ QQuery 48 │ 291.51 / 296.10 ±3.57 / 301.59 ms │ 291.08 / 296.25 ±5.10 / 304.43 ms │ no change │
│ QQuery 49 │ 265.42 / 266.57 ±0.63 / 267.29 ms │ 267.40 / 270.71 ±2.14 / 273.68 ms │ no change │
│ QQuery 50 │ 242.29 / 246.49 ±4.13 / 251.60 ms │ 241.30 / 247.27 ±4.31 / 252.88 ms │ no change │
│ QQuery 51 │ 190.99 / 195.91 ±3.05 / 200.49 ms │ 191.64 / 193.72 ±2.54 / 198.63 ms │ no change │
│ QQuery 52 │ 113.38 / 115.07 ±1.55 / 117.96 ms │ 113.90 / 114.81 ±0.54 / 115.44 ms │ no change │
│ QQuery 53 │ 108.40 / 109.53 ±0.63 / 110.12 ms │ 109.02 / 110.33 ±1.31 / 112.57 ms │ no change │
│ QQuery 54 │ 155.44 / 158.36 ±1.87 / 160.38 ms │ 158.82 / 159.09 ±0.22 / 159.45 ms │ no change │
│ QQuery 55 │ 111.15 / 112.23 ±0.89 / 113.75 ms │ 111.37 / 113.13 ±1.63 / 115.97 ms │ no change │
│ QQuery 56 │ 151.69 / 152.92 ±0.95 / 154.14 ms │ 151.28 / 154.86 ±2.24 / 157.47 ms │ no change │
│ QQuery 57 │ 193.19 / 195.28 ±1.82 / 198.53 ms │ 196.64 / 198.96 ±1.65 / 200.89 ms │ no change │
│ QQuery 58 │ 309.14 / 319.06 ±5.35 / 324.79 ms │ 313.25 / 315.10 ±1.58 / 318.03 ms │ no change │
│ QQuery 59 │ 208.70 / 210.34 ±1.22 / 212.30 ms │ 212.43 / 214.65 ±1.26 / 215.87 ms │ no change │
│ QQuery 60 │ 155.09 / 157.18 ±1.49 / 159.66 ms │ 155.50 / 158.24 ±2.33 / 161.96 ms │ no change │
│ QQuery 61 │ 183.02 / 184.79 ±1.11 / 186.23 ms │ 186.93 / 188.28 ±0.94 / 189.61 ms │ no change │
│ QQuery 62 │ 890.71 / 943.12 ±41.04 / 1011.72 ms │ 914.10 / 946.79 ±50.60 / 1047.43 ms │ no change │
│ QQuery 63 │ 109.43 / 114.30 ±6.11 / 125.89 ms │ 110.00 / 111.33 ±0.82 / 112.24 ms │ no change │
│ QQuery 64 │ 722.33 / 730.05 ±5.12 / 735.53 ms │ 725.76 / 730.26 ±3.66 / 734.80 ms │ no change │
│ QQuery 65 │ 265.36 / 267.97 ±1.75 / 270.55 ms │ 264.40 / 267.41 ±1.74 / 269.64 ms │ no change │
│ QQuery 66 │ 267.90 / 272.05 ±3.47 / 276.92 ms │ 253.34 / 265.40 ±7.86 / 277.30 ms │ no change │
│ QQuery 67 │ 347.03 / 351.32 ±3.79 / 358.31 ms │ 337.30 / 349.99 ±8.79 / 364.80 ms │ no change │
│ QQuery 68 │ 290.26 / 292.44 ±1.93 / 295.87 ms │ 287.76 / 290.83 ±2.78 / 294.64 ms │ no change │
│ QQuery 69 │ 113.26 / 116.24 ±4.50 / 125.21 ms │ 114.23 / 116.24 ±2.18 / 119.90 ms │ no change │
│ QQuery 70 │ 352.38 / 368.49 ±16.31 / 395.51 ms │ 355.75 / 369.08 ±11.38 / 388.33 ms │ no change │
│ QQuery 71 │ 139.76 / 141.71 ±1.33 / 143.08 ms │ 141.92 / 144.63 ±2.40 / 148.52 ms │ no change │
│ QQuery 72 │ 725.44 / 744.76 ±16.60 / 773.85 ms │ 732.64 / 744.15 ±11.50 / 766.08 ms │ no change │
│ QQuery 73 │ 108.24 / 110.83 ±1.57 / 113.18 ms │ 108.13 / 110.31 ±1.56 / 112.13 ms │ no change │
│ QQuery 74 │ 576.29 / 589.70 ±11.36 / 607.66 ms │ 590.27 / 610.98 ±20.15 / 646.25 ms │ no change │
│ QQuery 75 │ 295.15 / 297.88 ±1.73 / 300.14 ms │ 297.90 / 301.23 ±2.26 / 304.95 ms │ no change │
│ QQuery 76 │ 138.99 / 140.14 ±0.87 / 141.41 ms │ 140.40 / 143.00 ±1.48 / 144.95 ms │ no change │
│ QQuery 77 │ 203.50 / 205.54 ±1.69 / 208.53 ms │ 207.62 / 209.76 ±1.28 / 210.95 ms │ no change │
│ QQuery 78 │ 363.95 / 367.76 ±2.16 / 369.91 ms │ 379.77 / 382.79 ±1.94 / 385.04 ms │ no change │
│ QQuery 79 │ 235.39 / 238.81 ±2.53 / 243.08 ms │ 245.24 / 251.61 ±4.22 / 256.19 ms │ 1.05x slower │
│ QQuery 80 │ 341.22 / 344.03 ±2.13 / 347.42 ms │ 346.61 / 350.58 ±2.45 / 353.83 ms │ no change │
│ QQuery 81 │ 32.12 / 33.36 ±1.10 / 35.17 ms │ 33.48 / 34.78 ±1.06 / 36.57 ms │ no change │
│ QQuery 82 │ 205.33 / 208.07 ±3.50 / 214.87 ms │ 209.42 / 212.27 ±2.15 / 214.76 ms │ no change │
│ QQuery 83 │ 47.36 / 49.61 ±2.39 / 54.06 ms │ 48.08 / 48.82 ±0.67 / 49.80 ms │ no change │
│ QQuery 84 │ 52.55 / 53.65 ±0.96 / 55.25 ms │ 53.43 / 54.66 ±1.03 / 56.10 ms │ no change │
│ QQuery 85 │ 153.95 / 154.72 ±0.85 / 156.35 ms │ 154.59 / 156.89 ±1.85 / 160.11 ms │ no change │
│ QQuery 86 │ 42.02 / 42.87 ±0.72 / 44.10 ms │ 42.74 / 43.81 ±0.83 / 44.93 ms │ no change │
│ QQuery 87 │ 94.33 / 98.10 ±2.33 / 101.13 ms │ 94.19 / 98.00 ±2.42 / 101.47 ms │ no change │
│ QQuery 88 │ 113.29 / 114.11 ±1.07 / 116.21 ms │ 115.61 / 116.95 ±1.32 / 119.16 ms │ no change │
│ QQuery 89 │ 125.21 / 127.69 ±1.72 / 129.45 ms │ 126.84 / 128.36 ±1.11 / 130.22 ms │ no change │
│ QQuery 90 │ 28.57 / 28.95 ±0.38 / 29.52 ms │ 29.67 / 30.33 ±0.57 / 31.27 ms │ no change │
│ QQuery 91 │ 66.38 / 67.07 ±0.82 / 68.65 ms │ 67.64 / 68.67 ±0.90 / 69.95 ms │ no change │
│ QQuery 92 │ 62.12 / 63.01 ±0.69 / 64.15 ms │ 64.08 / 65.66 ±1.11 / 67.10 ms │ no change │
│ QQuery 93 │ 195.69 / 198.58 ±1.78 / 201.10 ms │ 199.65 / 201.81 ±2.32 / 205.26 ms │ no change │
│ QQuery 94 │ 66.34 / 66.71 ±0.30 / 67.11 ms │ 68.11 / 69.53 ±1.28 / 71.28 ms │ no change │
│ QQuery 95 │ 143.22 / 144.98 ±1.00 / 146.00 ms │ 144.51 / 149.51 ±2.98 / 153.06 ms │ no change │
│ QQuery 96 │ 79.66 / 80.25 ±0.62 / 81.12 ms │ 80.43 / 81.56 ±0.70 / 82.44 ms │ no change │
│ QQuery 97 │ 133.02 / 136.35 ±1.69 / 137.70 ms │ 139.07 / 141.55 ±2.03 / 143.83 ms │ no change │
│ QQuery 98 │ 154.39 / 157.94 ±2.61 / 161.89 ms │ 160.61 / 162.60 ±1.80 / 165.92 ms │ no change │
│ QQuery 99 │ 10804.68 / 10827.26 ±23.84 / 10857.95 ms │ 10746.81 / 10817.01 ±53.23 / 10872.55 ms │ no change │
└───────────┴──────────────────────────────────────────┴──────────────────────────────────────────┴──────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary ┃ ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD) │ 34832.51ms │
│ Total Time (ndv-equality-filter) │ 35027.68ms │
│ Average Time (HEAD) │ 351.84ms │
│ Average Time (ndv-equality-filter) │ 353.81ms │
│ Queries Faster │ 0 │
│ Queries Slower │ 3 │
│ Queries with No Change │ 96 │
│ Queries with Failure │ 0 │
└────────────────────────────────────┴────────────┘

Resource Usage

tpcds — base (merge-base)

MetricValue
Wall time174.5s
Peak memory5.3 GiB
Avg memory4.4 GiB
CPU user275.8s
CPU sys22.0s
Disk read0 B
Disk write703.5 MiB

tpcds — branch

MetricValue
Wall time175.5s
Peak memory5.5 GiB
Avg memory4.6 GiB
CPU user277.2s
CPU sys22.0s
Disk read0 B
Disk write780.0 KiB

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Details

Comparing HEAD and ndv-equality-filter
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query ┃ HEAD ┃ ndv-equality-filter ┃ Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0 │ 1.59 / 4.84 ±6.36 / 17.55 ms │ 1.64 / 4.89 ±6.41 / 17.72 ms │ no change │
│ QQuery 1 │ 14.34 / 14.96 ±0.49 / 15.85 ms │ 14.57 / 15.15 ±0.34 / 15.55 ms │ no change │
│ QQuery 2 │ 56.82 / 57.27 ±0.40 / 57.78 ms │ 57.62 / 58.15 ±0.41 / 58.81 ms │ no change │
│ QQuery 3 │ 50.36 / 51.73 ±1.15 / 53.38 ms │ 51.16 / 52.39 ±0.96 / 54.07 ms │ no change │
│ QQuery 4 │ 316.51 / 324.41 ±8.22 / 336.60 ms │ 310.16 / 315.57 ±4.40 / 322.11 ms │ no change │
│ QQuery 5 │ 366.74 / 370.01 ±2.60 / 374.54 ms │ 355.94 / 358.96 ±4.03 / 366.58 ms │ no change │
│ QQuery 6 │ 5.28 / 7.09 ±2.30 / 11.60 ms │ 5.26 / 6.26 ±0.80 / 7.29 ms │ +1.13x faster │
│ QQuery 7 │ 17.37 / 17.82 ±0.49 / 18.58 ms │ 17.39 / 18.32 ±1.06 / 20.03 ms │ no change │
│ QQuery 8 │ 446.53 / 462.81 ±11.85 / 477.85 ms │ 455.36 / 459.57 ±3.38 / 465.09 ms │ no change │
│ QQuery 9 │ 682.01 / 694.31 ±9.12 / 705.50 ms │ 681.30 / 695.04 ±9.87 / 706.33 ms │ no change │
│ QQuery 10 │ 94.23 / 99.23 ±4.90 / 108.38 ms │ 93.92 / 96.39 ±2.78 / 101.81 ms │ no change │
│ QQuery 11 │ 108.49 / 109.54 ±0.80 / 110.55 ms │ 108.50 / 110.30 ±1.12 / 111.48 ms │ no change │
│ QQuery 12 │ 360.57 / 370.55 ±7.56 / 381.91 ms │ 348.18 / 356.29 ±7.11 / 365.20 ms │ no change │
│ QQuery 13 │ 497.59 / 508.14 ±7.25 / 517.31 ms │ 471.97 / 484.19 ±7.11 / 491.25 ms │ no change │
│ QQuery 14 │ 362.59 / 371.77 ±6.89 / 381.67 ms │ 364.00 / 368.30 ±3.82 / 373.35 ms │ no change │
│ QQuery 15 │ 366.46 / 384.27 ±13.66 / 402.98 ms │ 380.48 / 403.36 ±22.73 / 432.12 ms │ no change │
│ QQuery 16 │ 756.72 / 771.34 ±12.05 / 790.83 ms │ 773.68 / 807.77 ±37.72 / 878.77 ms │ no change │
│ QQuery 17 │ 753.06 / 773.12 ±30.71 / 833.97 ms │ 759.58 / 764.66 ±4.57 / 770.88 ms │ no change │
│ QQuery 18 │ 1425.21 / 1469.90 ±58.85 / 1585.83 ms │ 1487.76 / 1552.08 ±52.44 / 1628.38 ms │ 1.06x slower │
│ QQuery 19 │ 35.33 / 36.48 ±0.79 / 37.41 ms │ 35.61 / 36.65 ±1.01 / 37.96 ms │ no change │
│ QQuery 20 │ 707.33 / 722.61 ±16.49 / 751.55 ms │ 711.34 / 720.98 ±7.48 / 731.76 ms │ no change │
│ QQuery 21 │ 759.24 / 762.22 ±2.36 / 764.98 ms │ 762.15 / 765.97 ±3.74 / 772.93 ms │ no change │
│ QQuery 22 │ 1133.27 / 1138.12 ±5.18 / 1147.88 ms │ 1132.94 / 1136.50 ±3.16 / 1140.41 ms │ no change │
│ QQuery 23 │ 3185.53 / 3208.21 ±20.04 / 3235.85 ms │ 3178.55 / 3199.69 ±15.10 / 3223.39 ms │ no change │
│ QQuery 24 │ 103.16 / 105.77 ±3.07 / 110.49 ms │ 102.51 / 105.90 ±2.50 / 109.48 ms │ no change │
│ QQuery 25 │ 142.38 / 144.29 ±1.40 / 145.73 ms │ 141.84 / 144.45 ±2.22 / 147.43 ms │ no change │
│ QQuery 26 │ 99.27 / 103.59 ±2.92 / 106.90 ms │ 99.57 / 104.62 ±2.78 / 107.94 ms │ no change │
│ QQuery 27 │ 852.33 / 858.35 ±4.18 / 864.12 ms │ 853.38 / 861.61 ±8.68 / 873.02 ms │ no change │
│ QQuery 28 │ 7741.12 / 7751.89 ±10.31 / 7769.29 ms │ 7730.20 / 7798.65 ±46.18 / 7864.26 ms │ no change │
│ QQuery 29 │ 330.68 / 337.35 ±10.34 / 357.95 ms │ 332.66 / 337.67 ±6.63 / 350.46 ms │ no change │
│ QQuery 30 │ 373.12 / 377.53 ±4.25 / 382.66 ms │ 381.00 / 385.48 ±4.52 / 393.53 ms │ no change │
│ QQuery 31 │ 368.61 / 376.93 ±13.52 / 403.88 ms │ 381.82 / 398.87 ±14.48 / 418.94 ms │ 1.06x slower │
│ QQuery 32 │ 1071.34 / 1083.64 ±14.56 / 1109.08 ms │ 1086.31 / 1118.64 ±28.52 / 1164.23 ms │ no change │
│ QQuery 33 │ 1485.34 / 1504.15 ±19.14 / 1528.43 ms │ 1511.56 / 1531.82 ±18.85 / 1565.72 ms │ no change │
│ QQuery 34 │ 1513.75 / 1579.34 ±52.97 / 1659.69 ms │ 1561.15 / 1591.53 ±16.98 / 1610.86 ms │ no change │
│ QQuery 35 │ 412.36 / 417.71 ±3.07 / 421.25 ms │ 431.20 / 442.95 ±8.73 / 457.16 ms │ 1.06x slower │
│ QQuery 36 │ 117.28 / 124.76 ±4.79 / 131.77 ms │ 124.09 / 129.90 ±3.00 / 132.81 ms │ no change │
│ QQuery 37 │ 49.32 / 51.12 ±1.28 / 52.37 ms │ 51.06 / 53.87 ±1.96 / 55.94 ms │ 1.05x slower │
│ QQuery 38 │ 74.66 / 77.38 ±1.65 / 79.54 ms │ 76.36 / 78.21 ±1.55 / 80.52 ms │ no change │
│ QQuery 39 │ 218.00 / 230.70 ±8.39 / 243.53 ms │ 215.63 / 229.31 ±7.48 / 236.36 ms │ no change │
│ QQuery 40 │ 22.69 / 25.75 ±1.75 / 28.14 ms │ 24.00 / 28.17 ±2.58 / 31.30 ms │ 1.09x slower │
│ QQuery 41 │ 19.82 / 21.17 ±1.04 / 22.30 ms │ 21.25 / 22.53 ±0.97 / 23.69 ms │ 1.06x slower │
│ QQuery 42 │ 20.82 / 21.03 ±0.15 / 21.25 ms │ 21.08 / 21.47 ±0.55 / 22.56 ms │ no change │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary ┃ ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD) │ 27923.18ms │
│ Total Time (ndv-equality-filter) │ 28173.09ms │
│ Average Time (HEAD) │ 649.38ms │
│ Average Time (ndv-equality-filter) │ 655.19ms │
│ Queries Faster │ 1 │
│ Queries Slower │ 6 │
│ Queries with No Change │ 36 │
│ Queries with Failure │ 0 │
└────────────────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

MetricValue
Wall time140.8s
Peak memory38.5 GiB
Avg memory33.1 GiB
CPU user1324.7s
CPU sys91.3s
Disk read0 B
Disk write4.2 GiB

clickbench_partitioned — branch

MetricValue
Wall time142.1s
Peak memory40.7 GiB
Avg memory33.2 GiB
CPU user1329.2s
CPU sys95.5s
Disk read0 B
Disk write752.0 KiB

@jonathanc-n

Copy link
Copy Markdown
ContributorAuthor

No perf changes should occur here, either this or #21077 would need to be merged before we can test performance

@kosiewkosiew 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.

lgtm

@alamb
alamb enabled auto-merge April 3, 2026 13:11
@alamb
alamb added this pull request to the merge queueApr 3, 2026
Merged via the queue into apache:main with commit a89b527Apr 3, 2026
35 checks passed
github-merge-queueBot pushed a commit that referenced this pull request Apr 7, 2026
)
## Which issue does this PR close?
- Part of #20766
Related: #20789 (uses NDV for equality filter selectivity, complementary
- this PR improves the NDV output stats, that PR consumes them)
## Rationale for this change
When a filter predicate collapses a column interval to a single value
(e.g. `d_qoy = 1`), the output column can only have one distinct value.
Currently `distinct_count` is always demoted to `Inexact`, losing this
information.
This matters for downstream optimizers that rely on `distinct_count`,
such as join cardinality estimation in
`estimate_inner_join_cardinality`.
## What changes are included in this PR?
In `collect_new_statistics` (filter.rs), when the post-filter interval
has `lower == upper` (both non-null), set `distinct_count` to
`Precision::Exact(1)` instead of demoting the input NDV to `Inexact`.
## Are these changes tested?
Yes, 4 unit tests:
- Equality predicate (`a = 42`) -> NDV becomes `Exact(1)`
- OR predicate (`a = 42 OR a = 22`) -> interval does not collapse, NDV
stays `Inexact`
- AND with mixed predicates (`a = 42 AND b > 10 AND c = 7`) -> `a` and
`c` get `Exact(1)`, `b` stays `Inexact`
- Equality with absent bounds (`a = 42`, no min/max) -> interval
analysis still resolves to `Exact(1)`
## Are there any user-facing changes?
No breaking changes. Statistics consumers will now see `Exact(1)` for
`distinct_count` on columns constrained to a single value by filter
predicates.
Disclaimer: I used AI to assist in the code generation, I have manually
reviewed the output and it matches my intention and understanding.
---------
Co-authored-by: xudong.w <wxd963996380@gmail.com>
Dandandan pushed a commit to Dandandan/arrow-datafusion that referenced this pull request Apr 8, 2026
…che#21077)
## Which issue does this PR close?
- Part of apache#20766
Related: apache#20789 (uses NDV for equality filter selectivity, complementary
- this PR improves the NDV output stats, that PR consumes them)
## Rationale for this change
When a filter predicate collapses a column interval to a single value
(e.g. `d_qoy = 1`), the output column can only have one distinct value.
Currently `distinct_count` is always demoted to `Inexact`, losing this
information.
This matters for downstream optimizers that rely on `distinct_count`,
such as join cardinality estimation in
`estimate_inner_join_cardinality`.
## What changes are included in this PR?
In `collect_new_statistics` (filter.rs), when the post-filter interval
has `lower == upper` (both non-null), set `distinct_count` to
`Precision::Exact(1)` instead of demoting the input NDV to `Inexact`.
## Are these changes tested?
Yes, 4 unit tests:
- Equality predicate (`a = 42`) -> NDV becomes `Exact(1)`
- OR predicate (`a = 42 OR a = 22`) -> interval does not collapse, NDV
stays `Inexact`
- AND with mixed predicates (`a = 42 AND b > 10 AND c = 7`) -> `a` and
`c` get `Exact(1)`, `b` stays `Inexact`
- Equality with absent bounds (`a = 42`, no min/max) -> interval
analysis still resolves to `Exact(1)`
## Are there any user-facing changes?
No breaking changes. Statistics consumers will now see `Exact(1)` for
`distinct_count` on columns constrained to a single value by filter
predicates.
Disclaimer: I used AI to assist in the code generation, I have manually
reviewed the output and it matches my intention and understanding.
---------
Co-authored-by: xudong.w <wxd963996380@gmail.com>
Rich-T-kid pushed a commit to Rich-T-kid/datafusion that referenced this pull request Apr 21, 2026
## Which issue does this PR close?
<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax. For example
`Closesapache#123` indicates that this PR will close issue apache#123.
-->
- Part of apache#20766 .
## Rationale for this change
Used NDV for equality filter selectivity calculation. <!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.
-->
## What changes are included in this PR?
Check if it is equality filter, and selectivity will be calculated using
(1/NDV)
<!--
There is no need to duplicate the description in the issue here but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->
## Are these changes tested?
<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code
If tests are not included in your PR, please explain why (for example,
are they covered by existing tests)?
-->
## Are there any user-facing changes?
<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.
-->
<!--
If there are any breaking changes to public APIs, please add the `api
change` label.
-->
---------
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
Rich-T-kid pushed a commit to Rich-T-kid/datafusion that referenced this pull request Apr 21, 2026
…che#21077)
## Which issue does this PR close?
- Part of apache#20766
Related: apache#20789 (uses NDV for equality filter selectivity, complementary
- this PR improves the NDV output stats, that PR consumes them)
## Rationale for this change
When a filter predicate collapses a column interval to a single value
(e.g. `d_qoy = 1`), the output column can only have one distinct value.
Currently `distinct_count` is always demoted to `Inexact`, losing this
information.
This matters for downstream optimizers that rely on `distinct_count`,
such as join cardinality estimation in
`estimate_inner_join_cardinality`.
## What changes are included in this PR?
In `collect_new_statistics` (filter.rs), when the post-filter interval
has `lower == upper` (both non-null), set `distinct_count` to
`Precision::Exact(1)` instead of demoting the input NDV to `Inexact`.
## Are these changes tested?
Yes, 4 unit tests:
- Equality predicate (`a = 42`) -> NDV becomes `Exact(1)`
- OR predicate (`a = 42 OR a = 22`) -> interval does not collapse, NDV
stays `Inexact`
- AND with mixed predicates (`a = 42 AND b > 10 AND c = 7`) -> `a` and
`c` get `Exact(1)`, `b` stays `Inexact`
- Equality with absent bounds (`a = 42`, no min/max) -> interval
analysis still resolves to `Exact(1)`
## Are there any user-facing changes?
No breaking changes. Statistics consumers will now see `Exact(1)` for
`distinct_count` on columns constrained to a single value by filter
predicates.
Disclaimer: I used AI to assist in the code generation, I have manually
reviewed the output and it matches my intention and understanding.
---------
Co-authored-by: xudong.w <wxd963996380@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

coreCore DataFusion cratephysical-exprChanges to the physical-expr crates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jonathanc-n@Dandandan@adriangbot@kosiew@alamb