Summary
Extend ALTER TABLE ... OPTIMIZE INDEX from #743 with size-tiered merge planning for scalar index segments.
ALTER TABLE table_name OPTIMIZE INDEX index_name
WITH (
target_rows_per_segment = 1000000,
target_bytes_per_segment = 1073741824,
merge_factor = 8
);
At least one target must be provided. Both targets are soft goals rather than strict limits.
Parameters
| Parameter |
Meaning |
target_rows_per_segment |
Desired number of indexed rows per output segment |
target_bytes_per_segment |
Desired physical size of an output segment |
merge_factor |
Number of similarly sized segments required to trigger a merge, and the maximum merge fan-in |
When both targets are provided, the dimension closest to its target controls segment sizing.
merge_factor is a scheduling parameter, not a direct mapping to Lance Core's numIndicesToMerge.
Planning
Planning runs against a single dataset snapshot:
- Append a new index segment for uncovered fragments, if any.
- Read physical segments from
describeIndices().
- Obtain each segment's:
- byte size from
Index#getSizeBytes();
- row count by summing the current rows of its covered fragments.
- Group similarly sized segments into internal size tiers.
- When a tier contains at least
merge_factor segments, select a merge group of up to merge_factor segments whose combined size is closest to the configured targets.
- Leave a fully covered index unchanged when no merge group is eligible.
Tier width is an implementation detail and is not exposed as a SQL parameter.
Execution
Size-tiered planning must select exact physical segments. It must not translate a group into numIndicesToMerge, because that option only selects trailing segments.
For each selected group, Spark uses the existing Lance APIs:
mergeExistingIndexSegments(group)
commitExistingIndexSegments(indexName, column, mergedSegments)
Multiple merged outputs should be committed atomically. Unselected segments remain unchanged.
Appending uncovered fragments may be a separate commit. If a later merge fails, the index remains correct and the next optimize operation can retry the merge.
Initial scope
The initial implementation covers mergeable scalar indexes such as BTree, ZoneMap, and FTS.
Vector indexes are excluded from the initial size-tiered policy. Physical vector-segment consolidation does not replace IVF partition rebalance, and independently rebalanced segments may have different model metadata. Existing vector optimizeIndices and retrain behavior remains delegated to Lance Core.
Distributed merge execution is a follow-up. The SQL contract and planning policy must not depend on whether merge tasks run on the driver or executors.
Dependencies
Acceptance criteria
- Supports row-based, byte-based, and combined targets.
- Selects exact, similarly sized physical segments.
- Does not merge unrelated large and small segments.
- Does not commit a new version when no append or merge is needed.
- Preserves index coverage after every commit.
- Includes validation, integration tests, and Spark SQL documentation.
Summary
Extend
ALTER TABLE ... OPTIMIZE INDEXfrom #743 with size-tiered merge planning for scalar index segments.At least one target must be provided. Both targets are soft goals rather than strict limits.
Parameters
target_rows_per_segmenttarget_bytes_per_segmentmerge_factorWhen both targets are provided, the dimension closest to its target controls segment sizing.
merge_factoris a scheduling parameter, not a direct mapping to Lance Core'snumIndicesToMerge.Planning
Planning runs against a single dataset snapshot:
describeIndices().Index#getSizeBytes();merge_factorsegments, select a merge group of up tomerge_factorsegments whose combined size is closest to the configured targets.Tier width is an implementation detail and is not exposed as a SQL parameter.
Execution
Size-tiered planning must select exact physical segments. It must not translate a group into
numIndicesToMerge, because that option only selects trailing segments.For each selected group, Spark uses the existing Lance APIs:
Multiple merged outputs should be committed atomically. Unselected segments remain unchanged.
Appending uncovered fragments may be a separate commit. If a later merge fails, the index remains correct and the next optimize operation can retry the merge.
Initial scope
The initial implementation covers mergeable scalar indexes such as BTree, ZoneMap, and FTS.
Vector indexes are excluded from the initial size-tiered policy. Physical vector-segment consolidation does not replace IVF partition rebalance, and independently rebalanced segments may have different model metadata. Existing vector
optimizeIndicesandretrainbehavior remains delegated to Lance Core.Distributed merge execution is a follow-up. The SQL contract and planning policy must not depend on whether merge tasks run on the driver or executors.
Dependencies
mergeExistingIndexSegmentsandcommitExistingIndexSegmentsAPIs.Acceptance criteria