Keep the part sorted when TTL GROUP BY ... SET rewrites a sorting key column - #119863
Keep the part sorted when TTL GROUP BY ... SET rewrites a sorting key column#119863alexey-milovidov wants to merge 2 commits into
Conversation
… column `TTL ... GROUP BY ... SET` emits the aggregated rows at the position of their group in the merged stream, but a `SET` expression may assign arbitrary values to a column of the sorting key, so an aggregated row could be less than the previously emitted one. The merge wrote such a part as is: a debug build threw `Sort order of blocks violated` in `CheckSortedTransform`, and a release build produced a part whose primary index does not match the data. Now `TTLAggregationAlgorithm` tracks the sorting key of the last emitted row. If the next row violates the order, its sorting key is replaced with the key of the previous row, so the output stays sorted and the primary index stays consistent with the data. Closes: #108514 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… on the number of merges Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Workflow [PR], commit [aa22ea9] Summary: ❌
AI ReviewSummaryThis PR tries to repair Findings❌ Blockers
Tests
Final VerdictChanges requested. |
|
|
||
| Columns sort_key; | ||
| for (const auto & elem : sort_description) | ||
| sort_key.push_back(block.getByName(elem.column_name).column->convertToFullColumnIfSparse()); |
There was a problem hiding this comment.
MergeTask materializes the ORDER BY expression columns before TTL, so here we are comparing and rewriting those helper columns, not the sort key that will be recomputed from the stored row later. In the ORDER BY (k, toStartOfDay(ts)) shape from the issue, finalizeAggregates keeps toStartOfDay(ts) at its pre-SET value even after ts is reassigned, and this code just copies that stale helper value forward. MergeTreeDataPartWriter then rebuilds the primary index from the helper columns while the persisted row keeps the new ts, so expression keys can still leave the part/index contract broken. I think the sort-key expressions need to be recomputed from the post-SET row before any order repair happens.
| for (size_t i = 0; i < sorting_key.column_names.size(); ++i) | ||
| { | ||
| /// The header of a mutation may lack the sorting key expressions that are not in the primary key. | ||
| if (!header.has(sorting_key.column_names[i])) |
There was a problem hiding this comment.
This drops the fix on the MATERIALIZE TTL path whenever the sorting key is longer than the primary key. MutateTask only materializes getPrimaryKeyAndSkipIndicesExpression() before TTLTransform, so for a table like PRIMARY KEY k ORDER BY (k, toStartOfDay(ts)) the header has k but not toStartOfDay(ts). Breaking here means restoreSortOrder silently checks only the k prefix, so a SET ts = ... that reorders rows inside one k still writes an invalid part during ALTER TABLE ... MATERIALIZE TTL. If we cannot build the full sorting key on mutations, this shape needs to be rejected instead of partially checked.
Build profile diff (arm_release)Comparing ✅ No significant changes. Binary sizes
The official master build is compiled with Object file sizes4 object files changed (+23.09 KiB total), 0 added.
716 more object files are built by the master warmup baseline only (it builds every object-file target, a pull request build only Compile time of recompiled translation units8 translation units recompiled, 25 s compile time in total, 8 of them have a recent master baseline. |
TTL ... GROUP BY ... SETemits the aggregated rows at the position of their group in the merged stream, but aSETexpression may assign arbitrary values to a column of the sorting key (for exampleORDER BY (k, toStartOfDay(ts))withSET k = max(v)), so an aggregated row could be less than the previously emitted one. The merge wrote such a part as is: a debug build threw the logical errorSort order of blocks violatedinCheckSortedTransform, and a release build silently produced a part whose primary index does not match the data.Now
TTLAggregationAlgorithmtracks the sorting key of the last emitted row. If the next row violates the order, its sorting key is replaced with the sorting key of the previous row, so the output stays sorted and the primary index stays consistent with the data. This is a simpler alternative to #108550, which re-sorts the output of the TTL step.Closes: #108514
Related: #108550
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Fix the order of rows in a data part written by a merge with
TTL ... GROUP BY ... SETwhen theSETclause assigns a new value to a column of the sorting key. Previously such a merge could produce a part whose primary index does not match the data (a logical errorSort order of blocks violatedin debug builds). Now the sorting key of an out-of-order row is replaced with the sorting key of the previous row. Closes #108514.Workflow [PR]
Sync PR [sync-upstream/pr/119863]