Skip to content

Conversation

@pepijnve
Copy link
Contributor

@pepijnve pepijnve commented Oct 18, 2025

Which issue does this PR close?

Rationale for this change

Case evaluation currently uses PhysicalExpr::evaluate_selection for each branch of the case expression. This implementation is fine, but because evaluate_selection is not specific to the case logic we're missing some optimisation opportunities. The main consequence is that too much work is being done filtering record batches and scattering results. This PR introduces specialised filtering logic and result interleaving for case.

A more detailed description and diagrams are available at #18075 (comment)

What changes are included in this PR?

Rewrite the case_when_no_expr and case_when_with_expr evaluation loops to avoid as much unnecessary work as possible. In particular the remaining rows to be evaluated are retained across loop iterations. This allows the record batch that needs to be filtered to shrink as the loop is being evaluated which reduces the number of rows that needs to be refiltered. If a when predicate does not match any rows at all, filtering is avoided entirely.

The final result is also not merged every loop iteration. Instead an index vector is constructed which is used to compose the final result once using a custom 'multi zip'/'interleave' like operation.

Are these changes tested?

Covered by existing unit tests and SLTs

Are there any user-facing changes?

No

@github-actions github-actions bot added physical-expr Changes to the physical-expr crates sqllogictest SQL Logic Tests (.slt) labels Oct 18, 2025
@pepijnve pepijnve changed the title Case reduce filtering Reduce unnecessary record batch filtering in "case without expression" Oct 18, 2025
@pepijnve
Copy link
Contributor Author

macOS test failure is unrelated afaict. Looks like a DNS issue on the test runner.

@pepijnve pepijnve force-pushed the case_reduce_filtering branch from 206af12 to 39ab973 Compare October 18, 2025 15:59
@pepijnve pepijnve changed the title Reduce unnecessary record batch filtering in "case without expression" Reduce unnecessary record batch filtering in "case with(out) expression" Oct 18, 2025
@pepijnve pepijnve marked this pull request as draft October 18, 2025 18:51
@pepijnve pepijnve force-pushed the case_reduce_filtering branch from 24e3d38 to 39ab973 Compare October 18, 2025 18:55
@pepijnve pepijnve force-pushed the case_reduce_filtering branch from 4442c54 to 7539068 Compare October 20, 2025 22:23
@github-actions github-actions bot removed the sqllogictest SQL Logic Tests (.slt) label Oct 20, 2025
@pepijnve pepijnve marked this pull request as ready for review October 20, 2025 22:26
@pepijnve pepijnve changed the title Reduce unnecessary record batch filtering in "case with(out) expression" Use interleave to compose case expression results Oct 20, 2025
@pepijnve
Copy link
Contributor Author

@alamb could you run the benchmarks against this?

@pepijnve
Copy link
Contributor Author

The test failure for f49d3ea seems unrelated. Pulling in changes from main to see if that resolves the problem.

@pepijnve pepijnve marked this pull request as draft October 22, 2025 18:30
@pepijnve pepijnve force-pushed the case_reduce_filtering branch from 96451ac to 864b156 Compare October 23, 2025 13:07
@pepijnve pepijnve changed the title Use interleave to compose case expression results Optimize interleaving of partial case expression results Oct 23, 2025
@pepijnve pepijnve force-pushed the case_reduce_filtering branch from 864b156 to 01d51d8 Compare October 23, 2025 13:15
Copy link
Member

@rluvaton rluvaton left a comment

Choose a reason for hiding this comment

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

Looks pretty good to me, left some comments, once resolved I can approve

@rluvaton
Copy link
Member

My rust generics skills are not at a point yet where I could figure out a good way to actually share the bulk of the logic. This would probably end up as a case of 'template method'.

I don't think you need generics here, you can have a trait for the logic and require implementation on the few differences (like evaluating the when)

@pepijnve
Copy link
Contributor Author

pepijnve commented Oct 27, 2025

Looks pretty good to me, left some comments, once resolved I can approve

I think I got 'em all except for the break suggestion. I would prefer to leave that as is so all the early exits follow the same and we don't need any special safety checks or assertions after the when/then loop. The duplicated calls to finish aren't ideal, but I feel this is better than the alternative.

I don't think you need generics here, you can have a trait for the logic and require implementation on the few differences (like evaluating the when)

I think I'm going to leave this for a followup PR. There are some subtle differences wrt an owned when array vs a reference that make this a bit tricky. Template method is nice in theory, but it also makes the code a bit harder to read since you need to jump back and forth between locations in the source file. Perhaps this is a case where it's better to not be ultra DRY?

