neilconway opened a new pull request, #11187:
URL: https://github.com/apache/arrow-rs/pull/11187
# Which issue does this PR close?
- N/A
# Rationale for this change
`date_part` is implemented by converting the timestamp to a Chrono value and
then extracting the requested date/time component using Chrono. For timestamp
values without a timestamp, we can often do better: "hour" through "nanosecond"
values can be extracted by doing arithmetic directly on the timestamp value,
without needing to consider the calendar date represented by the timestamp.
This is substantially faster than going through Chrono.
This is partly motivated by improving the performance of `date_part` and
`extract` in DataFusion. For example, ClickBench Q18 improves by about 2% using
this optimization.
Benchmarks: (ARM64, elapsed times in microseconds)
- timestamp_s/Hour/no_nulls: 33.964 → 5.903, −82.6%
- timestamp_s/Hour/mixed_nulls: 31.586 → 5.909, −81.3%
- timestamp_s/Minute/no_nulls: 37.616 → 7.172, −80.9%
- timestamp_s/Minute/mixed_nulls: 33.373 → 7.153, −78.6%
- timestamp_s/Second/no_nulls: 35.562 → 2.568, −92.8%
- timestamp_s/Second/mixed_nulls: 32.921 → 2.581, −92.2%
- timestamp_s/Millisecond/no_nulls: 0.344 → 0.353, +2.7%
- timestamp_s/Millisecond/mixed_nulls: 0.342 → 0.354, +3.4%
- timestamp_s/Microsecond/no_nulls: 0.339 → 0.344, +1.6%
- timestamp_s/Microsecond/mixed_nulls: 0.345 → 0.346, +0.4%
- timestamp_s/Nanosecond/no_nulls: 0.348 → 0.349, +0.2%
- timestamp_s/Nanosecond/mixed_nulls: 0.351 → 0.350, −0.3%
- timestamp_s/Minute/timezone_control: 60.107 → 60.102, 0.0%
- timestamp_s/Nanosecond/timezone_control: 0.344 → 0.346, +0.6%
- timestamp_s/Year/control: 32.778 → 33.179, +1.2%
- timestamp_ms/Hour/no_nulls: 45.956 → 5.911, −87.1%
- timestamp_ms/Hour/mixed_nulls: 40.266 → 5.919, −85.3%
- timestamp_ms/Minute/no_nulls: 49.837 → 6.305, −87.3%
- timestamp_ms/Minute/mixed_nulls: 41.962 → 6.265, −85.1%
- timestamp_ms/Second/no_nulls: 48.070 → 6.271, −87.0%
- timestamp_ms/Second/mixed_nulls: 41.210 → 6.302, −84.7%
- timestamp_ms/Millisecond/no_nulls: 45.229 → 2.333, −94.8%
- timestamp_ms/Millisecond/mixed_nulls: 39.643 → 2.345, −94.1%
- timestamp_ms/Microsecond/no_nulls: 45.364 → 2.490, −94.5%
- timestamp_ms/Microsecond/mixed_nulls: 40.163 → 2.492, −93.8%
- timestamp_ms/Nanosecond/no_nulls: 43.847 → 2.390, −94.5%
- timestamp_ms/Nanosecond/mixed_nulls: 39.255 → 2.394, −93.9%
- timestamp_ms/Minute/timezone_control: 74.756 → 74.833, +0.1%
- timestamp_ms/Nanosecond/timezone_control: 67.016 → 66.269, −1.1%
- timestamp_ms/Year/control: 45.080 → 45.166, +0.2%
- timestamp_us/Hour/no_nulls: 41.860 → 6.539, −84.4%
- timestamp_us/Hour/mixed_nulls: 38.822 → 6.408, −83.5%
- timestamp_us/Minute/no_nulls: 45.357 → 6.853, −84.9%
- timestamp_us/Minute/mixed_nulls: 40.589 → 6.743, −83.4%
- timestamp_us/Second/no_nulls: 42.589 → 6.246, −85.3%
- timestamp_us/Second/mixed_nulls: 39.346 → 6.205, −84.2%
- timestamp_us/Millisecond/no_nulls: 39.906 → 2.650, −93.4%
- timestamp_us/Millisecond/mixed_nulls: 38.902 → 2.631, −93.2%
- timestamp_us/Microsecond/no_nulls: 39.104 → 2.324, −94.1%
- timestamp_us/Microsecond/mixed_nulls: 38.804 → 2.329, −94.0%
- timestamp_us/Nanosecond/no_nulls: 38.297 → 2.380, −93.8%
- timestamp_us/Nanosecond/mixed_nulls: 37.745 → 2.392, −93.7%
- timestamp_us/Minute/timezone_control: 67.390 → 65.911, −2.2%
- timestamp_us/Nanosecond/timezone_control: 60.115 → 59.787, −0.5%
- timestamp_us/Year/control: 38.823 → 38.556, −0.7%
- timestamp_ns/Hour/no_nulls: 39.858 → 3.565, −91.1%
- timestamp_ns/Hour/mixed_nulls: 38.831 → 3.578, −90.8%
- timestamp_ns/Minute/no_nulls: 43.810 → 3.411, −92.2%
- timestamp_ns/Minute/mixed_nulls: 40.649 → 3.418, −91.6%
- timestamp_ns/Second/no_nulls: 42.057 → 6.246, −85.1%
- timestamp_ns/Second/mixed_nulls: 40.125 → 6.280, −84.3%
- timestamp_ns/Millisecond/no_nulls: 39.049 → 2.645, −93.2%
- timestamp_ns/Millisecond/mixed_nulls: 38.840 → 2.650, −93.2%
- timestamp_ns/Microsecond/no_nulls: 39.130 → 2.660, −93.2%
- timestamp_ns/Microsecond/mixed_nulls: 38.776 → 2.652, −93.2%
- timestamp_ns/Nanosecond/no_nulls: 38.303 → 2.326, −93.9%
- timestamp_ns/Nanosecond/mixed_nulls: 37.715 → 2.323, −93.8%
- timestamp_ns/Minute/timezone_control: 67.940 → 67.854, −0.1%
- timestamp_ns/Nanosecond/timezone_control: 61.504 → 60.833, −1.1%
- timestamp_ns/Year/control: 39.344 → 39.668, +0.8%
# What changes are included in this PR?
* Optimize `date_part` as described above
* Add unit tests
* Add benchmark for `date_part`
# Are these changes tested?
Existing tests pass. Two new tests were added: one checks the consistency of
this code path with the results produced by Chrono; the second checks the
results of this code path for extreme values (outside of Chrono's supported
calendar range).
# Are there any user-facing changes?
There is one user-visible behavior change. Chrono has a limited calendar
range (roughly +/- 262,000 years). Calling `date_part` on a timestamp outside
that range returned null. In this implementation, `date_part` will succeed for
the entire range of timestamp values. The returned value is correct, but this
behavior is slightly inconsistent with `date_part` for units that are still
implemented via Chrono, and for timestamp values with time zones.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]