feat: Optimize TopK for single primitive column sorts#21336
feat: Optimize TopK for single primitive column sorts#21336Dandandan wants to merge 1 commit intoapache:mainfrom
Conversation
For ORDER BY on a single primitive column (int, float, date, timestamp, etc.), bypass Arrow's RowConverter entirely and use inline u128 keys with order-preserving encoding. This avoids heap allocation per row (Vec<u8>), batch-level row conversion overhead, and variable-length byte-slice comparison. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
run benchmarks |
|
🤖 Benchmark running (GKE) | trigger CPU Details (lscpu)Comparing topk-native-optimization (e3c43c7) to 1e93a67 (merge-base) diff using: tpch File an issue against this benchmark runner |
|
🤖 Benchmark running (GKE) | trigger CPU Details (lscpu)Comparing topk-native-optimization (e3c43c7) to 1e93a67 (merge-base) diff using: tpcds File an issue against this benchmark runner |
|
🤖 Benchmark running (GKE) | trigger CPU Details (lscpu)Comparing topk-native-optimization (e3c43c7) to 1e93a67 (merge-base) diff using: clickbench_partitioned File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Instance: CPU Details (lscpu)Details
Resource Usagetpch — base (merge-base)
tpch — branch
File an issue against this benchmark runner |
|
Benchmark for this request failed. Last 20 lines of output: Click to expandFile an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Instance: CPU Details (lscpu)Details
Resource Usagetpcds — base (merge-base)
tpcds — branch
File an issue against this benchmark runner |
Which issue does this PR close?
N/A — performance optimization.
Rationale for this change
For
ORDER BY <single_primitive_column> LIMIT Kqueries, the current TopK operator converts every incoming row through Arrow'sRowConverterinto heap-allocatedVec<u8>byte slices, then compares those slices. This has three sources of overhead:TopKRowstores aVec<u8>for the sort keyWhat changes are included in this PR?
Adds a specialized native TopK path (
TopKInner::Native) for single-column sorts on primitive types (integers, floats, dates, timestamps, durations):NativeTopKRow: stores the sort key as an inlineu128(no heap allocation) with order-preserving encoding that handles ASC/DESC and NULLS FIRST/LASTNativeTopKHeap:BinaryHeap<NativeTopKRow>with the same compaction/emit logic as the existingTopKHeapfind_new_native_topk_items: type-dispatched inner loop that downcasts toPrimitiveArray<T>once per batch, then encodes and compares native values directlyTopKnow holds aTopKInnerenum (Row|Native), automatically selecting the native path intry_newwhen applicableThe existing row-based path is unchanged for multi-column sorts and non-primitive types.
Are these changes tested?
test_topk_marks_filter_completewhich exercises the native path via single Int32 column)Are there any user-facing changes?
No — this is a transparent performance optimization. Query results are unchanged.
🤖 Generated with Claude Code