@rluvaton
Copy link
Member

Looks pretty good to me, left some comments, once resolved I can approve

I think I got 'em all except for the break suggestion. I would prefer to leave that as is so all the early exits follow the same and we don't need any special safety checks or assertions after the when/then loop. The duplicated calls to finish aren't ideal, but I feel this is better than the alternative.

fine by me

I don't think you need generics here, you can have a trait for the logic and require implementation on the few differences (like evaluating the when)

I think I'm going to leave this for a followup PR. There are some subtle differences wrt an owned when array vs a reference that make this a bit tricky. Template method is nice in theory, but it also makes the code a bit harder to read since you need to jump back and forth between locations in the source file. Perhaps this is a case where it's better to not be ultra DRY?

np

@pepijnve
Copy link
Contributor Author

pepijnve commented Oct 27, 2025

I think I'm going to leave this for a followup PR. There are some subtle differences wrt an owned when array vs a reference that make this a bit tricky. Template method is nice in theory, but it also makes the code a bit harder to read since you need to jump back and forth between locations in the source file. Perhaps this is a case where it's better to not be ultra DRY?

np

Just for kicks I asked Claude code to give it a try. It came up with a solution that's similar to what I had in mind myself, but it resolved the reference vs owned problem by cloning &BooleanArray. It's only a shallow copy with some ref count bumps, but still seems like something you would want to avoid.

Leaving this challenge for later.

Copy link
Member

@rluvaton rluvaton left a comment

Choose a reason for hiding this comment

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

Great job @pepijnve! thanks for the PR.

@alamb do you want to continue your review or can I merge?

Comment on lines +194 to +198
/// The more constrained indexing mechanism used by this algorithm makes it easier to copy values
/// in contiguous slices. In the example below, the two subsequent elements from array `2` can be
/// copied in a single operation from the source array instead of copying them one by one.
/// Long spans of null values are also especially cheap because they do not need to be represented
/// in an input array.
Copy link
Member

Choose a reason for hiding this comment

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

BTW the check whether we have continues items from the same array and consecutive order of items can be added to interleave as well.

@pepijnve
Copy link
Contributor Author

Thanks for your help dotting the i's and crossing the t's @rluvaton

@rluvaton
Copy link
Member

rluvaton commented Oct 28, 2025

I'll run the benchmark again before merging (waiting for @alamb reply to know whether he wants to continue his review or not)

@rluvaton
Copy link
Member

Benchmark results:

Env

Neofetch:

ubuntu@ip-:~/datafusion/datafusion/physical-expr$ neofetch --off
ubuntu@ip-
-----------------------
OS: Ubuntu 24.04.3 LTS x86_64
Host: c5.metal 1.0
Kernel: 6.14.0-1011-aws
Uptime: 2 hours
Packages: 820 (dpkg), 4 (snap)
Shell: bash 5.2.21
Terminal: /dev/pts/0
CPU: Intel Xeon Platinum 8275CL (96) @ 3.900GHz
Memory: 1637MiB / 193026MiB

cpufetch:

ubuntu@ip-:~/datafusion/datafusion/physical-expr$ cpufetch
 Name:                Intel Xeon Platinum 8275CL
 Microarchitecture:   Cascade Lake
 Technology:          14nm
 Max Frequency:       3.900 GHz
 Sockets:             2
 Cores:               24 cores (48 threads)
 Cores (Total):       48 cores (96 threads)
 AVX:                 AVX,AVX2,AVX512
 FMA:                 FMA3
 L1i Size:            32KB (1.5MB Total)
 L1d Size:            32KB (1.5MB Total)
 L2 Size:             1MB (48MB Total)
 L3 Size:             35.75MB (71.5MB Total)
 Peak Performance:    11.98 TFLOP/s

Compare:

main:

  • Branch: main
  • Commit: bea4b68fc
  • Upstream: upstream/main

optimization:

  • Branch: case_reduce_filtering
  • Commit: pepijnve@7a4a24b51
  • Upstream: origin/case_reduce_filtering
Results
$ cargo bench --bench case_when -- --load-baseline optimization --baseline main

