Skip to content

Do not sort batches for Batch sorted merge over unordered chunks if query sort matches compressed sort - #10303

Merged
natalya-aksman merged 1 commit into
mainfrom
skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks
Jul 29, 2026
Merged

Do not sort batches for Batch sorted merge over unordered chunks if query sort matches compressed sort#10303
natalya-aksman merged 1 commit into
mainfrom
skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks

Conversation

@natalya-aksman

@natalya-aksman natalya-aksman commented Jul 21, 2026

Copy link
Copy Markdown
Member

When we apply Batch sorted merge to unordered chunks and query sort is matching sort on compressed orderby leading metadata column, we do not need to sort batches before feeding them into Batch sorted merge heap.

--- Should be able to use Batch Sort Merge over unordered chunks 
--- without sorting compressed batches beforehand
SELECT * FROM t_segcol_orderbycol WHERE segcol = 1 ORDER BY orderbycol;

Our batches will already be sorted on (orderby leading metadata column) and the only reason we won't be able to use compressed sort is because the chunk is unordered.

Skipping unnecessary sort for Batch sort merge on unordered chunks can improve performance after Direct compress.

Removing unnecessary sort exposed an existing bug in ColumnarScan exec loop where we didn't quit asking for next batch and then trying to get next batch even after all compressed batches were consumed, as there could still be remaining tuples on the heap.
Sort node hid the bug as it would stop fetching batches residing in a sort buffer, but with the regular column scan we just kept fetching batches as we didn't hit the exit condition.
The bug is now fixed.

Part of work on https://github.com/timescale/eng-database/issues/811

Disable-check: force-changelog-file

@github-actions

Copy link
Copy Markdown

@pnthao, @akuzm: please review this pull request.

Powered by pull-review

@natalya-aksman
natalya-aksman force-pushed the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch from 757000f to 597d0d0 Compare July 21, 2026 18:46
@natalya-aksman
natalya-aksman requested review from Poroma-Banerjee, antekresic and svenklemm and removed request for pnthao July 21, 2026 18:46
@natalya-aksman natalya-aksman added performance Columnstore Related to the column store / compression planner labels Jul 21, 2026
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.73239% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
tsl/src/nodes/columnar_scan/columnar_scan.c 86.88% 2 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

@natalya-aksman

natalya-aksman commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

LLM Fuzzer found an issue needs addressed: https://github.com/timescale/timescaledb/actions/runs/29857661986

Will add tests for multikey orderby as we can't use compressed sort for BSM for multikey orderby over unordered chunks. UPDATE - done.

@natalya-aksman
natalya-aksman force-pushed the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch from 597d0d0 to 039fa86 Compare July 21, 2026 20:03
Comment thread tsl/src/nodes/columnar_scan/batch_queue.h Outdated
Comment thread tsl/src/nodes/columnar_scan/columnar_scan.c Outdated
@akuzm

akuzm commented Jul 22, 2026

Copy link
Copy Markdown
Member

Removing unnecessary sort exposed an existing bug in ColumnarScan exec loop where we didn't quit asking for next batch and then trying to get next batch even after all compressed batches were consumed, as there could still be remaining tuples on the heap.
Sort node hid the bug as it would stop fetching batches residing in a sort buffer, but with the regular column scan we just kept fetching batches as we didn't hit the exit condition.

Oh, I know this problem, sounds like this was actually a violation of Postgres protocol for exec nodes. In Postgres, if ExecProcNode returns NULL once, it means the scan ended, and you're not allowed to call it again. Otherwise some types of nodes will restart the scan.

Comment thread tsl/src/nodes/columnar_scan/batch_queue_heap.c Outdated
akuzm added a commit that referenced this pull request Jul 23, 2026
The high-level logic of the SkipScan node is similar to restarting a
correlated subquery with LIMIT 1, which is already reflected in the cost
model.

SkipScan cannot use the normal parameterized index scan, because
fundamentally the skip scan needs ordering, not comparison, and there's
no way to use comparison predicates to produce index ordering while
correctly handling NULLs. So we use a hacky approach where we directly
replace the index scan internals, replacing the entire comparison with
"null check" clause when needed.

After changing the parameters, the child node must be restarted. At the
moment we do it in a custom way that depends on the ColumnarScan
internals. This does not follow the standard Postgres API `ExecReScan`,
not fully resetting ColumnarScan and leading in turn to other problems
that were discovered in #10303. Remove the custom code and use the
standard `ExecReScan`. Our manual parameterization doesn't seem to
conflict with that.
@natalya-aksman
natalya-aksman force-pushed the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch 2 times, most recently from fc8d8bf to 4456d00 Compare July 23, 2026 13:05
Comment thread tsl/test/expected/compression_sorted_merge_unordered.out Outdated
Comment thread tsl/src/nodes/columnar_scan/exec.h
Comment thread tsl/src/nodes/columnar_scan/columnar_scan.c Outdated
@natalya-aksman
natalya-aksman force-pushed the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch 2 times, most recently from e101650 to d0f6206 Compare July 24, 2026 14:27

@antekresic antekresic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving but would love to see tests without segmentby to double check index is used correctly in that setup as well.

@natalya-aksman

Copy link
Copy Markdown
Member Author

Approving but would love to see tests without segmentby to double check index is used correctly in that setup as well.

There is a test on test_nosegby table which checks plan for skipping unnecessary sort, I'll add tests on table with no segmentby and overlapping batches, to check for correctness.

@natalya-aksman
natalya-aksman force-pushed the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch from d0f6206 to 2467570 Compare July 29, 2026 14:32
@natalya-aksman
natalya-aksman merged commit d1e64f3 into main Jul 29, 2026
104 of 117 checks passed
@natalya-aksman
natalya-aksman deleted the skip_matching_sort_for_batch_sorted_merge_on_unordered_chunks branch July 29, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Columnstore Related to the column store / compression performance planner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants