perf(scan): reduce system column pipeline overhead - #8747
Merged
Xuanwo merged 7 commits intoSep 4, 2026
Conversation
This was referenced Aug 25, 2026
jiaoew1991
changed the base branch from
jiaoew/stack-system-column-base-v5
to
main
August 25, 2026 12:28
BubbleCal
pushed a commit
that referenced
this pull request
Aug 26, 2026
## Summary Reuse a stable row-ID cursor across ordered record-batch tasks and bulk-decode range-backed segments. Stable row IDs represented as `RangeWithBitmap` / `RangeWithHoles` previously rebuilt selection state for every batch. Sequential scans therefore rescanned an ever-growing prefix, approaching quadratic work as batch count increased. This change: - persists `RowIdSequenceCursor` across ordered tasks and caches segment lengths; - adds an exact-capacity contiguous-range path; - adds `SegmentCursorState::extend_range` for bulk expansion of range and bitmap segments; - preserves the direct/random selection fallback and rejects unsorted indices explicitly; - reports truncated stable row-ID metadata as `CorruptFile` instead of panicking or returning a short batch. ## Performance 100K-row synthetic sequential scan, identical Criterion harness: | Batch size | `main` | This PR | Speedup | |---:|---:|---:|---:| | 64 | 17.177 ms | 1.174 ms | 14.6x | | 1024 | 1.868 ms | 236.16 us | 7.9x | CPU profiling on `main` attributed 51.73% to `RowIdSequence::select` and 33.45% to `U64Segment::len`, matching repeated prefix traversal. After this change those hotspots are replaced by `SegmentCursorState::extend_range`; remaining time is fixed allocation/schema work. ## Validation - `cargo test -p lance-table --lib` (336 passed) - `cargo check -p lance-table --tests --benches` - `cargo clippy -p lance-table --all-targets --no-deps -- -D warnings` - `cargo fmt --all -- --check` - `git diff --check` This is the root of the row-ID optimization stack and has no dependency on the bitmap or version-cursor follow-ups. Follow-up PRs: - #8715: dense / near-dense bitmap decode paths - #8716: dataset-version RLE cursor - #8747: system-column scan pipeline fixed-cost reduction
jiaoew1991
force-pushed
the
perf/system-column-scan-pipeline
branch
from
September 3, 2026 03:21
53925c6 to
8229ef7
Compare
Contributor
There was a problem hiding this comment.
✅ Gate recommendation: approve.
The rebase preserves all five substantive patches exactly. Current-head stream and fragment regressions remain clean, and the intervening row-ID optimization is isolated to index/cache lookup rather than this stream-selection path, so the prior correctness and base-equivalent variable-task performance evidence remains valid.
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.
Summary
Reduce fixed per-batch work in the system-column scan pipeline after the row-ID and version cursors have removed decoder prefix scans.
This supersedes #8717, which was merged into its temporary integration base while the dependency stack was being refreshed. No version of #8717 was merged into
main.This change:
RecordBatchfor uniform task streams, while variable task streams retain the prior incremental assembly;Arc<Schema>values, and disables that cache after task sizes vary;For batches up to 64K rows, each cached row-ID chunk is at most 64K
u64values (512 KiB). A larger batch is decoded as one batch without additional read-ahead. Zero-copy slices can keep a chunk alive until adjacent batches are released; an irregular stream can make one boundary copy while draining the existing chunk.Performance
Benchmarks compare
mainata8bec27d5(including #8716) with this branch, userelease-with-debug, pin both revisions to the same CPU, and run each case in a fresh process.The 100K-row uniform-task matrix improved all 16 combinations of batch size (64/1024), bitmap density (holes every 2/17 values), payload (absent/present), and system columns (
_rowid/all):_rowidimproved 30.3%-33.7%; all system columns improved 51.4%-56.8%;_rowidimproved 13.1%-26.5%; all system columns improved 29.5%-36.7%.A standard Criterion run for the representative batch-size-64, holes-17, zero-payload, all-system-columns case measured 3.7000 ms on
mainand 1.7455 ms here (-52.8%). CPU profiles attribute the change:RecordBatchExt::try_with_column(7.47% self time onmain) andSchemaExt::try_with_column(4.59%) both fell below the 0.1% reporting threshold.The review reproducer uses 10M rows, holes-17, one payload column,
_rowid, and alternating 32,768/32,769-row tasks. With isolated base/head target directories, standard Criterion measured 10.387-10.468 ms onmainand 10.449-10.499 ms here (+0.51% by point estimate, within run noise). A second pair underperf recordmeasured 10.699-10.746 ms and 10.652-10.724 ms, respectively. Profiles show the same dominant workload (SegmentCursorState::extend_dense_range, 42.17% / 42.22% self time);RecordBatchExt::try_with_columnwas only 0.16% / 0.10%, and schema reconstruction and boundary copying were not hotspots.Validation
cargo test -p lance-table --lib(384 passed)cargo test -p lance --lib dataset::fragment(108 passed)cargo check -p lance-table --tests --benchescargo clippy --all --tests --benches -- -D warningscargo fmt --all -- --checkgit diff --checktest_to_batches_with_partial_last_batch,test_to_batches,test_scan_no_columns, andtest_roundtrip_reader(4 passed)Targeted regressions cover mixed payload + all-system projection schema/order, uniform structurally equal schemas with different
Arcs, variable-task fallback, stable-row-ID unsorted indices and metadata underfill, read-ahead tail/chunk boundaries, empty tasks, and system-onlyread_all/read_ranges.Dependencies #8713, #8715, and #8716 are merged into
main. This PR's diff is limited to the system-column benchmark and the two implementation files.