Skip to content

Core, Spark 4.1: Add compute_sort_order_stats procedure to measure sort-key file overlap - #17504

Open
gimgit wants to merge 2 commits into
apache:mainfrom
gimgit:compute-sort-order-stats
Open

Core, Spark 4.1: Add compute_sort_order_stats procedure to measure sort-key file overlap#17504
gimgit wants to merge 2 commits into
apache:mainfrom
gimgit:compute-sort-order-stats

Conversation

@gimgit

@gimgit gimgit commented Aug 4, 2026

Copy link
Copy Markdown

Relates to #17489.

What

Adds a read-only Spark procedure compute_sort_order_stats that reports, per partition, how well the data file layout matches the table's declared sort order:

CALL catalog.system.compute_sort_order_stats(table => 'db.tbl' [, snapshot_id => ...]);
output meaning
max_overlap_depth largest number of data files whose ranges on the first sort field cover a single point — 1 = perfectly clustered
avg_overlap_depth mean overlap depth over files with bounds
file_count / files_missing_bounds files without bounds for the sort field are excluded from depth and surfaced explicitly

Why

As described in #17489, rewrite_data_files candidate selection considers only file size, so a table whose files are all within the healthy size band is permanently excluded from sort/z-order compaction — the job reports success on every run while sort-key overlap never improves. Today there is no way to detect this state: every size-based health metric reports such a table as perfectly healthy. This was also the missing piece asked in #12761 ("Do you have a way to identify the non-sorted files somehow?").

This PR intentionally starts with measurement only (no planner/selection changes), so operators can detect the state and decide when to trigger a rewrite-all/filtered rewrite. A follow-up could add an opt-in selection option as sketched in #17489.

How

  • SortOrderStatsHandler (core): computes overlap depth purely from data file metadata (lowerBounds/upperBounds of the first sort field) via a sweep line over [lower, upper] ranges — no data files are opened, nothing is committed.
    • requires a sort order whose first field uses an order-preserving transform (validated)
    • only the first sort field is considered, analogous to how clustering depth is commonly reported for multi-column layouts
    • truncated bounds can only widen a range, so the reported depth is an upper-bound estimate (documented)
  • ComputeSortOrderStatsProcedure (Spark 4.1): thin read-only wrapper returning one row per partition. Scoped to Spark 4.1 first; happy to backport to 4.0/3.5 if this lands.
  • No Action layer: the computation is driver-side metadata-only, so the procedure calls the core handler directly (same pattern as other read-only procedures). Can add the action layer if preferred.

Testing

  • TestSortOrderStatsHandler (core, 10 cases): full overlap, disjoint, touching boundaries, partial overlap, missing bounds (partial/all), single file, unsorted table, non-order-preserving transform, snapshot_id time travel
  • TestComputeSortOrderStatsProcedure (spark-extensions, 6 cases × 4 catalogs): empty table, unsorted failure, overlap/disjoint reporting, per-partition reporting, snapshot_id

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