Skip to content

Performance improvements#710

Merged
joe-clickhouse merged 39 commits intomainfrom
joe/perf-work
May 5, 2026
Merged

Performance improvements#710
joe-clickhouse merged 39 commits intomainfrom
joe/perf-work

Conversation

@joe-clickhouse
Copy link
Copy Markdown
Contributor

@joe-clickhouse joe-clickhouse commented Apr 15, 2026

Summary

  • Optimized DateTime and DateTime64 native read hot paths, especially for naive UTC and UTC-equivalent timezones, by moving more conversion work onto direct epoch-arithmetic paths and dedicated Cython helpers.
  • Added a dedicated Cython DateTime64 naive-UTC decode loop and routed UTC-equivalent timezone reads through the same Cython C-API construction path used for naive UTC.
  • Cython DateTime and DateTime64 reads now construct datetime objects directly via the CPython datetime C API, bypassing the intermediate component tuple and the Python-level datetime(...) constructor.
  • Fixed Cython DateTime conversion bugs and a pre-existing leap-year bug in the epoch decoder where centuries divisible by 400 (2400, 2800, 3200, ...) were treated as non-leap. Expanded epoch/date arithmetic test coverage.
  • Optimized fixed-width numeric INSERT serialization by routing native writes through a shared write_native_col helper.
  • Added a fast memcpy path for compatible 1-D C-contiguous NumPy arrays in the Cython native write path.
  • Optimized Map INSERT serialization with a shared build_map_columns helper and a faster Cython implementation for flattening keys/values plus offsets.
  • Reduced Map read materialization overhead by avoiding an intermediate pair-tuple allocation.
  • Optimized Decimal and BigDecimal reads by replacing per-row string construction with direct Decimal(int).scaleb(-scale).

Checklist

Delete items not relevant to your PR:

  • Unit and integration tests covering the common scenarios were added
  • A human-readable description of the changes was provided to include in CHANGELOG

@genzgd
Copy link
Copy Markdown
Collaborator

genzgd commented Apr 16, 2026

I don't know if we can use this: https://www.benjoffe.com/fast-date-64, but I keeping meaning to take a look.

@joe-clickhouse
Copy link
Copy Markdown
Contributor Author

Thanks @genzgd! Great find. I'll definitely take a look.

@joe-clickhouse joe-clickhouse marked this pull request as ready for review April 30, 2026 19:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR focuses on speeding up hot-path native reads/writes (especially temporal types and Map/numeric inserts) by shifting more work into Cython and using direct epoch arithmetic and buffer-level fast paths, while also fixing a leap-year bug in epoch decoding.

Changes:

  • Optimizes DateTime/DateTime64 decoding (naive UTC + UTC-equivalent tz) via epoch arithmetic and CPython datetime C-API construction, adding supporting helpers and tests.
  • Adds faster native write helpers (write_native_col, build_map_columns) including a NumPy memcpy fast path for compatible arrays.
  • Reduces Map read/write materialization overhead and improves Decimal/BigDecimal read performance by avoiding per-row string building.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/unit_tests/test_driver/test_epoch_arithmetic.py Adds unit tests for epoch arithmetic helpers and UTC-equivalent timezone helpers.
clickhouse_connect/driverc/dataconv.pyx Adds epoch-to-datetime arithmetic helpers, DateTime64 decode loops, NumPy memcpy native writes, and Map flattening helper; fixes leap-year logic.
clickhouse_connect/driverc/buffer.pyx Optimizes varint string-length parsing and adds a UTF-8 decode fast path in string reads.
clickhouse_connect/driver/tzutil.py Reworks utcfromtimestamp and adds arithmetic-based helpers for UTC-equivalent tz-aware datetimes and explicit microseconds.
clickhouse_connect/driver/dataconv.py Routes UTC-equivalent timezone reads through new arithmetic helper and adds pure-Python fallbacks for new C helpers.
clickhouse_connect/datatypes/temporal.py Routes DateTime64 reads through shared conversion helpers (UTC-equivalent vs non-UTC).
clickhouse_connect/datatypes/numeric.py Routes native fixed-width numeric inserts through write_native_col and optimizes Decimal/BigDecimal reads.
clickhouse_connect/datatypes/container.py Uses new build_map_columns helper and reduces Map read allocations.
CHANGELOG.md Documents the performance improvements and bug fix in UNRELEASED notes.

Comment thread clickhouse_connect/driverc/buffer.pyx Outdated
Comment thread clickhouse_connect/driverc/buffer.pyx Outdated
Comment thread clickhouse_connect/driver/tzutil.py Outdated
Comment thread tests/unit_tests/test_driver/test_epoch_arithmetic.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Comment thread tests/unit_tests/test_driver/test_epoch_arithmetic.py
Comment thread clickhouse_connect/driver/tzutil.py Outdated
Comment thread clickhouse_connect/datatypes/container.py
Comment thread clickhouse_connect/driverc/dataconv.pyx
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread clickhouse_connect/driverc/dataconv.pyx
Comment thread clickhouse_connect/driverc/dataconv.pyx
@joe-clickhouse
Copy link
Copy Markdown
Contributor Author

Also, I've looked into the https://www.benjoffe.com/fast-date-64 stuff and it's super impressive. In the clickhouse-connect code though, after the current improvements in the branch, profiling shows the dt64 read hot path bottleneck is pretty much entirely now in the datetime_new pyobject construction. Will definitely keep this around for future ref though. Thanks!

@joe-clickhouse joe-clickhouse merged commit 39ca7ed into main May 5, 2026
37 checks passed
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.

3 participants