case_when 8192x3: CASE WHEN c1 <= 500 THEN 1 ELSE 0 END
                        time:   [53.611 µs 53.695 µs 53.777 µs]
                        change: [+3.2855% +3.5627% +3.8167%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high severe

case_when 8192x3: CASE WHEN c1 <= 500 THEN c2 ELSE c3 END
                        time:   [22.324 µs 22.361 µs 22.403 µs]
                        change: [+5.6317% +6.1119% +6.6143%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

case_when 8192x3: CASE WHEN c1 <= 500 THEN c2 [ELSE NULL] END
                        time:   [6.3978 µs 6.4011 µs 6.4048 µs]
                        change: [+1.1985% +1.4094% +1.6072%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 14 outliers among 100 measurements (14.00%)
  6 (6.00%) high mild
  8 (8.00%) high severe

case_when 8192x3: CASE c1 WHEN 1 THEN c2 WHEN 2 THEN c3 END
                        time:   [27.901 µs 27.931 µs 27.963 µs]
                        change: [-6.3486% -6.0872% -5.7951%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) high mild
  2 (2.00%) high severe

case_when 8192x3: CASE WHEN c1 == 0 THEN 0 WHEN c1 == 1 THEN 1 ... WHEN c1 == n THEN n ELSE n + 1 END
                        time:   [65.275 ms 65.306 ms 65.340 ms]
                        change: [-72.797% -72.776% -72.756%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  6 (6.00%) high mild
  1 (1.00%) high severe

case_when 8192x3: CASE WHEN c1 < 0 THEN 0 WHEN c1 < 1000 THEN 1 ... WHEN c1 < n * 1000 THEN n ELSE n + 1 END
                        time:   [197.77 µs 198.13 µs 198.50 µs]
                        change: [-47.790% -47.693% -47.600%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe

case_when 8192x3: CASE c1 WHEN 0 THEN 0 WHEN 1 THEN 1 ... WHEN n THEN n ELSE n + 1 END
                        time:   [69.361 ms 69.398 ms 69.437 ms]
                        change: [-68.445% -68.423% -68.400%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe

case_when 8192x3: CASE c2 WHEN 0 THEN 0 WHEN 1000 THEN 1 ... WHEN n * 1000 THEN n ELSE n + 1 END
                        time:   [182.58 µs 182.85 µs 183.10 µs]
                        change: [-47.380% -47.300% -47.221%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

case_when 8192x50: CASE WHEN c1 <= 500 THEN 1 ELSE 0 END
                        time:   [53.946 µs 54.011 µs 54.080 µs]
                        change: [+4.2469% +4.4854% +4.7280%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low mild
  6 (6.00%) high mild
  2 (2.00%) high severe

case_when 8192x50: CASE WHEN c1 <= 500 THEN c2 ELSE c3 END
                        time:   [191.48 µs 191.59 µs 191.70 µs]
                        change: [+1.2698% +1.4108% +1.5473%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 18 outliers among 100 measurements (18.00%)
  1 (1.00%) low severe
  3 (3.00%) low mild
  4 (4.00%) high mild
  10 (10.00%) high severe

case_when 8192x50: CASE WHEN c1 <= 500 THEN c2 [ELSE NULL] END
                        time:   [6.2858 µs 6.2887 µs 6.2919 µs]
                        change: [-4.3230% -4.1166% -3.9167%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  8 (8.00%) high mild
  6 (6.00%) high severe

case_when 8192x50: CASE c1 WHEN 1 THEN c2 WHEN 2 THEN c3 END
                        time:   [195.80 µs 196.00 µs 196.21 µs]
                        change: [-2.9970% -2.8401% -2.6754%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low severe
  1 (1.00%) low mild
  3 (3.00%) high mild
  4 (4.00%) high severe

case_when 8192x50: CASE WHEN c1 == 0 THEN 0 WHEN c1 == 1 THEN 1 ... WHEN c1 == n THEN n ELSE n + 1 END
                        time:   [713.30 ms 713.69 ms 714.09 ms]
                        change: [-50.040% -50.007% -49.977%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

case_when 8192x50: CASE WHEN c1 < 0 THEN 0 WHEN c1 < 1000 THEN 1 ... WHEN c1 < n * 1000 THEN n ELSE n + 1 END
                        time:   [1.3047 ms 1.3053 ms 1.3060 ms]
                        change: [-27.957% -27.896% -27.829%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  3 (3.00%) high mild
  3 (3.00%) high severe

case_when 8192x50: CASE c1 WHEN 0 THEN 0 WHEN 1 THEN 1 ... WHEN n THEN n ELSE n + 1 END
                        time:   [734.99 ms 735.27 ms 735.57 ms]
                        change: [-47.345% -47.319% -47.294%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

case_when 8192x50: CASE c2 WHEN 0 THEN 0 WHEN 1000 THEN 1 ... WHEN n * 1000 THEN n ELSE n + 1 END
                        time:   [1.3060 ms 1.3066 ms 1.3073 ms]
                        change: [-26.799% -26.738% -26.674%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  3 (3.00%) low mild
  3 (3.00%) high mild
  4 (4.00%) high severe

case_when 8192x100: CASE WHEN c1 <= 500 THEN 1 ELSE 0 END
                        time:   [54.655 µs 54.745 µs 54.844 µs]
                        change: [+4.2756% +4.5483% +4.8346%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe

case_when 8192x100: CASE WHEN c1 <= 500 THEN c2 ELSE c3 END
                        time:   [375.32 µs 375.49 µs 375.67 µs]
                        change: [+0.8718% +0.9941% +1.1125%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 12 outliers among 100 measurements (12.00%)
  1 (1.00%) low mild
  4 (4.00%) high mild
  7 (7.00%) high severe

case_when 8192x100: CASE WHEN c1 <= 500 THEN c2 [ELSE NULL] END
                        time:   [6.5703 µs 6.5732 µs 6.5766 µs]
                        change: [+0.8111% +1.0421% +1.2975%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 5 outliers among 100 measurements (5.00%)
  2 (2.00%) high mild
  3 (3.00%) high severe

case_when 8192x100: CASE c1 WHEN 1 THEN c2 WHEN 2 THEN c3 END
                        time:   [377.61 µs 377.72 µs 377.85 µs]
                        change: [-1.7167% -1.5865% -1.4691%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  6 (6.00%) high mild
  9 (9.00%) high severe

case_when 8192x100: CASE WHEN c1 == 0 THEN 0 WHEN c1 == 1 THEN 1 ... WHEN c1 == n THEN n ELSE n + 1 END
                        time:   [1.5675 s 1.5681 s 1.5687 s]
                        change: [-40.673% -40.646% -40.618%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) low mild
  1 (1.00%) high mild

case_when 8192x100: CASE WHEN c1 < 0 THEN 0 WHEN c1 < 1000 THEN 1 ... WHEN c1 < n * 1000 THEN n ELSE n + 1 END
                        time:   [2.4750 ms 2.4770 ms 2.4799 ms]
                        change: [-25.593% -25.514% -25.419%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  5 (5.00%) high mild
  7 (7.00%) high severe

case_when 8192x100: CASE c1 WHEN 0 THEN 0 WHEN 1 THEN 1 ... WHEN n THEN n ELSE n + 1 END
                        time:   [1.5862 s 1.5866 s 1.5870 s]
                        change: [-39.594% -39.575% -39.555%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) high mild

case_when 8192x100: CASE c2 WHEN 0 THEN 0 WHEN 1000 THEN 1 ... WHEN n * 1000 THEN n ELSE n + 1 END
                        time:   [2.4907 ms 2.4917 ms 2.4928 ms]
                        change: [-24.824% -24.783% -24.738%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  2 (2.00%) high mild
  11 (11.00%) high severe

lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [320.04 µs 320.21 µs 320.40 µs]
                        change: [-45.423% -45.330% -45.242%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [537.79 µs 538.01 µs 538.25 µs]
                        change: [-33.598% -33.556% -33.509%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  6 (6.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [184.73 µs 184.79 µs 184.85 µs]
                        change: [-46.289% -46.177% -46.064%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [220.32 µs 220.41 µs 220.51 µs]
                        change: [-50.624% -50.545% -50.454%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 17 outliers among 100 measurements (17.00%)
  2 (2.00%) low mild
  9 (9.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [447.02 µs 447.26 µs 447.53 µs]
                        change: [-44.879% -44.812% -44.721%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  3 (3.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [834.96 µs 835.28 µs 835.62 µs]
                        change: [-40.626% -40.542% -40.457%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  2 (2.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [184.39 µs 184.47 µs 184.56 µs]
                        change: [-46.405% -46.309% -46.209%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  6 (6.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [220.15 µs 220.26 µs 220.37 µs]
                        change: [-50.754% -50.696% -50.599%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  4 (4.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [603.80 µs 604.12 µs 604.46 µs]
                        change: [-49.568% -49.475% -49.382%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [1.1896 ms 1.1902 ms 1.1908 ms]
                        change: [-50.507% -50.457% -50.399%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  4 (4.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [184.41 µs 184.51 µs 184.63 µs]
                        change: [-46.395% -46.288% -46.180%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 17 outliers among 100 measurements (17.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild
  14 (14.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0
                        time:   [220.30 µs 220.38 µs 220.48 µs]
                        change: [-50.821% -50.738% -50.657%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  6 (6.00%) high mild
  8 (8.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [378.11 µs 378.38 µs 378.69 µs]
                        change: [-49.039% -48.933% -48.829%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [612.46 µs 612.69 µs 612.94 µs]
                        change: [-37.391% -37.306% -37.215%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  5 (5.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [261.74 µs 261.94 µs 262.14 µs]
                        change: [-46.855% -46.783% -46.700%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [325.58 µs 325.75 µs 325.93 µs]
                        change: [-43.071% -42.962% -42.855%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [499.83 µs 500.08 µs 500.34 µs]
                        change: [-52.121% -52.023% -51.939%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) low mild
  4 (4.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [884.19 µs 884.60 µs 885.07 µs]
                        change: [-45.898% -45.830% -45.764%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  4 (4.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [261.80 µs 261.91 µs 262.04 µs]
                        change: [-46.855% -46.766% -46.651%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  6 (6.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [326.22 µs 326.37 µs 326.54 µs]
                        change: [-43.056% -42.946% -42.845%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  5 (5.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [646.08 µs 646.36 µs 646.66 µs]
                        change: [-58.699% -58.631% -58.545%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  1 (1.00%) low mild
  5 (5.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [1.1819 ms 1.1823 ms 1.1828 ms]
                        change: [-57.450% -57.412% -57.352%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  5 (5.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [262.13 µs 262.29 µs 262.49 µs]
                        change: [-46.866% -46.768% -46.668%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.1
                        time:   [325.61 µs 325.77 µs 325.99 µs]
                        change: [-43.180% -43.061% -42.947%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  2 (2.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [310.68 µs 310.83 µs 311.00 µs]
                        change: [-50.227% -50.135% -50.035%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [482.26 µs 482.43 µs 482.62 µs]
                        change: [-40.847% -40.758% -40.669%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  5 (5.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [250.93 µs 251.05 µs 251.17 µs]
                        change: [-45.001% -44.890% -44.743%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  4 (4.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [311.69 µs 311.83 µs 311.98 µs]
                        change: [-40.073% -39.921% -39.796%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  6 (6.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [387.30 µs 387.64 µs 387.98 µs]
                        change: [-54.331% -54.245% -54.142%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [629.41 µs 629.72 µs 630.07 µs]
                        change: [-52.353% -52.259% -52.171%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [250.41 µs 250.50 µs 250.60 µs]
                        change: [-45.202% -45.107% -44.993%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  1 (1.00%) low mild
  6 (6.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [311.48 µs 311.60 µs 311.74 µs]
                        change: [-40.037% -39.932% -39.841%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  4 (4.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [484.81 µs 485.07 µs 485.35 µs]
                        change: [-61.369% -61.303% -61.235%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [825.12 µs 825.48 µs 825.87 µs]
                        change: [-62.526% -62.494% -62.450%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [249.95 µs 250.05 µs 250.16 µs]
                        change: [-45.170% -45.076% -44.972%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  1 (1.00%) low mild
  5 (5.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.1, nulls: 0.5
                        time:   [311.61 µs 311.72 µs 311.85 µs]
                        change: [-39.994% -39.856% -39.708%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  4 (4.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [317.88 µs 318.05 µs 318.24 µs]
                        change: [-45.762% -45.642% -45.516%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  2 (2.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [534.66 µs 534.87 µs 535.10 µs]
                        change: [-34.145% -34.046% -33.921%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  6 (6.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [184.25 µs 184.34 µs 184.47 µs]
                        change: [-46.503% -46.406% -46.311%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  5 (5.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [220.59 µs 220.71 µs 220.86 µs]
                        change: [-50.679% -50.542% -50.429%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [447.80 µs 448.11 µs 448.44 µs]
                        change: [-44.948% -44.860% -44.761%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [834.24 µs 834.66 µs 835.13 µs]
                        change: [-40.649% -40.568% -40.493%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  4 (4.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [184.60 µs 184.68 µs 184.76 µs]
                        change: [-46.387% -46.276% -46.164%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  1 (1.00%) low mild
  4 (4.00%) high mild
  9 (9.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [220.34 µs 220.44 µs 220.55 µs]
                        change: [-50.591% -50.513% -50.428%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  3 (3.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [601.98 µs 602.35 µs 602.81 µs]
                        change: [-49.679% -49.590% -49.517%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  3 (3.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [1.1897 ms 1.1903 ms 1.1910 ms]
                        change: [-50.241% -50.197% -50.155%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  5 (5.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [184.35 µs 184.44 µs 184.55 µs]
                        change: [-46.474% -46.351% -46.228%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  6 (6.00%) high mild
  8 (8.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0
                        time:   [220.35 µs 220.44 µs 220.53 µs]
                        change: [-50.673% -50.605% -50.554%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  6 (6.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [379.38 µs 379.64 µs 379.91 µs]
                        change: [-48.908% -48.828% -48.761%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  6 (6.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [611.33 µs 611.57 µs 611.83 µs]
                        change: [-37.400% -37.339% -37.291%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  5 (5.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [262.05 µs 262.16 µs 262.29 µs]
                        change: [-46.919% -46.846% -46.779%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  5 (5.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [325.99 µs 326.17 µs 326.38 µs]
                        change: [-43.095% -42.996% -42.920%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  3 (3.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [499.05 µs 499.31 µs 499.58 µs]
                        change: [-52.229% -52.182% -52.137%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [884.59 µs 884.93 µs 885.29 µs]
                        change: [-46.024% -45.966% -45.922%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  6 (6.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [261.96 µs 262.08 µs 262.22 µs]
                        change: [-46.906% -46.832% -46.773%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  3 (3.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [325.68 µs 325.82 µs 325.99 µs]
                        change: [-43.175% -43.075% -42.990%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  3 (3.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [648.99 µs 649.67 µs 650.48 µs]
                        change: [-58.611% -58.547% -58.485%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  3 (3.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [1.1823 ms 1.1827 ms 1.1832 ms]
                        change: [-57.509% -57.479% -57.449%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  8 (8.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [261.83 µs 261.95 µs 262.10 µs]
                        change: [-46.956% -46.915% -46.875%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.1
                        time:   [325.76 µs 325.88 µs 326.01 µs]
                        change: [-43.047% -43.001% -42.960%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [311.34 µs 311.47 µs 311.60 µs]
                        change: [-50.255% -50.173% -50.110%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [482.09 µs 482.30 µs 482.55 µs]
                        change: [-40.862% -40.790% -40.734%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  4 (4.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [249.66 µs 249.76 µs 249.88 µs]
                        change: [-45.318% -45.242% -45.183%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [312.05 µs 312.16 µs 312.29 µs]
                        change: [-40.111% -39.946% -39.815%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  4 (4.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [385.89 µs 386.22 µs 386.56 µs]
                        change: [-54.581% -54.495% -54.421%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  8 (8.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [629.63 µs 629.89 µs 630.18 µs]
                        change: [-52.291% -52.215% -52.158%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  6 (6.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [250.53 µs 250.63 µs 250.73 µs]
                        change: [-45.208% -45.120% -45.061%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [311.73 µs 312.14 µs 312.84 µs]
                        change: [-40.001% -39.846% -39.664%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  4 (4.00%) high mild
  10 (10.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [485.48 µs 485.79 µs 486.15 µs]
                        change: [-61.400% -61.369% -61.338%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [821.14 µs 821.43 µs 821.75 µs]
                        change: [-62.793% -62.772% -62.751%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  3 (3.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [250.50 µs 250.60 µs 250.71 µs]
                        change: [-45.067% -45.031% -44.991%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  7 (7.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.5, nulls: 0.5
                        time:   [311.67 µs 311.78 µs 311.91 µs]
                        change: [-40.104% -40.004% -39.933%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  3 (3.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [317.22 µs 317.35 µs 317.49 µs]
                        change: [-45.953% -45.850% -45.776%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  6 (6.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [535.44 µs 535.71 µs 536.02 µs]
                        change: [-34.093% -34.009% -33.943%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  9 (9.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [184.53 µs 184.61 µs 184.70 µs]
                        change: [-46.348% -46.203% -46.018%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  1 (1.00%) low mild
  4 (4.00%) high mild
  10 (10.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [220.76 µs 220.85 µs 220.96 µs]
                        change: [-50.533% -50.507% -50.479%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  6 (6.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [448.90 µs 449.25 µs 449.63 µs]
                        change: [-44.921% -44.846% -44.786%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  5 (5.00%) high mild
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [834.84 µs 835.13 µs 835.48 µs]
                        change: [-40.804% -40.722% -40.666%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  3 (3.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [184.62 µs 184.71 µs 184.82 µs]
                        change: [-46.457% -46.324% -46.147%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  1 (1.00%) high mild
  14 (14.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [220.54 µs 220.64 µs 220.76 µs]
                        change: [-50.627% -50.541% -50.446%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  6 (6.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [604.72 µs 605.11 µs 605.52 µs]
                        change: [-49.608% -49.500% -49.397%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 6 outliers among 100 measurements (6.00%)
  3 (3.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [1.1897 ms 1.1902 ms 1.1908 ms]
                        change: [-50.301% -50.239% -50.166%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [184.78 µs 184.89 µs 185.02 µs]
                        change: [-46.327% -46.264% -46.188%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  4 (4.00%) high mild
  10 (10.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0
                        time:   [220.78 µs 220.89 µs 221.02 µs]
                        change: [-50.481% -50.384% -50.286%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  5 (5.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [380.11 µs 380.35 µs 380.60 µs]
                        change: [-48.763% -48.658% -48.547%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [612.17 µs 612.50 µs 612.86 µs]
                        change: [-37.370% -37.290% -37.198%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  6 (6.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [261.13 µs 261.27 µs 261.43 µs]
                        change: [-47.060% -46.965% -46.873%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [325.59 µs 325.77 µs 325.98 µs]
                        change: [-43.134% -43.031% -42.932%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  5 (5.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [499.78 µs 500.12 µs 500.47 µs]
                        change: [-52.360% -52.251% -52.151%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  1 (1.00%) low mild
  8 (8.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [885.91 µs 886.37 µs 886.91 µs]
                        change: [-45.948% -45.899% -45.838%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  2 (2.00%) high mild
  9 (9.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [261.69 µs 261.82 µs 261.96 µs]
                        change: [-46.933% -46.816% -46.698%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 8 outliers among 100 measurements (8.00%)
  3 (3.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [325.81 µs 326.10 µs 326.47 µs]
                        change: [-43.161% -43.052% -42.950%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 14 outliers among 100 measurements (14.00%)
  5 (5.00%) high mild
  9 (9.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [646.48 µs 646.83 µs 647.21 µs]
                        change: [-58.858% -58.753% -58.676%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  4 (4.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [1.1822 ms 1.1827 ms 1.1833 ms]
                        change: [-57.590% -57.554% -57.511%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 11 outliers among 100 measurements (11.00%)
  6 (6.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [261.53 µs 261.64 µs 261.75 µs]
                        change: [-47.034% -46.964% -46.912%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  6 (6.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 0.9, nulls: 0.1
                        time:   [325.64 µs 325.75 µs 325.88 µs]
                        change: [-43.223% -43.074% -42.873%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  5 (5.00%) high mild
  8 (8.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [318.60 µs 318.77 µs 318.98 µs]
                        change: [-45.598% -45.499% -45.401%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  3 (3.00%) high mild
  4 (4.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [535.79 µs 536.02 µs 536.27 µs]
                        change: [-34.078% -34.002% -33.946%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) high mild
  6 (6.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [184.35 µs 184.43 µs 184.52 µs]
                        change: [-46.597% -46.499% -46.424%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  3 (3.00%) high mild
  10 (10.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 5 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [221.24 µs 221.32 µs 221.40 µs]
                        change: [-50.529% -50.450% -50.396%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  4 (4.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [447.56 µs 447.88 µs 448.22 µs]
                        change: [-44.991% -44.910% -44.843%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  3 (3.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [834.38 µs 834.71 µs 835.05 µs]
                        change: [-40.699% -40.629% -40.579%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  5 (5.00%) high mild
  2 (2.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [184.54 µs 184.61 µs 184.70 µs]
                        change: [-46.448% -46.323% -46.219%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  11 (11.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 10 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [220.74 µs 220.83 µs 220.93 µs]
                        change: [-50.540% -50.468% -50.418%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 12 outliers among 100 measurements (12.00%)
  7 (7.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [600.44 µs 600.73 µs 601.04 µs]
                        change: [-49.882% -49.802% -49.745%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
lookup_table_case_when/case when utf8 -> i32, 20 entries, all equally true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [1.1902 ms 1.1907 ms 1.1913 ms]
                        change: [-50.332% -50.302% -50.274%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 15 outliers among 100 measurements (15.00%)
  4 (4.00%) low mild
  6 (6.00%) high mild
  5 (5.00%) high severe
lookup_table_case_when/case when i32 -> utf8, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [184.29 µs 184.37 µs 184.47 µs]
                        change: [-46.503% -46.416% -46.354%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  6 (6.00%) high mild
  7 (7.00%) high severe
lookup_table_case_when/case when utf8 -> i32, 20 entries, only first 2 are true/case_when 8192 rows: in_range: 1, nulls: 0
                        time:   [220.92 µs 221.01 µs 221.11 µs]
                        change: [-50.534% -50.467% -50.411%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  7 (7.00%) high mild
  6 (6.00%) high severe

@pepijnve
Copy link
Contributor Author

pepijnve commented Oct 28, 2025

Does this warrant a closer look? Large relative difference, but small absolute one.

case_when 8192x3: CASE WHEN c1 <= 500 THEN c2 ELSE c3 END
                        time:   [22.324 µs 22.361 µs 22.403 µs]
                        change: [+5.6317% +6.1119% +6.6143%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

On the other hand there are also results like

case_when 8192x50: CASE WHEN c1 <= 500 THEN 1 ELSE 0 END
                        time:   [53.946 µs 54.011 µs 54.080 µs]
                        change: [+4.2469% +4.4854% +4.7280%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 9 outliers among 100 measurements (9.00%)
  1 (1.00%) low mild
  6 (6.00%) high mild
  2 (2.00%) high severe

which is in the same ballpark, but that's the EvalMethod::ExpressionOrExpression which didn't change AFAIK.

Edit: these are both actually EvalMethod::ExpressionOrExpression. This is why I had made this public, so I could be sure I was checking the right thing in the benchmarks at a glance 😄
So neither result is relevant for this PR.

Nice to see the improvements on the lookup benchmarks. Your hash table work will do even better, but for now this is a good proxy for more general case expressions.

@pepijnve
Copy link
Contributor Author

Looking at the profiler output for ExpressionOrExpression. Based on that I'm wondering if it might benefit from the same treatment after all. I'll give this a quick try and report back. We can keep that for a separate PR.

image

@rluvaton
Copy link
Member

[..] We can keep that for a separate PR.

different pr sounds good.

we should also start split different optimizations to different files to make it more manageable.

also, we need to add a way to check if expression can fail or not (e.g. divide can fail on divide by 0), column cannot fail (unless of course the column is missing)

this way it open another optimization for this that we can evaluate both in case it is cheap and do simple zip.

but for now we can add another optimization for column/literal or column/literal and do a simple zip

@rluvaton rluvaton added this pull request to the merge queue Oct 28, 2025
Merged via the queue into apache:main with commit e9431fc Oct 28, 2025
32 checks passed
@pepijnve
Copy link
Contributor Author

Removing the scatter and using a custom 'unaligned' zip compared to bea4b68

case_when 8192x3: CASE WHEN c1 <= 500 THEN c2 ELSE c3 END
                        time:   [9.9382 µs 9.9748 µs 10.013 µs]
                        change: [-31.136% -30.852% -30.574%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 1 outliers among 100 measurements (1.00%)

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

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

Thank you @pepijnve and @rluvaton

I had a chance to go through this PR today and it is quite clever. 👏

/// ││ C ││ ├─────────┤ ├─────────┤
/// │├─────────┤│ │ 2 │ │ C │
/// ││ D ││ ├─────────┤ ├─────────┤
/// │└─────────┘│ │ 2 │ │ D │
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the result array be B, A, C, C (b/c index 2 means C)? I made a PR to fix this:

Copy link
Contributor Author

@pepijnve pepijnve Oct 29, 2025

Choose a reason for hiding this comment

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

Answered in PR but just for completeness if anyone else reads this, the diagram is correct. Merge works like interleave, except the second index from interleave is implicitly defined as the number of times the first index value occurs. So 2, 2 for merge is equivalent to (2, 0), (2, 1) for interleave.

In executable code what's drawn is

let a1 = StringArray::from(vec![Some("A")]).to_data();
let a2 = StringArray::from(vec![Some("B")]).to_data();
let a3 = StringArray::from(vec![Some("C"), Some("D")]).to_data();

let indices = vec![
    PartialResultIndex::none(),
    PartialResultIndex::try_new(1).unwrap(),
    PartialResultIndex::try_new(0).unwrap(),
    PartialResultIndex::none(),
    PartialResultIndex::try_new(2).unwrap(),
    PartialResultIndex::try_new(2).unwrap()
];

let merged = merge(&vec![a1, a2, a3], &indices).unwrap();
let merged = merged.as_string::<i32>();

assert_eq!(merged.len(), indices.len());
assert!(!merged.is_valid(0));
assert!(merged.is_valid(1));
assert_eq!(merged.value(1), "B");
assert!(merged.is_valid(2));
assert_eq!(merged.value(2), "A");
assert!(!merged.is_valid(3));
assert!(merged.is_valid(4));
assert_eq!(merged.value(4), "C");
assert!(merged.is_valid(5));
assert_eq!(merged.value(5), "D");

Copy link
Contributor Author

@pepijnve pepijnve Oct 29, 2025

Choose a reason for hiding this comment

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

Added as unit test in #18369

github-merge-queue bot pushed a commit that referenced this pull request Oct 30, 2025
## Which issue does this PR close?

- None, followup for #18152

## Rationale for this change

Add a unit test testing (and demonstrating) the merge function.

## What changes are included in this PR?

Adds an additional test case

## Are these changes tested?

Who tests the tests?

## Are there any user-facing changes?

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

Labels

physical-expr Changes to the physical-expr crates sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants