Skip to content

storage: Fast approximate snapshot partitioning - #37994

Draft
peterdukelarsen wants to merge 2 commits into
MaterializeInc:mainfrom
peterdukelarsen:pl/mysql-snapshot-prefix-partition
Draft

storage: Fast approximate snapshot partitioning#37994
peterdukelarsen wants to merge 2 commits into
MaterializeInc:mainfrom
peterdukelarsen:pl/mysql-snapshot-prefix-partition

Conversation

@peterdukelarsen

@peterdukelarsen peterdukelarsen commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Motivation

The boundary computation for parallel snapshotting was about as slow as the single-threaded snapshot in many cases, i.e.
Parallelized (~2h runtime):
Screenshot 2026-08-03 at 10 42 14 AM Screenshot 2026-08-03 at 10 42 49 AM

Single-threaded (~1h50m runtime):
Screenshot 2026-08-03 at 10 44 07 AM Screenshot 2026-08-03 at 10 44 27 AM

Description

Probes the values of a single-column string primary key using EXPLAIN and SELECT LIKE queries to compute approximate partitioning.

In slightly more detail we:

  1. Grab all of the unique first characters of the primary key strings and use EXPLAIN to estimate their row count
  2. For any character with a high row count we will redo the process one character deeper
  3. We continue stepping down into longer prefixes until we run out of a configured number of calls to make or we've resolved granular enough buckets to build partition boundaries
  4. Finally, we pick partition boundaries based on the total estimated row count (which could diverge from the real row count or the regular estimated row count by a good bit), and just walk the partitions in order computing boundary keys, which are just prefixes.

Downsides

  1. Complexity
  2. Won't work in all cases -- particularly any cases with extremely high cardinality characters in their prefixes could devolve. To work around this we'll implement some caps on the number of queries we make, but that will mean this doesn't apply to all string PK shapes.

Verification

  1. Deployed 777e7e8 to staging and snapshot 1B row table (August 3, around noon-3pm EDT)

Replace the OFFSET-walking boundary discovery with a prefix-based
partitioner in mz-mysql-util. Ranges the optimizer estimates too large
are recursively subdivided at each distinct key prefix one character
longer, then accumulated into per-worker buckets, so discovery costs
EXPLAIN index dives instead of an O(rows) index pass.

Only string primary keys are supported. Integer keys, which the OFFSET
walk used to sample, now fall back to a single-worker whole-table read.
Prefixes of a numeric key do not order consistently with its values, so
they would need a separate numeric range splitter.

All key ordering happens server-side under the column collation. The
walk guards against non-advancing prefixes and caps children per split
so a misbehaving server cannot hang it, and boundaries still pass the
existing strict-monotonicity verification in each read transaction.

The new mysql_source_snapshot_partition_min_rows dyncfg (default
50000) stops splitting below a minimum range size. Test configs set it
low so the tiny tables in mysql-cdc testdrive and parallel-workload
still exercise range reads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@peterdukelarsen
peterdukelarsen force-pushed the pl/mysql-snapshot-prefix-partition branch from 57d29d8 to 777e7e8 Compare July 31, 2026 23:50
Log the number of queries the prefix partitioner issues per table, the
duration of each table's split computation and of the whole bounds
sampling phase, and the boundaries that came out.

TODO markers note that this logging must be removed or downgraded
before merging.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant