-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Optimize muti-column grouping with StringView/ByteView #19364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
||
| fn vectorized_equal_to_inner( | ||
| /// Comparison when there are no nulls in array | ||
| fn vectorized_equal_to_no_nulls( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change 1 is to create a second copy of the loop when there are no nulls (to avoid the null check and give LLVM a better chance to optimize)
| array: &GenericByteViewArray<B>, | ||
| rhs_row: usize, | ||
| ) -> bool { | ||
| // SAFETY: the row indexes passed to vectorized_equal are in bounds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimization 2: skip bounds check on data access
| ) | ||
| }; | ||
| exist_inline == input_inline | ||
| // the views are inlined and the lengths are equal, so just |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimization 3: just compare the view directly rather than breaking it into parts first
|
run benchmarks |
|
run benchmark tpch |
|
run benchmarks |
|
🤖 |
|
My runner script keeps dying when there is a problem with the scripts. I am working on a way to keep it going (make it more resilent to failures) |
|
🤖: Benchmark completed Details
|
|
🤖 |
|
🤖: Benchmark completed Details
|
|
🤖 |
|
TPCH Q1 does have the pattern that is optimized in this PR (multiple group by columns) so it is plausible that the benefits are measured there datafusion/benchmarks/queries/q1.sql Lines 1 to 21 in 32951c3
|
I added some error checking here: alamb/datafusion-benchmarking@64ebd3a |
|
🤖: Benchmark completed Details
|
39690eb to
da34c4c
Compare
|
Marking back to draft as I try out some other ideas from @Dandandan |
|
run benchmark tpcds |
|
🤖 |
|
🤖: Benchmark completed Details
|
|
I benchmarked with/without the no buffers optimization and it seems to be worth around 1% (10ms out of 990ms) hyperfine --warmup 3 " ./datafusion-cli-starting -c \"select l_returnflag,l_linestatus, count(*) as count_order from 'lineitem.parquet' group by l_returnflag, l_linestatus;\" "Starting (before da34c4c) After da34c4c It seems reproducable: |
|
I have a better version here: |
…5% faster (#19413) ## 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 `Closes #123` indicates that this PR will close issue #123. --> - Part of #18411 - Closes #19344 - Closes #19364 Note this is an alternate to #19364 ## Rationale for this change @camuel found a query where DuckDB's raw grouping is is faster. I looked into it and much of the difference can be explained by better vectorization in the comparisons and short string optimizations ## What changes are included in this PR? Optimize (will comment inline) ## Are these changes tested? By CI. See also benchmark results below. I tested manually as well Create Data: ```shell nice tpchgen-cli --tables=lineitem --format=parquet --scale-factor 100 ``` Run query: ```shell hyperfine --warmup 3 " datafusion-cli -c \"select l_returnflag,l_linestatus, count(*) as count_order from 'lineitem.parquet' group by l_returnflag, l_linestatus;\" " ``` Before (main): 1.368s ```shell Benchmark 1: datafusion-cli -c "select l_returnflag,l_linestatus, count(*) as count_order from 'lineitem.parquet' group by l_returnflag, l_linestatus;" Time (mean ± σ): 1.393 s ± 0.020 s [User: 16.778 s, System: 0.688 s] Range (min … max): 1.368 s … 1.438 s 10 runs ``` After (this PR) 1.022s ```shell Benchmark 1: ./datafusion-cli-multi-gby-try2 -c "select l_returnflag,l_linestatus, count(*) as count_order from 'lineitem.parquet' group by l_returnflag, l_linestatus;" Time (mean ± σ): 1.022 s ± 0.015 s [User: 11.685 s, System: 0.644 s] Range (min … max): 1.005 s … 1.052 s 10 runs ``` I have a PR that improves string view hashing performance too, see - #19374 ## Are there any user-facing changes? Faster performance
Which issue does this PR close?
Rationale for this change
@camuel found a query where DuckDB's raw grouping is is faster.
I looked into it and much of the difference can be explained by better vectorization in the comparisons and short string optimizations
What changes are included in this PR?
Optimize (will comment inline)
Are these changes tested?
By CI. See also benchmark results below. I tested manually as well
Create Data:
Run query:
Before (main)
After (this PR)
I have some thoughts to improve string view hashing performance too -- will make as a separate PR
Are there any user-facing changes?
Faster performance