Preserve original key order in bucketed Map serialization by Avogar · Pull Request #109178 · ClickHouse/ClickHouse · GitHub
Skip to content

Preserve original key order in bucketed Map serialization#109178

Open
Avogar wants to merge 3 commits into
masterfrom
fix-bucketed-map-key-order
Open

Preserve original key order in bucketed Map serialization#109178
Avogar wants to merge 3 commits into
masterfrom
fix-bucketed-map-key-order

Conversation

@Avogar

@Avogar Avogar commented Jul 2, 2026

Copy link
Copy Markdown
Member

Bucketed Map serialization (PR #99200) splits map keys into buckets by hash, which reorders them. This breaks ColumnMap::compareAt (positional comparison) and operations that depend on it: ORDER BY, DISTINCT, GROUP BY, min/max, and equality filters on Map columns.

Fix by writing an additional MapBucketIndexes substream during serialization that records each key-value pair's bucket index in original insertion order. During deserialization, this stream is used to reconstruct the original key order from per-bucket data.

Key changes:

  • Add SubstreamType::MapBucketIndexes for the new stream
  • Add CheckStreamExistsCallback to DeserializeBinaryBulkSettings for backward compatibility with old parts lacking the stream
  • Update SerializationMap: write/read bucket indexes, implement collectMapFromBucketsWithOrder
  • Update SerializationMapKeysOrValues: same for m.keys/m.values subcolumn reads
  • Set check_stream_exists_callback in MergeTreeReaderWide and MergeTreeReaderCompact
  • Update existing test reference files for correct key ordering
  • Add stateless tests for key order preservation and comparison correctness
  • Add integration test for backward compatibility with old parts

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in an official stable release)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Preserve original key order in bucketed Map serialization to fix comparison operations that depend on it.

Bucketed Map serialization (PR #99200) splits map keys into buckets by
hash, which reorders them. This breaks `ColumnMap::compareAt` (positional
comparison) and operations that depend on it: ORDER BY, DISTINCT,
GROUP BY, min/max, and equality filters on Map columns.

Fix by writing an additional `MapBucketIndexes` substream during
serialization that records each key-value pair's bucket index in original
insertion order. During deserialization, this stream is used to
reconstruct the original key order from per-bucket data.

Key changes:
- Add `SubstreamType::MapBucketIndexes` for the new stream
- Add `CheckStreamExistsCallback` to `DeserializeBinaryBulkSettings`
  for backward compatibility with old parts lacking the stream
- Update `SerializationMap`: write/read bucket indexes, implement
  `collectMapFromBucketsWithOrder`
- Update `SerializationMapKeysOrValues`: same for `m.keys`/`m.values`
  subcolumn reads
- Set `check_stream_exists_callback` in `MergeTreeReaderWide` and
  `MergeTreeReaderCompact`
- Update existing test reference files for correct key ordering
- Add stateless tests for key order preservation and comparison
  correctness
- Add integration test for backward compatibility with old parts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@clickhouse-gh

clickhouse-gh Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@clickhouse-gh clickhouse-gh Bot added the pr-bugfix Pull request with bugfix, not backported by default label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant