fix(query): optimize numeric if branch selection - #20232
Draft
dantengsky wants to merge 2 commits into
Draft
Conversation
dantengsky
force-pushed
the
fix/numeric-if-branch-selection
branch
from
July 30, 2026 10:25
1d19bd9 to
2417c42
Compare
Contributor
🤖 CI Job Analysis (Retry 1)
📊 Summary
❌ NO RETRY NEEDEDAll failures appear to be code/test issues requiring manual fixes. 🔍 Job Details
🤖 AboutAutomated analysis using job annotations to distinguish infrastructure issues (auto-retried) from code/test issues (manual fixes needed). |
dantengsky
marked this pull request as draft
July 30, 2026 10:37
dantengsky
force-pushed
the
fix/numeric-if-branch-selection
branch
from
July 30, 2026 11:59
2417c42 to
ad08592
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I hereby agree to the terms of the CLA available at: https://docs.databend.com/dev/policies/cla/
Summary
Optimize final row selection for a binary
ifwhen the result is numeric or decimal.The generic evaluator selects every row through type-erased scalar values and a generic column builder. This is expensive after the condition and both result branches have already been evaluated.
Implementation
ifThe typed path is used only when the block has a known row count, the
ifhas exactly one condition, and the result type is supported.Performance
This is an evaluator benchmark, not an end-to-end
databend-querySQL benchmark.The benchmark uses the production release profile, 30 samples per case, and two block sizes:
max_block_sizeExpression parsing, type checking, and input construction are outside the timed section.
Evaluator::runand output allocation are timed. Divan drops the returned output after the timed section.Both revisions were built as separate release binaries. The binaries were pinned to CPU 1 and run five times in balanced interleaved order on an otherwise idle 16-CPU host. The tables report the median of the five Divan medians.
Numeric results
if_containsif_moduloif_containsif_moduloThe numeric reduction is large and directionally consistent at both block sizes.
Unsupported Boolean fallback
if_booleanreturns Boolean, so it does not use the new typed selector and continues through the existing generic selector.The after revision is consistently slower for this case in this evaluator microbenchmark. The added fallback work is one output-type dispatch per block, while the measured gap grows with the number of rows, so that dispatch cannot explain the result. Treat this as an unresolved regression: the current benchmark times condition evaluation, both result branches, and final selection together, and does not yet identify which stage regressed.
Absolute times depend on the machine. Run the comparison locally and focus on matching cases and row counts.
Reproduce
The first commit contains only the benchmark and measures the old evaluator. The second commit adds the optimization without changing the benchmark.
On Linux, build first and then pin the cached benchmark run to one CPU:
On systems without
taskset, omit that prefix. Run on an idle machine and compare matching cases and row counts. For lower noise, repeat before and after in alternating order and compare medians. The output also reports rows per second.--profile releaseis intentional: the repository bench profile enables debug assertions, while the production release profile does not. Separate target directories prevent Cargo artifacts from being reused across revisions.Tests
Commands run:
cargo fmt --all -- --check cargo test -p databend-common-functions --test it scalars::control::test_control cargo clippy -p databend-common-expression -p databend-common-functions --all-targets -- -D warnings cargo bench --profile release -p databend-common-functions --bench bench -- numeric_ifType of change
AI assistance
This change is