Skip to content

feat(datetime): support date_bin literal origins for range locality - #27135

Merged
alamb merged 2 commits into
apache:mainfrom
benbellick:feat/date-bin-literal-origin-locality
Nov 9, 2026
Merged

alamb merged 2 commits into
apache:mainfrom
benbellick:feat/date-bin-literal-origin-locality

Conversation

@benbellick

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Closes #26913.

Rationale for this change

An explicit origin currently prevents date_bin from reusing range partitioning for aggregation, even when its buckets align with every range split.

What changes are included in this PR?

Admit non-null literal origins while retaining timezone-less nanosecond timestamps and positive fixed-duration, month-free strides. A fixed origin shifts the buckets without changing their nondecreasing behavior. The existing boundary proof still rejects crossing buckets and evaluation errors.

What is the testing strategy for this PR?

SQLLogicTests check plans and results for explicit epoch, shifted-aligned, and crossing origins. Unit tests cover rejected arguments, ascending/descending splits, and fail-closed boundary errors.

Are there any user-facing changes?

More aligned date_bin aggregations can avoid a hash shuffle. No function-result or public API changes.


Note: This PR was developed with AI assistance. All changes have been reviewed, and I take full responsibility for this contribution.

@github-actions github-actions Bot added physical-expr Changes to the physical-expr crates sqllogictest SQL Logic Tests (.slt) functions Changes to functions implementation labels Nov 5, 2026
@benbellick

Copy link
Copy Markdown
Contributor Author

cc @NGA-TRAN @jayzhan211 Another small extension, thanks!

@benbellick
benbellick marked this pull request as ready for review November 5, 2026 17:59

@NGA-TRAN NGA-TRAN left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Thanks Ben

06)----------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch_range_partitioning/range_sorted_time_bin/part-0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch_range_partitioning/range_sorted_time_bin/part-1.parquet]]}, projection=[key, col4, timestamp, value], output_ordering=[key@0 ASC, timestamp@2 ASC], output_partitioning=Range([timestamp@2 ASC], [(1704070800000000000)], 2), file_type=parquet, predicate=col4@4 = a, pruning_predicate=col4_null_count@2 != row_count@3 AND col4_min@0 <= a AND a <= col4_max@1, required_guarantees=[col4 in (a)]
02)--AggregateExec: mode=SinglePartitioned, gby=[key@0 as key, date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 60000000000 }, timestamp@1, 0) as date_bin(IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 60000000000 }"),range_sorted_time_bin.timestamp,Utf8("1970-01-01 00:00:00"))], aggr=[sum(range_sorted_time_bin.value)], group_clustering_mode=Full
03)----FilterExec: col4@1 = a, projection=[key@0, timestamp@2, value@3]
04)------DataSourceExec: file_groups={2 groups: [[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch_range_partitioning/range_sorted_time_bin/part-0.parquet], [WORKSPACE_ROOT/datafusion/sqllogictest/test_files/scratch_range_partitioning/range_sorted_time_bin/part-1.parquet]]}, projection=[key, col4, timestamp, value], output_ordering=[key@0 ASC, timestamp@2 ASC], output_partitioning=Range([timestamp@2 ASC], [(1704070800000000000)], 2), file_type=parquet, predicate=col4@4 = a, pruning_predicate=col4_null_count@2 != row_count@3 AND col4_min@0 <= a AND a <= col4_max@1, required_guarantees=[col4 in (a)]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@jayzhan211
jayzhan211 self-requested a review November 7, 2026 13:50

@jayzhan211 jayzhan211 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benbellick thanks for the PR. On skewed tables this change makes three-argument date_bin slower: when one file holds 97% of 16M rows and groups are mostly unique, the new SinglePartitioned plan takes 2.3x the shuffle plan's time at target_partitions=4 and 4.1x at 8, because all that grouping runs in one partition on one thread.

This doesn't need to block the PR. It only applies with preserve_file_partitions enabled, sorted files gain up to 5x, and the two-argument call, which this PR doesn't change, shows the same ratio (4.15x). It's fine to handle in a follow-up: could you open an issue for taking row-count skew into account when skipping the shuffle?

New plan time ÷ shuffle plan time (16M rows, 4 files, 9 rounds, medians; below 1 means the new plan is faster)
Input 3-arg, target_partitions=8 3-arg, target_partitions=4 2-arg, target_partitions=8
Sorted, mostly unique groups 0.21 0.29 0.20
Sorted, low cardinality 0.60 0.87 0.51
Balanced, low cardinality 1.37 0.95 1.46
Balanced, mostly unique groups 1.10 0.93 1.13
97% skew, low cardinality 3.07 1.03 3.03
97% skew, mostly unique groups 4.11 2.35 4.15

Same binary for both plans, using a wrapper UDF that keeps the default-deny locality hook, on a busy laptop. With round-robin repartitioning off at target_partitions=8, balanced low-cardinality is 1.00, low-cardinality skew is 1.04 and mostly-unique skew is 2.29. At default config the plan doesn't change.

@alamb
alamb added this pull request to the merge queue Nov 9, 2026
@alamb

alamb commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Thanks everyone

@benbellick

Copy link
Copy Markdown
Contributor Author

Thanks for benchmarking this @jayzhan211! Opened #27268 to track the follow-up.

Merged via the queue into apache:main with commit 14b3edd Nov 9, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

functions Changes to functions implementation physical-expr Changes to the physical-expr crates sqllogictest SQL Logic Tests (.slt) v57.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support range-key locality analysis for date_bin with a literal origin

4 participants