Altinity Stable® Build for ClickHouse® 26.3

Here are the detailed release notes for version 26.3.

Release history

Version 26.3.16.10001 is the latest release. We recommend that you use this version. But read the detailed release notes and upgrade instructions for version 26.3 first. Once you’ve done that, review the details for each release for known issues and changes between the Altinity Stable Build and the upstream release.

Version Release date Details Docker images
26.3.16.10001 2026-07-03 CI report | Release page | Install guide AMD64 and Aarch64

Builds are available for both AMD64 and Aarch64 from builds.altinity.cloud as either .deb, .rpm, or .tgz.

Finally, check the Altinity ClickHouse® Upgrade E-book, which provides guidelines for upgrading ClickHouse databases.

Major new features in 26.3 since the previous Altinity Stable release 25.8

Everything new since the 25.8 baseline, consolidated across releases 25.9 through 26.3.

Across ClickHouse 25.9 → 26.3 there were 154 new features, 608 improvements, 160 performance enhancements 75 backward-incompatible changes, and 41 known issues. (1872 distinct changes deduped from 2250 changelog entries.) Because the differences for this release are substantial, we’ve broken them into sections:

Highlights

  • Column Statistics & Text Index — Automatic column statistics (auto_statistics_types) and scalable full‑text indexing (v3) reach production, dramatically accelerating analytics on semi‑structured and text data (25.10/25.12)
  • QBit Vector Data Type — Bit‑sliced vector storage plus approximate L2 distance enable high‑speed, tunable‑accuracy vector search inside ClickHouse (25.10)
  • Geometry Type & Geospatial Functions — A native Geometry type with WKB/WKT I/O and area/perimeter functions brings first‑class geospatial support (25.11/25.12)
  • Data Lake Integration — Direct query of Apache Paimon tables, Microsoft OneLake catalogs, and Google BigLake catalogs; Iceberg/Delta Lake metadata logging and expire_snapshots (25.10–26.2)
  • Async Inserts & Deduplication Defaults – Async inserts and unified dedup are now enabled by default, reducing part count and improving write throughput (26.2/26.3)
  • Fractional LIMIT/OFFSETLIMIT 0.25 and negative LIMIT/OFFSET provide flexible row‑selection without subqueries (25.11)
  • Polyglot SQL Transpiler – Write queries in 30+ SQL dialects (e.g. Snowflake, MySQL) and have them automatically translated to ClickHouse (26.3)
  • Nullable(Tuple) & Materialized CTEs – Experimental Nullable(Tuple) and materialized CTEs expand SQL expressiveness for complex workflows (26.1/26.3)

Bottom line: Across 25.9–26.3 ClickHouse doubled down on zero‑effort performance (default async inserts, built‑in statistics, smarter parallel replicas) while adding high‑value new data types (QBit, Geometry, full‑text) and deepening data lake integration (Paimon, OneLake, BigLake). The result is a platform that requires less operator tuning, handles more workloads out‑of‑the‑box, and meets users where they are – in Snowflake, on object storage, or in geospatial analytics.

👆 Back to v26.3 versus 25.8 overview

⚠️ Require attention

The changes most likely to need operator action on upgrade. The full list of breaking changes is in the backward incompatible changes section below.

  • ALTER MODIFY COLUMN requires explicit DEFAULT when converting nullable to non-nullable (in 25.12) #5985
  • Escape filenames for Variant subcolumns in MergeTree (in 25.11) #69590
  • Schema inference respects metadata nullability by default (in 25.10) #71499
  • Infer PostgreSQL DATE columns as Date32 (in 26.2) #73084
  • Remove transposed_with_wide_view mode of metric_log (in 26.1) #78412
  • JSON type SKIP REGEXP uses partial match by default (in 26.1) #79250
  • Query cache ignores log_comment setting (in 25.10) #79878
  • Stop formatting operators as table functions in syntax output (in 25.10) #81601
  • Disallow empty column list in JOIN USING (in 26.1) #82502
  • Fix alias substitution in formatter, potentially breaking CREATE VIEW with IN (in 26.1) #82833
  • Introduce dedicated Geometry type with WKB/WKT I/O (in 25.11) #83344
  • Revert INSERT into ALIAS columns feature (in 26.1) #84154
  • Remove deprecated Object data type (in 25.11) #85718
  • Disable nonsensical binary operations with IPv4/IPv6 and non-integer types (in 25.9) #86336
  • Forbid Dynamic type in JOIN keys by default (in 25.10) #86358
  • Remove allow_dynamic_metadata_for_data_lakes setting (in 25.9) #86366
  • Rework inverted text index for scalability (backward incompatible) (in 25.9) #86485
  • Enable apply_row_policy_after_final by default (in 25.12, 26.2) #87303 #97402
  • Force storage_metadata_write_full_object_key on by default (in 25.10) #87335
  • Default deduplication window reduced from 1 week to 1 hour (in 25.10) #87414
  • Rename setting query_plan_use_new_logical_join_step to query_plan_use_logical_join_step (in 25.10) #87679
  • New tokenizer parameter syntax for text indexes (in 25.10) #87997
  • Rename searchAny/searchAll to hasAnyTokens/hasAllTokens (in 25.10) #88109
  • Remove cache_hits_threshold from filesystem cache (in 25.10) #88344
  • Refine min_free_disk settings: use unreserved space, skip system tables (in 25.10) #88468
  • Enable async replication for Keeper by default (in 25.10) #88515
  • Remove obsolete LIVE VIEW feature (in 25.11) #88706
  • Prohibit multiple plain-rewritable disks on shared object storage path (in 25.11) #89038
  • Fix fatal error in T64 codec for non-aligned data sizes (in 25.11) #89282
  • Enable with_size_stream serialization for String columns by default (in 25.11) #89329

👆 Back to v26.3 versus 25.8 overview

Backward incompatible changes

SQL / Main features

  • Forbid subqueries in table key expressions — Disallows subqueries in ORDER BY, PARTITION BY, PRIMARY KEY, SAMPLE BY, TTL, and index expressions, changing the error code from UNKNOWN_FUNCTION to BAD_ARGUMENTS. Prevents logical errors; users must rewrite queries that previously used subqueries in key expressions. (introduced in 26.2) #96847
  • Variant type throws on type mismatch instead of returning NULL — Changes Variant type operations (e.g., comparison) to throw an exception on type mismatch, replacing the previous silent NULL return. Catches type errors early and avoids silent data issues, but may break queries that relied on the old NULL behavior. (introduced in 26.2) #95811
  • Correct SHOW COLUMNS permission check for CREATE TABLE … AS … — Changes the permission check for CREATE TABLE ... AS ... queries from SHOW TABLES to SHOW COLUMNS, which is the correct grant for this type of permission check. Operators must update grants: users now require SHOW COLUMNS privilege instead of SHOW TABLES for these queries, breaking existing permissions. (introduced in 26.1) #94556

Functions

  • Rename searchAny/searchAll to hasAnyTokens/hasAllTokens — Renames the functions searchAny and searchAll to hasAnyTokens and hasAllTokens respectively, aligning their naming with the existing hasToken function. This is a breaking change; old function names will no longer work. Provides consistent naming for token search functions, but requires users to update queries that used the old names. (functions hasAnyTokens, hasAllTokens) (introduced in 25.10) #88109
    • e.g. SELECT hasAnyTokens(text, 'foo bar'); -- instead of searchAny(text, 'foo bar')

MergeTree-related

  • Inverted text index v3: part-wide format, requires rebuild — Rewrites the storage layout of the inverted text index to a part-wide format optimized for object storage, removes bloom filters, and improves merge performance. Existing indexes must be dropped and rebuilt after upgrade. Delivers faster reads from object storage and better merge performance, but requires manual index rebuild to avoid incompatibility. (settings enable_full_text_index) (introduced in 25.12) #91518
    • e.g. ALTER TABLE table DROP INDEX idx; ALTER TABLE table ADD INDEX idx (col) TYPE full_text;
  • Rework inverted text index for scalability (backward incompatible) — Rewrites the inverted text index from scratch to support datasets that do not fit into RAM, introducing new settings for Bloom filter usage and query plan direct reads. Existing inverted indexes must be rebuilt after upgrade; this change enables full-text search on very large datasets efficiently. (settings text_index_use_bloom_filter, query_plan_direct_read_from_text_index) (introduced in 25.9) #86485
  • Packed format for column statistics introduced — Changes the storage format of column statistics to a single packed file instead of multiple files. Improves storage efficiency and reduces file count, but requires a migration and is backward incompatible. (introduced in 26.2) #93414
  • Refactor do_not_merge_across_partitions_select_final; add automatic decision setting — Makes the setting explicit: do_not_merge=1 now unconditionally enables the optimization, while automatic decision is controlled by new setting enable_automatic_decision_for_merging_across_partitions_for_final (default enabled). Clarifies behavior and avoids confusion; operators must review their use of the setting after upgrade. (settings enable_automatic_decision_for_merging_across_partitions_for_final) (introduced in 26.2) #96110
    • e.g. SET do_not_merge_across_partitions_select_final = 1
  • Escape filenames for Variant subcolumns in MergeTree — Escapes filenames created for Variant type subcolumns in Wide data parts to handle special characters like backslashes in timezone names. This breaks compatibility with old tables using Variant/Dynamic/JSON types. Fixes storage of types with special symbols; requires migration or disabling the setting for existing tables. (settings escape_variant_subcolumn_filenames) (introduced in 25.11) #69590
  • Forbid empty ORDER BY keys in special MergeTree tables — Prevents creation of special MergeTree tables (e.g., ReplacingMergeTree, CollapsingMergeTree) with an empty ORDER BY key, as merge behavior is undefined. Override with allow_suspicious_primary_key setting. Eliminates merge errors and undefined behavior; forces users to define an explicit sorting key. (introduced in 25.12) #91569
    • e.g. CREATE TABLE ... ENGINE = ReplacingMergeTree ORDER BY () -- will fail unless allow_suspicious_primary_key=1
  • Fix projection recognition for multi-column sorting keys — Corrects metadata of normal projections so that multi-column sorting keys are properly recognized, enabling correct projection matching for query optimization. Ensures projections with complex sorting keys are used effectively, preventing missed optimization opportunities. (introduced in 26.3) #90429

Codecs / compression

  • Remove DEFLATE_QPL and ZSTD_QAT codecs — Removes the DEFLATE_QPL and ZSTD_QAT compression codecs (backed by Intel QPL/QAT libraries). Existing data using these codecs must be converted before upgrade. Users who have data compressed with these codecs will be unable to read it after upgrade unless they first convert it to a supported codec. (introduced in 26.1) #92150
  • Fix fatal error in T64 codec for non-aligned data sizes — Fixes a fatal error that occurred when compressing data with the T64 codec if the data size was not aligned to the element size. Eliminates crashes when using the T64 compression codec with certain data patterns, but may require upgrading compressed data. (introduced in 25.11) #89282

ObjectStore - S3/Azure/GCS

  • Add S3 schema validation — Adds validation of S3 schema configuration, ensuring that S3-related settings conform to expected structure. Prevents misconfigured S3 storage that could lead to errors or silent failures. (introduced in 26.2) #96089
  • Prohibit multiple plain-rewritable disks on shared object storage path — Adds a startup check that throws an error if two plain-rewritable disks have overlapping object storage prefixes with different metadata stores, preventing undefined behavior and potential data loss. Eliminates a dangerous configuration that could cause data corruption and loss when multiple plain-rewritable disks accidentally share the same object storage path. (introduced in 25.11) #89038

Datalakes & catalogs

  • Remove allow_dynamic_metadata_for_data_lakes setting — Deprecates the setting allow_dynamic_metadata_for_data_lakes; Iceberg and DeltaLake tables now always fetch up-to-date schema before each query. Simplifies configuration and ensures schema freshness for data lake tables. (introduced in 25.9) #86366
    • e.g. system.delta_lake_metadata_log
  • New setting makes DataLakeCatalog throw on metadata access errors by default — Adds setting database_datalake_require_metadata_access (default true) that causes DataLakeCatalog to throw an error when it cannot access table metadata, instead of silently ignoring the error. This is backward-incompatible for users relying on the old behavior. Operators must set database_datalake_require_metadata_access to false if they previously relied on ignoring metadata access errors, otherwise queries will fail. (settings database_datalake_require_metadata_access) (introduced in 26.1) #93606
    • e.g. SET database_datalake_require_metadata_access = 0;

Integrations

  • Capture UDF stderr in query logs for debugging — Changes UDF stderr handling: stderr_reaction defaults to ’throw’, and captures full stderr (up to 1MB) before throwing, exposing Python tracebacks in system.query_log.exception. Enables effective debugging of UDF failures by making error messages visible in query logs instead of only files. (introduced in 26.1) #92209
  • Fix Kafka SASL settings precedence to respect table-level config — Table-level SASL settings specified in CREATE TABLE queries now correctly override consumer/producer-specific settings from configuration files. Ensures explicit per-table security settings take effect as intended, improving security consistency. (introduced in 25.11) #89401
    • e.g. CREATE TABLE my_table (key UInt32, value String) ENGINE = Kafka() SETTINGS kafka_sasl_username = 'user', kafka_sasl_password = 'pass'

S3Queue

  • S3Queue metadata cache now size-limited; system tables renamed — Introduces a size-limited in-memory cache for S3Queue/AzureQueue metadata with configurable byte and element limits, and renames system tables from system.s3queue to system.s3queue_metadata_cache (and similarly azure_queue). Prevents unbounded memory growth; operators must update queries that reference the old system table names. (settings metadata_cache_size_bytes, metadata_cache_size_elements) (introduced in 26.1) #96828
    • e.g. SELECT * FROM system.s3queue_metadata_cache
  • Limit S3Queue/AzureQueue in-memory metadata; rename system tables — Introduces a size-limited in-memory cache for S3Queue/AzureQueue metadata (configurable via metadata_cache_size_bytes and metadata_cache_size_elements) and renames system tables from system.s3queue to system.s3queue_metadata_cache and system.azure_queue to system.azure_queue_metadata_cache. Prevents unbounded memory growth and improves resource management; operators must update queries referencing the old system table names. (settings metadata_cache_size_bytes, metadata_cache_size_elements) (introduced in 26.2) #95809

Formats

  • Schema inference respects metadata nullability by default — Changes the default of schema_inference_make_columns_nullable to 3, which respects nullability information from Parquet/ORC/Arrow metadata instead of making all columns nullable. Provides more accurate schema inference; may break queries that expected all columns to be nullable. (introduced in 25.10) #71499

Operations

  • Refine min_free_disk settings: use unreserved space, skip system tables — Changes min_free_disk_bytes and min_free_disk_ratio to use unreserved disk space instead of available space, and excludes system tables from these checks. More accurate free space accounting prevents unnecessary insert rejections and ensures system logs remain operational. (introduced in 25.10) #88468

CLI

  • Client returns non-zero exit code on receive_timeout — The clickhouse-client now exits with code 159 (TIMEOUT_EXCEEDED) instead of 0 when a query times out due to receive_timeout. Scripts and automation can now reliably detect timeout failures instead of mistaking them for success. (introduced in 25.12) #91432

Keeper

  • Enable async replication for Keeper by default — Enables async mode for Keeper’s internal replication by default, preserving the same behavior with potential performance improvements. Operators upgrading from versions older than 23.9 must follow a multi-step upgrade or temporarily disable async replication to avoid issues. (introduced in 25.10) #88515
    • e.g. Set keeper_server.coordination_settings.async_replication to 0 before update if needed.

Misc

  • Propagate serialization versions to nested types — Enables propagation of serialization versions like with_size_stream to nested types (Array, Map, Variant, JSON), controlled by new MergeTree setting propagate_types_serialization_versions_to_nested_types enabled by default. New parts cannot be read by older ClickHouse versions; upgrade safe but downgrade not. Ensures consistency of serialization across nested structures. (settings propagate_types_serialization_versions_to_nested_types) (introduced in 26.3) #94859
  • Introduce dedicated Geometry type with WKB/WKT I/O — Adds a new Geometry data type that replaces the previous String alias. Supports reading WKB and WKT formats via readWkb and readWkt functions. Enables type-safe geospatial data storage and processing, but existing columns using Geometry as String will need migration. (functions readWkt, readWkb) (introduced in 25.11) #83344
    • e.g. readWkt, readWkb functions
  • Enable async inserts by default — Changes the default value of async_insert to true, so small inserts are batched automatically. The old behavior can be restored via compatibility setting. Reduces number of parts and improves write throughput, but may change behavior for applications expecting synchronous inserts. (introduced in 26.2) #98752
    • e.g. SET compatibility = '26.1'; -- to disable async_insert by default
  • Enable proper MySQL data type mapping by default — Changed the default value of mysql_datatypes_support_level from empty to decimal,datetime64,date2Date32, enabling correct mapping of MySQL DATE to Date32, DECIMAL to Decimal, and DATETIME/TIMESTAMP with precision to DateTime64. Prevents data corruption for historical dates (pre-1970) and improves MySQL compatibility out of the box. (introduced in 26.3) #97716
    • e.g. With the new default, MySQL DATEcolumns are mapped toDate32instead ofDate, avoiding range issues.
  • Async inserts enabled by default — Changed the default value of async_insert from false to true, so small INSERT queries are batched by default. Old behavior can be restored via compatibility settings or by explicitly setting async_insert = 0. Operators must verify their workloads tolerate batching or disable async inserts to preserve synchronous insertion behavior. (introduced in 26.3) #97590
    • e.g. SET async_insert = 0; SET compatibility = '25.12';
  • Enable deduplication for all inserts by default (breaking change) — Changes the default value of deduplicate_insert from ‘backward_compatible_choice’ to ’enable’, and deduplicate_blocks_in_dependent_materialized_views from false to true, enabling deduplication for all inserts (sync, async, materialized views) by default. Ensures consistent deduplication behavior across all insert methods, but users who relied on the old behavior must explicitly set these settings to maintain previous semantics. (introduced in 26.2) #95970
    • e.g. To keep old behavior: SET deduplicate_insert='backward_compatible_choice'; SET deduplicate_blocks_in_dependent_materialized_views=0;
  • Enable advanced shared data for JSON by default (downgrade incompatible) — Enables advanced shared data serialization for JSON and Dynamic types by default, changing the defaults of MergeTree settings. Downgrade to versions before 25.8 becomes impossible because older versions cannot read new data parts. Improves storage efficiency for JSON columns, but requires careful upgrade planning to avoid incompatibility with older versions. (introduced in 25.12) #93224
    • e.g. SET compatibility = '25.8' before upgrading to ensure safe operation.
  • Enable advanced shared data for JSON types by default (breaking) — Enables new advanced shared data serialization for JSON and Dynamic types by default, changing several MergeTree settings. Data written with this format is not readable by versions prior to 25.8. Improves storage efficiency for JSON columns, but prevents downgrade to versions older than 25.8. Operators can set compatibility to the previous version or explicitly set dynamic_serialization_version=‘v2’, object_serialization_version=‘v2’ before upgrade. (introduced in 26.1) #92511
    • e.g. SET compatibility = '25.7' -- before upgrade to keep old format
  • Remove Lazy database engine — The Lazy database engine is removed and no longer available; all uses must be migrated to another engine. Users with Lazy engine databases must recreate or convert them before upgrading, as they will no longer function. (introduced in 26.1) #91231
  • Escape index filenames to prevent broken parts — Introduces proper escaping of non-ASCII characters in index filenames to prevent broken parts, with a backward-compatible setting to load old indices. Prevents data corruption for indices with non-ASCII names; existing indices created by previous versions must be loaded with escape_index_filenames set to false. (settings escape_index_filenames) (introduced in 26.1) #94079
    • e.g. SETTINGS escape_index_filenames = false
  • Introduce enable_positional_arguments_for_projections setting — Marks disabled positional arguments in projections as a backward-incompatible change and introduces the enable_positional_arguments_for_projections setting to allow a safe upgrade for clusters with positional arguments in projections. Operators must enable this setting before upgrade if their projections use positional arguments, otherwise those projections will become invalid. (settings enable_positional_arguments_for_projections) (introduced in 25.10, 25.11) #92119 #92120
    • e.g. SET enable_positional_arguments_for_projections = 1;
  • Mark disabled positional arguments in projections as backward-incompatible change — Introduces the enable_positional_arguments_for_projections setting to safely manage the disabling of positional arguments in projections, allowing a controlled upgrade process. Prevents unexpected query behavior changes during cluster upgrades when projections contain positional arguments. (settings enable_positional_arguments_for_projections) (introduced in 25.12) #92007
    • e.g. SET enable_positional_arguments_for_projections = 1;
  • Rename setting query_plan_use_new_logical_join_step to query_plan_use_logical_join_step — Renames the setting query_plan_use_new_logical_join_step to query_plan_use_logical_join_step with a backward-compatible alias; the old name is deprecated. Users need to update configurations to use the new setting name; the old name still works but will be removed in future. (settings query_plan_use_logical_join_step) (introduced in 25.10) #87679
    • e.g. SET query_plan_use_logical_join_step = 1
  • Forbid Dynamic type in JOIN keys by default — Disables using Dynamic type in JOIN keys due to potential unexpected comparison results; a new setting allow_dynamic_type_in_join_keys (default false) is added for compatibility. Prevents silent wrong results in queries with Dynamic type joins; users must cast Dynamic columns to required type. (settings allow_dynamic_type_in_join_keys) (introduced in 25.10) #86358
    • e.g. SET allow_dynamic_type_in_join_keys = 1;
  • HTTP response exception tagging with new setting — Adds exception tagging in HTTP results for reliable client parsing, controlled by new setting http_write_exception_in_output_format (disabled by default). Clients can now parse exceptions more reliably, but the change is opt‑in and may affect existing integrations that rely on the previous format. (settings http_write_exception_in_output_format) (introduced in 25.11) #75175
    • e.g. SET http_write_exception_in_output_format = 1
  • Remove experimental detectProgrammingLanguage function — Removes the previously experimental detectProgrammingLanguage function. Users relying on this function must remove references from their queries; this change reduces maintenance burden. (introduced in 26.3) #99567
  • mergeTreeAnalyzeIndexes functions now accept array of part names instead of regexp — Changes the internal table functions mergeTreeAnalyzeIndexes and mergeTreeAnalyzeIndexesUUID to accept an array of part names instead of a regexp string, making them faster and more robust for large numbers of parts. This is a backward-incompatible change for users of these experimental functions; queries must be updated to pass an array of part names instead of a regexp. (introduced in 26.3) #98474
    • e.g. SELECT * FROM mergeTreeAnalyzeIndexes(array('part1', 'part2'))
  • Fix NOT operator precedence to match SQL standard — Changed NOT operator precedence so it binds looser than IS NULL, BETWEEN, LIKE, and arithmetic operators. Previously NOT (x) IS NULL was parsed as (NOT x) IS NULL; it is now parsed as NOT (x IS NULL). Queries relying on the old non-standard precedence may produce different results after upgrading; review queries using NOT with operators like IS NULL or BETWEEN. (introduced in 26.3) #97680
    • e.g. Old behavior: NOT x IS NULL(NOT x) IS NULL. New behavior: NOT x IS NULLNOT (x IS NULL).
  • Enable apply_row_policy_after_final by default — Enables the setting apply_row_policy_after_final by default, causing row policies to always be applied after FINAL, restoring previous behavior and fixing a regression where PREWHERE did not work with row policies. Changes behavior for optimize_move_to_prewhere_if_final=1; operators must use apply_row_policy_after_final instead to control row policy evaluation order. (introduced in 25.12, 26.2) #87303 #97402
  • Hash long skip index filenames to prevent file name too long errors — Hashes long skip index filenames when they exceed max_file_name_length, preventing ‘File name too long’ errors and making indices with long names work correctly. This is backward compatible (new servers read old parts), but downgrading may cause long-named indices to be ignored. Ensures skip indices with long names are properly handled and not ignored during downgrades. (introduced in 26.3) #97128
  • Remove experimental hypothesis skip index type — Removes the hypothesis skip index type entirely. Creating tables with INDEX … TYPE hypothesis will now produce an error. Existing tables using this index type must be altered or dropped before upgrading to avoid errors. (introduced in 26.3) #96874
    • e.g. ALTER TABLE table DROP INDEX index_name -- to remove hypothesis index before upgrade
  • Variant type throws on type mismatch instead of NULL — Changes Variant type operations (e.g., comparison) to throw an exception on type mismatch instead of returning NULL, fixing a logical error. Existing queries that rely on NULL returns from type mismatches will now fail; users must adjust queries or data. (introduced in 26.1) #96147
  • joinGet/joinGetOrNull now enforce SELECT privilege on Join table — joinGet and joinGetOrNull functions now check that the user has SELECT privilege on the underlying Join table’s key and attribute columns; lack of privilege results in ACCESS_DENIED. Enhances security by enforcing access control on join table data, but may break existing workflows that rely on joinGet without explicit grants. (introduced in 26.1) #94307
    • e.g. GRANT SELECT(key_col, attr_col) ON db.join_table TO user
  • Move format settings to regular settings causing errors in table engine definitions — Changed several settings (exact_rows_before_limit, rows_before_aggregation, cross_to_inner_join_rewrite, regexp_dict_allow_hyperscan, regexp_dict_flag_case_insensitive, regexp_dict_flag_dotall, dictionary_use_async_executor) from format to regular settings. Specifying them in table engine definitions (e.g., Iceberg, Kafka) now throws an error instead of being ignored. Users with these settings in table engine definitions must remove them to avoid errors. (introduced in 26.1) #94106
  • Enable cpu_slot_preemption by default — Changes the default value of cpu_slot_preemption server setting from false to true, making CPU scheduling preemptive by default. Existing workloads may need adjustment; operators should review CPU scheduling behavior. (introduced in 26.1) #94060
    • e.g. SETTINGS cpu_slot_preemption = false
  • Revert INSERT into simple ALIAS columns due to format incompatibility — Reverts the ability to INSERT into simple ALIAS columns because the feature did not work with custom formats and was not guarded by a setting. Restores previous behavior – INSERTs into ALIAS columns are no longer allowed; users relying on this functionality must adjust their workflows. (introduced in 25.12) #93061
  • Fix bitShiftLeft and bitShiftRight to return zero when shifting by full bit width — Changes the behavior of bitShiftLeft and bitShiftRight functions to return zero or empty value when the shift amount equals the bit width of the type, instead of non-zero values. Corrects a semantic bug in bit shift operations, but may change results for existing queries relying on the old behavior. (introduced in 25.12) #91943
    • e.g. SELECT bitShiftLeft(1, 8) -- previously returned 256, now returns 0
  • Fix implicit indices metadata handling — Fixes multiple issues with implicit minmax indices created by settings. Implicit indices are no longer included in table metadata, which may cause metadata errors on older replicas during rolling upgrades. Prevents schema inconsistencies and potential errors when using implicit indices with ReplicatedMergeTree. (introduced in 25.12) #91429
  • Change default of check_query_single_value_result to false for detailed CHECK TABLE output — Changes the default value of setting check_query_single_value_result from true to false, so CHECK TABLE now returns detailed per-part results instead of a single aggregated 0/1. Provides more informative CHECK TABLE output by default, but may break scripts that parse the old format. (introduced in 25.12) #91009
    • e.g. CHECK TABLE table_name;
  • Statistics format change for Nullable columns requires regeneration — Fixes statistics format incompatibility when altering columns to Nullable(String); old statistics cause crashes. Operators must run ALTER TABLE … MATERIALIZE STATISTICS ALL to regenerate. Failing to regenerate statistics may lead to server crashes after upgrade. (introduced in 25.12) #90311
    • e.g. ALTER TABLE table_name MATERIALIZE STATISTICS ALL
  • Remove settings allowing non-comparable types in ORDER BY and comparisons — Removes the settings allow_not_comparable_types_in_order_by and allow_not_comparable_types_in_comparison_functions, which allowed using non-comparable types like QBit in orderings and comparisons, causing potential logical errors. Prevents silent logical errors by enforcing type safety in ordering and comparison operations. (introduced in 25.12) #90028
  • Ngram tokenizer no longer returns short ngrams; empty search returns no rows — Changes the ngram tokenizer to not return ngrams shorter than the configured length N, and makes text search return no rows when search tokens are empty. Ensures consistent behavior, but may break existing queries that relied on the old (incorrect) tokenizer output or empty search token handling. (introduced in 25.12) #89757
  • Prohibit multiple plain-rewritable disks with shared object storage path — Adds a startup check that prevents creating multiple plain-rewritable disks on top of the same object storage path, as colliding metadata transactions can cause undefined behavior and data loss. Eliminates the risk of data corruption when multiple plain-rewritable disks mistakenly share the same object storage prefix. (introduced in 25.10) #89358
  • Enable with_size_stream serialization for String columns by default — Enables the new with_size_stream serialization format for String columns in MergeTree tables, which is incompatible with versions before 25.10. Improves storage efficiency but prevents downgrade to versions before 25.10 unless legacy settings are configured. (introduced in 25.11) #89329
    • e.g. To preserve downgrade capability, set serialization_info_version=‘basic’andstring_serialization_version=‘single_stream’ in the merge_tree configuration.
  • Remove obsolete LIVE VIEW feature — Removed the deprecated LIVE VIEW feature entirely; existing LIVE VIEW tables must be dropped before upgrading to this version. Upgrading will fail if any LIVE VIEW tables exist, so users must migrate away beforehand. (introduced in 25.11) #88706
  • Remove cache_hits_threshold from filesystem cache — Removes the cache_hits_threshold feature from the filesystem cache. This setting, which deferred caching until a certain number of hits, is now redundant due to the SLRU cache policy. This is a backward incompatible change; any configurations using cache_hits_threshold will be ignored and caching behavior may change. (introduced in 25.10) #88344
  • New tokenizer parameter syntax for text indexes — Changes tokenizer parameter syntax and names: old names (default, split, ngram, no_op) are replaced with new ones (splitByNonAlpha, splitByString, ngrams, array) and parameters use function-style notation. Existing DDLs using old tokenizer names will fail; must be updated to new syntax. (introduced in 25.10) #87997
    • e.g. ALTER TABLE ... ADD INDEX my_idx TYPE full_text(ngrams(2))
  • Default deduplication window reduced from 1 week to 1 hour — Decreases the default value of replicated_deduplication_window_seconds from 604800 to 3600 to reduce ZooKeeper znode storage. Reduces ZooKeeper storage for low insertion rates; may cause duplicate inserts if replication delay exceeds one hour. (introduced in 25.10) #87414
    • e.g. SET replicated_deduplication_window_seconds = 604800;
  • Force storage_metadata_write_full_object_key on by default — Enables the server setting storage_metadata_write_full_object_key by default and makes it immutable; metadata writes always use the full object key format. Simplifies metadata handling but restricts downgrade compatibility to 25.x releases only; downgrading to earlier versions is not supported. (introduced in 25.10) #87335
  • Disable nonsensical binary operations with IPv4/IPv6 and non-integer types — Disables plus/minus arithmetic operations between IPv4/IPv6 values and non-integer types (e.g., Float, DateTime), which previously caused logical errors or crashes. Prevents incorrect queries and potential crashes; existing queries or views using such operations will fail and require adjustment. (introduced in 25.9) #86336
  • Remove deprecated Object data type — Removes the deprecated Object data type used for storing semi-structured JSON-like data. Tables with Object columns must be migrated before upgrading. Upgrade will fail if any table still uses the Object type; requires pre-upgrade migration to avoid data loss. (introduced in 25.11) #85718
    • e.g. ALTER TABLE table MODIFY COLUMN col JSON
  • Revert INSERT into ALIAS columns feature — Reverts the previous change that allowed INSERT into simple ALIAS columns, as it did not work with custom formats and was not guarded by a setting. Users who relied on this feature must adjust their queries; the feature is removed. (introduced in 26.1) #84154
  • Fix alias substitution in formatter, potentially breaking CREATE VIEW with IN — Fixes inconsistent formatting caused by incorrect alias substitution; some CREATE VIEW queries with IN referencing an alias may fail when the analyzer is disabled. Operators using the old analyzer (disabled) may need to enable the analyzer to prevent incompatibility. (introduced in 26.1) #82833
  • Disallow empty column list in JOIN USING — Makes USING() with no columns a syntax error instead of causing runtime or logical errors. Prevents confusing crashes and logical errors, enforcing correct SQL syntax. (introduced in 26.1) #82502
  • Stop formatting operators as table functions in syntax output — Changes formatting: EXPLAIN SYNTAX no longer formats operators as if they were table functions, and clickhouse-format/formatQuery will not convert functional syntax to operator syntax. Queries that relied on the old formatting may produce different output; EXPLAIN SYNTAX now better reflects actual syntax. (introduced in 25.10) #81601
  • Query cache ignores log_comment setting — Made the query result cache ignore the log_comment setting so that queries differing only in log_comment hit the cache. Improves cache efficiency but breaks users who used log_comment for cache segmentation; they should switch to query_cache_tag. (introduced in 25.10) #79878
  • JSON type SKIP REGEXP uses partial match by default — Changed the default matching behavior of SKIP REGEXP in JSON type to use partial match instead of full match. Queries relying on full match may produce different results on upgrade. (introduced in 26.1) #79250
  • Remove transposed_with_wide_view mode of metric_log — Removes the transposed_with_wide_view mode for system.metric_log because it was unusable due to a bug. Defining this mode is no longer allowed. Users with custom metric_log configurations using this mode must remove it before upgrading to avoid errors; no data loss is expected. (introduced in 26.1) #78412
  • Infer PostgreSQL DATE columns as Date32 — DATE columns from PostgreSQL are now inferred as Date32 in ClickHouse instead of Date, and Date32 values can be inserted back to PostgreSQL. Correctly handles dates outside the narrow Date range; existing tables relying on Date inference may break on upgrade. (introduced in 26.2) #73084
  • ALTER MODIFY COLUMN requires explicit DEFAULT when converting nullable to non-nullable — When converting a Nullable column to a non-nullable type, ALTER MODIFY COLUMN now requires an explicit DEFAULT expression; NULLs are replaced with the default instead of causing an error. Prevents stuck ALTERs and provides consistent behavior for nullable-to-nonnullable conversions. (introduced in 25.12) #5985
    • e.g. ALTER TABLE t MODIFY COLUMN x Int32 DEFAULT 0;

Misc

  • Propagate serialization versions to nested types — Enables propagation of serialization versions like with_size_stream to nested types (Array, Map, Variant, JSON), controlled by new MergeTree setting propagate_types_serialization_versions_to_nested_types enabled by default. New parts cannot be read by older ClickHouse versions; upgrade safe but downgrade not. Ensures consistency of serialization across nested structures. (settings propagate_types_serialization_versions_to_nested_types) (introduced in 26.3) #94859
  • Introduce dedicated Geometry type with WKB/WKT I/O — Adds a new Geometry data type that replaces the previous String alias. Supports reading WKB and WKT formats via readWkb and readWkt functions. Enables type-safe geospatial data storage and processing, but existing columns using Geometry as String will need migration. (functions readWkt, readWkb) (introduced in 25.11) #83344
    • e.g. readWkt, readWkb functions
  • Enable async inserts by default — Changes the default value of async_insert to true, so small inserts are batched automatically. The old behavior can be restored via compatibility setting. Reduces number of parts and improves write throughput, but may change behavior for applications expecting synchronous inserts. (introduced in 26.2) #98752
    • e.g. SET compatibility = '26.1'; -- to disable async_insert by default
  • Enable proper MySQL data type mapping by default — Changed the default value of mysql_datatypes_support_level from empty to decimal,datetime64,date2Date32, enabling correct mapping of MySQL DATE to Date32, DECIMAL to Decimal, and DATETIME/TIMESTAMP with precision to DateTime64. Prevents data corruption for historical dates (pre-1970) and improves MySQL compatibility out of the box. (introduced in 26.3) #97716
    • e.g. With the new default, MySQL DATEcolumns are mapped toDate32instead ofDate, avoiding range issues.
  • Async inserts enabled by default — Changed the default value of async_insert from false to true, so small INSERT queries are batched by default. Old behavior can be restored via compatibility settings or by explicitly setting async_insert = 0. Operators must verify their workloads tolerate batching or disable async inserts to preserve synchronous insertion behavior. (introduced in 26.3) #97590
    • e.g. SET async_insert = 0; SET compatibility = '25.12';
  • Enable deduplication for all inserts by default (breaking change) — Changes the default value of deduplicate_insert from ‘backward_compatible_choice’ to ’enable’, and deduplicate_blocks_in_dependent_materialized_views from false to true, enabling deduplication for all inserts (sync, async, materialized views) by default. Ensures consistent deduplication behavior across all insert methods, but users who relied on the old behavior must explicitly set these settings to maintain previous semantics. (introduced in 26.2) #95970
    • e.g. To keep old behavior: SET deduplicate_insert='backward_compatible_choice'; SET deduplicate_blocks_in_dependent_materialized_views=0;
  • Enable advanced shared data for JSON by default (downgrade incompatible) — Enables advanced shared data serialization for JSON and Dynamic types by default, changing the defaults of MergeTree settings. Downgrade to versions before 25.8 becomes impossible because older versions cannot read new data parts. Improves storage efficiency for JSON columns, but requires careful upgrade planning to avoid incompatibility with older versions. (introduced in 25.12) #93224
    • e.g. SET compatibility = '25.8' before upgrading to ensure safe operation.
  • Enable advanced shared data for JSON types by default (breaking) — Enables new advanced shared data serialization for JSON and Dynamic types by default, changing several MergeTree settings. Data written with this format is not readable by versions prior to 25.8. Improves storage efficiency for JSON columns, but prevents downgrade to versions older than 25.8. Operators can set compatibility to the previous version or explicitly set dynamic_serialization_version=‘v2’, object_serialization_version=‘v2’ before upgrade. (introduced in 26.1) #92511
    • e.g. SET compatibility = '25.7' -- before upgrade to keep old format
  • Remove Lazy database engine — The Lazy database engine is removed and no longer available; all uses must be migrated to another engine. Users with Lazy engine databases must recreate or convert them before upgrading, as they will no longer function. (introduced in 26.1) #91231
  • Escape index filenames to prevent broken parts — Introduces proper escaping of non-ASCII characters in index filenames to prevent broken parts, with a backward-compatible setting to load old indices. Prevents data corruption for indices with non-ASCII names; existing indices created by previous versions must be loaded with escape_index_filenames set to false. (settings escape_index_filenames) (introduced in 26.1) #94079
    • e.g. SETTINGS escape_index_filenames = false
  • Introduce enable_positional_arguments_for_projections setting — Marks disabled positional arguments in projections as a backward-incompatible change and introduces the enable_positional_arguments_for_projections setting to allow a safe upgrade for clusters with positional arguments in projections. Operators must enable this setting before upgrade if their projections use positional arguments, otherwise those projections will become invalid. (settings enable_positional_arguments_for_projections) (introduced in 25.10, 25.11) #92119 #92120
    • e.g. SET enable_positional_arguments_for_projections = 1;
  • Mark disabled positional arguments in projections as backward-incompatible change — Introduces the enable_positional_arguments_for_projections setting to safely manage the disabling of positional arguments in projections, allowing a controlled upgrade process. Prevents unexpected query behavior changes during cluster upgrades when projections contain positional arguments. (settings enable_positional_arguments_for_projections) (introduced in 25.12) #92007
    • e.g. SET enable_positional_arguments_for_projections = 1;
  • Rename setting query_plan_use_new_logical_join_step to query_plan_use_logical_join_step — Renames the setting query_plan_use_new_logical_join_step to query_plan_use_logical_join_step with a backward-compatible alias; the old name is deprecated. Users need to update configurations to use the new setting name; the old name still works but will be removed in future. (settings query_plan_use_logical_join_step) (introduced in 25.10) #87679
    • e.g. SET query_plan_use_logical_join_step = 1
  • Forbid Dynamic type in JOIN keys by default — Disables using Dynamic type in JOIN keys due to potential unexpected comparison results; a new setting allow_dynamic_type_in_join_keys (default false) is added for compatibility. Prevents silent wrong results in queries with Dynamic type joins; users must cast Dynamic columns to required type. (settings allow_dynamic_type_in_join_keys) (introduced in 25.10) #86358
    • e.g. SET allow_dynamic_type_in_join_keys = 1;
  • HTTP response exception tagging with new setting — Adds exception tagging in HTTP results for reliable client parsing, controlled by new setting http_write_exception_in_output_format (disabled by default). Clients can now parse exceptions more reliably, but the change is opt‑in and may affect existing integrations that rely on the previous format. (settings http_write_exception_in_output_format) (introduced in 25.11) #75175
    • e.g. SET http_write_exception_in_output_format = 1
  • Remove experimental detectProgrammingLanguage function — Removes the previously experimental detectProgrammingLanguage function. Users relying on this function must remove references from their queries; this change reduces maintenance burden. (introduced in 26.3) #99567
  • mergeTreeAnalyzeIndexes functions now accept array of part names instead of regexp — Changes the internal table functions mergeTreeAnalyzeIndexes and mergeTreeAnalyzeIndexesUUID to accept an array of part names instead of a regexp string, making them faster and more robust for large numbers of parts. This is a backward-incompatible change for users of these experimental functions; queries must be updated to pass an array of part names instead of a regexp. (introduced in 26.3) #98474
    • e.g. SELECT * FROM mergeTreeAnalyzeIndexes(array('part1', 'part2'))
  • Fix NOT operator precedence to match SQL standard — Changed NOT operator precedence so it binds looser than IS NULL, BETWEEN, LIKE, and arithmetic operators. Previously NOT (x) IS NULL was parsed as (NOT x) IS NULL; it is now parsed as NOT (x IS NULL). Queries relying on the old non-standard precedence may produce different results after upgrading; review queries using NOT with operators like IS NULL or BETWEEN. (introduced in 26.3) #97680
    • e.g. Old behavior: NOT x IS NULL(NOT x) IS NULL. New behavior: NOT x IS NULLNOT (x IS NULL).
  • Enable apply_row_policy_after_final by default — Enables the setting apply_row_policy_after_final by default, causing row policies to always be applied after FINAL, restoring previous behavior and fixing a regression where PREWHERE did not work with row policies. Changes behavior for optimize_move_to_prewhere_if_final=1; operators must use apply_row_policy_after_final instead to control row policy evaluation order. (introduced in 25.12, 26.2) #87303 #97402
  • Hash long skip index filenames to prevent file name too long errors — Hashes long skip index filenames when they exceed max_file_name_length, preventing ‘File name too long’ errors and making indices with long names work correctly. This is backward compatible (new servers read old parts), but downgrading may cause long-named indices to be ignored. Ensures skip indices with long names are properly handled and not ignored during downgrades. (introduced in 26.3) #97128
  • Remove experimental hypothesis skip index type — Removes the hypothesis skip index type entirely. Creating tables with INDEX … TYPE hypothesis will now produce an error. Existing tables using this index type must be altered or dropped before upgrading to avoid errors. (introduced in 26.3) #96874
    • e.g. ALTER TABLE table DROP INDEX index_name -- to remove hypothesis index before upgrade
  • Variant type throws on type mismatch instead of NULL — Changes Variant type operations (e.g., comparison) to throw an exception on type mismatch instead of returning NULL, fixing a logical error. Existing queries that rely on NULL returns from type mismatches will now fail; users must adjust queries or data. (introduced in 26.1) #96147
  • joinGet/joinGetOrNull now enforce SELECT privilege on Join table — joinGet and joinGetOrNull functions now check that the user has SELECT privilege on the underlying Join table’s key and attribute columns; lack of privilege results in ACCESS_DENIED. Enhances security by enforcing access control on join table data, but may break existing workflows that rely on joinGet without explicit grants. (introduced in 26.1) #94307
    • e.g. GRANT SELECT(key_col, attr_col) ON db.join_table TO user
  • Move format settings to regular settings causing errors in table engine definitions — Changed several settings (exact_rows_before_limit, rows_before_aggregation, cross_to_inner_join_rewrite, regexp_dict_allow_hyperscan, regexp_dict_flag_case_insensitive, regexp_dict_flag_dotall, dictionary_use_async_executor) from format to regular settings. Specifying them in table engine definitions (e.g., Iceberg, Kafka) now throws an error instead of being ignored. Users with these settings in table engine definitions must remove them to avoid errors. (introduced in 26.1) #94106
  • Enable cpu_slot_preemption by default — Changes the default value of cpu_slot_preemption server setting from false to true, making CPU scheduling preemptive by default. Existing workloads may need adjustment; operators should review CPU scheduling behavior. (introduced in 26.1) #94060
    • e.g. SETTINGS cpu_slot_preemption = false
  • Revert INSERT into simple ALIAS columns due to format incompatibility — Reverts the ability to INSERT into simple ALIAS columns because the feature did not work with custom formats and was not guarded by a setting. Restores previous behavior – INSERTs into ALIAS columns are no longer allowed; users relying on this functionality must adjust their workflows. (introduced in 25.12) #93061
  • Fix bitShiftLeft and bitShiftRight to return zero when shifting by full bit width — Changes the behavior of bitShiftLeft and bitShiftRight functions to return zero or empty value when the shift amount equals the bit width of the type, instead of non-zero values. Corrects a semantic bug in bit shift operations, but may change results for existing queries relying on the old behavior. (introduced in 25.12) #91943
    • e.g. SELECT bitShiftLeft(1, 8) -- previously returned 256, now returns 0
  • Fix implicit indices metadata handling — Fixes multiple issues with implicit minmax indices created by settings. Implicit indices are no longer included in table metadata, which may cause metadata errors on older replicas during rolling upgrades. Prevents schema inconsistencies and potential errors when using implicit indices with ReplicatedMergeTree. (introduced in 25.12) #91429
  • Change default of check_query_single_value_result to false for detailed CHECK TABLE output — Changes the default value of setting check_query_single_value_result from true to false, so CHECK TABLE now returns detailed per-part results instead of a single aggregated 0/1. Provides more informative CHECK TABLE output by default, but may break scripts that parse the old format. (introduced in 25.12) #91009
    • e.g. CHECK TABLE table_name;
  • Statistics format change for Nullable columns requires regeneration — Fixes statistics format incompatibility when altering columns to Nullable(String); old statistics cause crashes. Operators must run ALTER TABLE … MATERIALIZE STATISTICS ALL to regenerate. Failing to regenerate statistics may lead to server crashes after upgrade. (introduced in 25.12) #90311
    • e.g. ALTER TABLE table_name MATERIALIZE STATISTICS ALL
  • Remove settings allowing non-comparable types in ORDER BY and comparisons — Removes the settings allow_not_comparable_types_in_order_by and allow_not_comparable_types_in_comparison_functions, which allowed using non-comparable types like QBit in orderings and comparisons, causing potential logical errors. Prevents silent logical errors by enforcing type safety in ordering and comparison operations. (introduced in 25.12) #90028
  • Ngram tokenizer no longer returns short ngrams; empty search returns no rows — Changes the ngram tokenizer to not return ngrams shorter than the configured length N, and makes text search return no rows when search tokens are empty. Ensures consistent behavior, but may break existing queries that relied on the old (incorrect) tokenizer output or empty search token handling. (introduced in 25.12) #89757
  • Prohibit multiple plain-rewritable disks with shared object storage path — Adds a startup check that prevents creating multiple plain-rewritable disks on top of the same object storage path, as colliding metadata transactions can cause undefined behavior and data loss. Eliminates the risk of data corruption when multiple plain-rewritable disks mistakenly share the same object storage prefix. (introduced in 25.10) #89358
  • Enable with_size_stream serialization for String columns by default — Enables the new with_size_stream serialization format for String columns in MergeTree tables, which is incompatible with versions before 25.10. Improves storage efficiency but prevents downgrade to versions before 25.10 unless legacy settings are configured. (introduced in 25.11) #89329
    • e.g. To preserve downgrade capability, set serialization_info_version=‘basic’andstring_serialization_version=‘single_stream’ in the merge_tree configuration.
  • Remove obsolete LIVE VIEW feature — Removed the deprecated LIVE VIEW feature entirely; existing LIVE VIEW tables must be dropped before upgrading to this version. Upgrading will fail if any LIVE VIEW tables exist, so users must migrate away beforehand. (introduced in 25.11) #88706
  • Remove cache_hits_threshold from filesystem cache — Removes the cache_hits_threshold feature from the filesystem cache. This setting, which deferred caching until a certain number of hits, is now redundant due to the SLRU cache policy. This is a backward incompatible change; any configurations using cache_hits_threshold will be ignored and caching behavior may change. (introduced in 25.10) #88344
  • New tokenizer parameter syntax for text indexes — Changes tokenizer parameter syntax and names: old names (default, split, ngram, no_op) are replaced with new ones (splitByNonAlpha, splitByString, ngrams, array) and parameters use function-style notation. Existing DDLs using old tokenizer names will fail; must be updated to new syntax. (introduced in 25.10) #87997
    • e.g. ALTER TABLE ... ADD INDEX my_idx TYPE full_text(ngrams(2))
  • Default deduplication window reduced from 1 week to 1 hour — Decreases the default value of replicated_deduplication_window_seconds from 604800 to 3600 to reduce ZooKeeper znode storage. Reduces ZooKeeper storage for low insertion rates; may cause duplicate inserts if replication delay exceeds one hour. (introduced in 25.10) #87414
    • e.g. SET replicated_deduplication_window_seconds = 604800;
  • Force storage_metadata_write_full_object_key on by default — Enables the server setting storage_metadata_write_full_object_key by default and makes it immutable; metadata writes always use the full object key format. Simplifies metadata handling but restricts downgrade compatibility to 25.x releases only; downgrading to earlier versions is not supported. (introduced in 25.10) #87335
  • Disable nonsensical binary operations with IPv4/IPv6 and non-integer types — Disables plus/minus arithmetic operations between IPv4/IPv6 values and non-integer types (e.g., Float, DateTime), which previously caused logical errors or crashes. Prevents incorrect queries and potential crashes; existing queries or views using such operations will fail and require adjustment. (introduced in 25.9) #86336
  • Remove deprecated Object data type — Removes the deprecated Object data type used for storing semi-structured JSON-like data. Tables with Object columns must be migrated before upgrading. Upgrade will fail if any table still uses the Object type; requires pre-upgrade migration to avoid data loss. (introduced in 25.11) #85718
    • e.g. ALTER TABLE table MODIFY COLUMN col JSON
  • Revert INSERT into ALIAS columns feature — Reverts the previous change that allowed INSERT into simple ALIAS columns, as it did not work with custom formats and was not guarded by a setting. Users who relied on this feature must adjust their queries; the feature is removed. (introduced in 26.1) #84154
  • Fix alias substitution in formatter, potentially breaking CREATE VIEW with IN — Fixes inconsistent formatting caused by incorrect alias substitution; some CREATE VIEW queries with IN referencing an alias may fail when the analyzer is disabled. Operators using the old analyzer (disabled) may need to enable the analyzer to prevent incompatibility. (introduced in 26.1) #82833
  • Disallow empty column list in JOIN USING — Makes USING() with no columns a syntax error instead of causing runtime or logical errors. Prevents confusing crashes and logical errors, enforcing correct SQL syntax. (introduced in 26.1) #82502
  • Stop formatting operators as table functions in syntax output — Changes formatting: EXPLAIN SYNTAX no longer formats operators as if they were table functions, and clickhouse-format/formatQuery will not convert functional syntax to operator syntax. Queries that relied on the old formatting may produce different output; EXPLAIN SYNTAX now better reflects actual syntax. (introduced in 25.10) #81601
  • Query cache ignores log_comment setting — Made the query result cache ignore the log_comment setting so that queries differing only in log_comment hit the cache. Improves cache efficiency but breaks users who used log_comment for cache segmentation; they should switch to query_cache_tag. (introduced in 25.10) #79878
  • JSON type SKIP REGEXP uses partial match by default — Changed the default matching behavior of SKIP REGEXP in JSON type to use partial match instead of full match. Queries relying on full match may produce different results on upgrade. (introduced in 26.1) #79250
  • Remove transposed_with_wide_view mode of metric_log — Removes the transposed_with_wide_view mode for system.metric_log because it was unusable due to a bug. Defining this mode is no longer allowed. Users with custom metric_log configurations using this mode must remove it before upgrading to avoid errors; no data loss is expected. (introduced in 26.1) #78412
  • Infer PostgreSQL DATE columns as Date32 — DATE columns from PostgreSQL are now inferred as Date32 in ClickHouse instead of Date, and Date32 values can be inserted back to PostgreSQL. Correctly handles dates outside the narrow Date range; existing tables relying on Date inference may break on upgrade. (introduced in 26.2) #73084
  • ALTER MODIFY COLUMN requires explicit DEFAULT when converting nullable to non-nullable — When converting a Nullable column to a non-nullable type, ALTER MODIFY COLUMN now requires an explicit DEFAULT expression; NULLs are replaced with the default instead of causing an error. Prevents stuck ALTERs and provides consistent behavior for nullable-to-nonnullable conversions. (introduced in 25.12) #5985
    • e.g. ALTER TABLE t MODIFY COLUMN x Int32 DEFAULT 0;

👆 Back to v26.3 versus 25.8 overview

New features

SQL / Main features

  • Add polyglot SQL transpiler for 30+ external dialects — Integrates a Rust-based polyglot SQL transpiler that allows writing queries in over 30 SQL dialects (e.g., MySQL, PostgreSQL, SQLite) and transpiles them to ClickHouse SQL, controlled by two experimental settings: allow_experimental_polyglot_dialect and polyglot_dialect. Enables users to write queries in familiar SQL syntax from other databases without manual translation, reducing migration friction. (settings allow_experimental_polyglot_dialect, polyglot_dialect) (introduced in 26.3) #99496
    • e.g. SET dialect = 'polyglot', polyglot_dialect = 'snowflake'; SELECT IFF(1 > 0, 'yes', 'no');
  • Support Nullable(Tuple) type experimentally — Adds support for the Nullable(Tuple) type, enabled by the setting allow_experimental_nullable_tuple_type. This also changes JSON/Dynamic/Variant tuple subcolumns to return NULL instead of default values. Enables more flexible schema handling where tuple fields can be null, but note the breaking change for JSON/Dynamic/Variant subcolumns. (settings allow_experimental_nullable_tuple_type) (introduced in 26.1) #89643
    • e.g. CREATE TABLE test (id UInt32, data Nullable(Tuple(String, Int64)))
  • ClickHouse gains bit-sliced vector type QBit and approximate L2 distance function — Adds the QBit data type for storing vectors in bit-sliced format and the L2DistanceTransposed function for approximate vector search with precision-speed trade-off. Enables efficient approximate nearest neighbor search with tunable accuracy. (settings allow_experimental_qbit_type; functions L2DistanceTransposed) (introduced in 25.10) #87922
    • e.g. SELECT L2DistanceTransposed(vector, [1.0, 2.0]) FROM table;
  • Add IS DISTINCT FROM and enhance <=> operator — Adds the IS DISTINCT FROM operator and enhances the existing IS NOT DISTINCT FROM (<=>) operator to support compatible numeric types (e.g., UInt32 vs Int64) and nullable combinations. This improves SQL standard compliance and provides more flexible null-safe comparisons across different numeric types. (functions isDistinctFrom, isNotDistinctFrom) (introduced in 25.11) #87581
    • e.g. SELECT 1 IS DISTINCT FROM NULL; -- returns 1
  • Support Materialized CTE (Common Table Expressions) — Allows CTEs to be evaluated only once during query execution, with results stored in temporary tables, avoiding repeated computation. Improves performance for queries that reference the same CTE multiple times. (introduced in 26.3) #100331
    • e.g. SET enable_materialized_cte = 1; WITH top_users AS MATERIALIZED (SELECT user_id, count() AS cnt FROM events GROUP BY user_id ORDER BY cnt DESC LIMIT 1000) SELECT * FROM top_users INNER JOIN (SELECT us
  • EXPLAIN PLAN gets pretty and compact formatting options — Adds pretty=1 to display the query plan as a tree using Unicode line-drawing characters, and compact=1 to hide Expression steps and detailed action descriptions. EXPLAIN PLAN output becomes more readable and concise, aiding in query debugging and optimization. (introduced in 26.3) #98500
    • e.g. EXPLAIN pretty=1, compact=1 SELECT URL, count() FROM hits WHERE URL LIKE '%google%' GROUP BY URL ORDER BY count() DESC LIMIT 10;
  • Add fractional LIMIT and OFFSET support — Allows LIMIT and OFFSET to be fractional values (e.g., 0.5) to select a percentage of rows from a query result. Simplifies sampling and percentile queries without needing to know the total row count. (introduced in 25.11) #81892
    • e.g. SELECT county, avg(price) AS price FROM uk_price_paid GROUP BY county ORDER BY price DESC LIMIT 0.25;
  • Add system.unicode table for Unicode character properties — Adds a system.unicode table containing a list of Unicode characters and their properties. Provides an easy way to query Unicode character data directly from SQL. (introduced in 25.11) #80055
    • e.g. SELECT block, general_category, groupConcat(code_point) FROM system.unicode WHERE name LIKE '%LEAF%' GROUP BY ALL
  • Add LIMIT BY ALL syntax — Introduces LIMIT BY ALL which automatically expands to include all non-aggregate expressions from the SELECT clause as LIMIT BY keys. Simplifies queries by eliminating the need to explicitly list all non-aggregate columns when limiting per group. (introduced in 25.10) #59152
    • e.g. LIMIT 5 BY ALL
  • Add support for negative LIMIT and negative OFFSET — Allows negative LIMIT to return the last N rows and negative OFFSET to skip from the end of the result set. Provides more flexible pagination and tail-row retrieval without requiring subqueries. (introduced in 25.10) #28913
    • e.g. SELECT * FROM logs WHERE date = today() ORDER BY time LIMIT -100;
  • New deduplicate_insert setting for unified dedup control — Introduces the deduplicate_insert setting that overrides both insert_deduplicate and async_insert_deduplicate, providing centralized control over block deduplication for INSERTs into Replicated tables. Simplifies configuration by replacing two settings with one, reducing confusion and potential misconfiguration. (settings deduplicate_insert) (introduced in 26.2) #94413
    • e.g. SET deduplicate_insert = 'enable';
  • Add default_dictionary_database setting — Introduces a new setting default_dictionary_database that specifies the default database for unqualified external dictionary references, easing migration from XML-defined to SQL-defined dictionaries. Simplifies dictionary migration by allowing legacy dictionary queries to work without modification. (settings default_dictionary_database) (introduced in 26.2) #91412
    • e.g. SET default_dictionary_database = 'mydb'; SELECT dictGet('dict_name', 'attr', key);
  • Alias table engine moved behind experimental flag — Moves the Alias table engine to experimental, requiring the setting allow_experimental_alias_table_engine to be enabled (default false) to create new Alias tables. Existing Alias tables continue to work. Provides a safety net by marking Alias engine as experimental, preventing accidental use and allowing future development. (settings allow_experimental_alias_table_engine) (introduced in 25.11) #89712
  • Add setting to auto-create parent directories for INTO OUTFILE — Introduces the into_outfile_create_parent_directories setting that automatically creates missing parent directories when writing query results to a file via INTO OUTFILE. Simplifies workflows by eliminating the need to manually create directories before writing output files. (settings into_outfile_create_parent_directories) (introduced in 25.11) #88610
    • e.g. SET into_outfile_create_parent_directories=1; SELECT * FROM table INTO OUTFILE '/tmp/new_dir/output.csv';
  • Add SOME keyword for subquery expressions — Users can now use the SOME keyword in subquery expressions, which behaves identically to ANY. Provides alternative syntax, improving SQL compatibility and readability. (introduced in 26.3) #99842
    • e.g. SELECT * FROM t1 WHERE col1 = SOME(SELECT col2 FROM t2);
  • Nullable query parameters default to NULL when omitted — When a query parameter has Nullable type and is not provided, it is treated as NULL instead of causing an error. Simplifies usage of optional parameters in queries. (introduced in 26.3) #93869
    • e.g. SELECT {param:Nullable(String)}
  • Add table function primes and system table system.primes — Introduces a table function primes and corresponding system table system.primes that return prime numbers in ascending order. Provides a convenient, built-in source of prime numbers for testing, benchmarking, or mathematical queries without external data. (introduced in 26.2) #90839
    • e.g. SELECT * FROM primes(100) LIMIT 10
  • Async insert deduplication now works with dependent materialized views — Implements deduplication for async inserts into tables that have dependent materialized views: when a block_id collision occurs, conflicting rows are filtered out and remaining rows are transformed through the materialized views’ select queries to produce a deduplicated block. Enables idempotent async inserts into tables with materialized views, preventing duplicate data ingestion. (introduced in 26.1) #89140
  • Full-text search moves to private preview — Full-text search functionality has been promoted from experimental to a private preview stage, indicating greater stability and readiness for testing. Users can now evaluate full-text search in a more stable environment, moving it closer to general availability. (introduced in 25.11) #88928
  • Add temporary views support — Introduces CREATE TEMPORARY VIEW with session-scoped visibility, similar to temporary tables, including a dedicated access privilege. Enables users to define temporary named queries for session-local use without persisting them, improving workflow flexibility. (introduced in 25.9) #86432
    • e.g. CREATE TEMPORARY VIEW my_view AS SELECT * FROM table WHERE condition;
  • Support Alias table engine for table aliasing — Introduces the Alias table engine, allowing creation of a table that is an alias for another existing table. DML queries on the alias are redirected to the referenced table; DDL operations (DROP, DETACH, SHOW CREATE) act on the alias itself. Provides a lightweight way to create alternative names for tables, simplifying query writing and migration scenarios. (introduced in 25.9) #76569
    • e.g. CREATE TABLE alias_table ENGINE = Alias('target_table')
  • Allow SQL-standard functions without parentheses — Allows certain niladic SQL functions (e.g., NOW, CURRENT_TIMESTAMP, CURRENT_USER) to be called without parentheses, improving compatibility with other SQL dialects. Reduces syntactic noise and aligns ClickHouse SQL syntax with standard SQL. (introduced in 26.2, 26.3) #52102
    • e.g. SELECT CURRENT_TIMESTAMP;
  • Support CREATE OR REPLACE for temporary tables — Adds the ability to use CREATE OR REPLACE TABLE syntax for temporary tables, atomically replacing an existing temporary table if it exists. Simplifies managing temporary tables by avoiding separate DROP and CREATE statements. (introduced in 25.11) #35888
    • e.g. CREATE OR REPLACE TEMPORARY TABLE t (x Int32) ENGINE = Memory

Functions

  • Add reverseBySeparator function — Adds a new function reverseBySeparator that reverses the order of substrings in a string separated by a specified separator. Provides a built-in efficient way to reverse DNS-like strings or other delimited substrings. (functions reverseBySeparator) (introduced in 26.1) #91463
    • e.g. SELECT reverseBySeparator('benchmark.clickhouse.com', '.')
  • Add argAndMin and argAndMax aggregate functions — Introduces two new aggregate functions argAndMin and argAndMax that return a tuple containing both the argument and the corresponding minimum/maximum value. Provides a convenient way to retrieve both the value and its min/max key in one function call, reducing query complexity. (functions argAndMin, argAndMax) (introduced in 25.11) #89884
    • e.g. SELECT argAndMax(town, price) FROM uk_price_paid WHERE toYear(date) = 2025;
  • Add cume_dist window function — Implements the standard SQL cume_dist window function to compute cumulative distribution within a window partition. Enhances SQL compatibility and enables percentile-like analytical queries. (functions cume_dist) (introduced in 25.11) #86920
    • e.g. SELECT cume_dist() OVER (ORDER BY value) FROM table
  • Experimental WebAssembly UDF support — Adds experimental support for WebAssembly-based user-defined functions, allowing custom function logic implemented in Wasm to be executed within ClickHouse using the Wasmtime backend. Enables powerful user-defined logic in SQL without C++ extensions, expanding extensibility for custom data processing. (introduced in 26.3) #88747
  • Add unicode_word tokenizer for full-text indexes and tokens function — Adds a unicode_word tokenizer for full-text indexes and a tokens function that splits text using Unicode word boundary rules, with configurable stop words defaulting to common CJK punctuation. Enables better full-text search on multilingual text, especially for CJK content. (functions tokens) (introduced in 26.3) #99357
    • e.g. SELECT tokens('Hello world')
  • Add normalizeUTF8NFKCCasefold function — Adds the normalizeUTF8NFKCCasefold string function that combines NFKC normalization with Unicode case folding. Enables case-insensitive identifier matching and normalization according to NFKC_Casefold standard. (functions normalizeUTF8NFKCCasefold) (introduced in 26.3) #99276
    • e.g. SELECT normalizeUTF8NFKCCasefold('Hello')
  • Add caseFoldUTF8 and removeDiacriticsUTF8 functions — Introduces two new functions for Unicode case folding and diacritical mark removal using the ICU library. Enables case-insensitive and accent-insensitive string matching and comparison. (functions caseFoldUTF8, removeDiacriticsUTF8) (introduced in 26.3) #98973
    • e.g. SELECT caseFoldUTF8('Hello'); SELECT removeDiacriticsUTF8('Café');
  • Add xxh3_128 hash function with UInt128 return type — Introduces the xxh3_128 hash function that returns a UInt128 value, compatible with reference xxHash3 implementations for single arguments. Provides a high-performance, non-cryptographic 128-bit hash function for use in queries. (functions xxh3_128) (introduced in 26.2) #96055
    • e.g. SELECT xxh3_128('hello');
  • Add cosineDistanceTransposed function — Introduced the cosineDistanceTransposed function that efficiently approximates the cosine distance between two points using QBit columns with adjustable precision. Enables fast approximate cosine distance computation for similarity searches and vector processing. (functions cosineDistanceTransposed) (introduced in 26.1) #93621
    • e.g. SELECT cosineDistanceTransposed(quantileBFloat16(embedding1), quantileBFloat16(embedding2)) FROM vectors_table;
  • Add colorOKLABToSRGB and colorSRGBToOKLAB functions — Adds two scalar functions for converting between sRGB and OKLAB color spaces. Enables color space transformations directly in SQL for analytics and data processing. (functions colorOKLABToSRGB, colorSRGBToOKLAB) (introduced in 26.2) #93361
    • e.g. SELECT colorSRGBToOKLAB(0.5, 0.5, 0.5);
  • Implement FunctionVariantAdaptor for Variant type support — Adds a FunctionVariantAdaptor to provide default implementations for functions operating on Variant types, enabling support for variant arguments in functions like flipCoordinates. Extends function compatibility with the Variant data type, improving flexibility. (settings use_variant_default_implementation_for_comparisons) (introduced in 26.1) #90900
    • e.g. SELECT flipCoordinates(variant_column) FROM table;
  • Add naturalSortKey function for human-friendly string ordering — Introduces the naturalSortKey function that encodes digit sequences with a sortable prefix, enabling natural ordering (e.g., ‘hello4world5’ before ‘hello4world10’). Allows intuitive sorting of strings with embedded numbers, useful for filenames and version strings. (functions naturalSortKey) (introduced in 26.3) #90322
    • e.g. SELECT naturalSortKey('hello4world10')
  • Implement dictGetKeys function for reverse dictionary lookup — Adds the dictGetKeys function that returns the dictionary key(s) whose attribute equals a specified value, using a per-query reverse-lookup cache tuned by the max_reverse_dictionary_lookup_cache_size_bytes setting to speed up repeated lookups. Enables efficient reverse dictionary lookups without full scan, useful for finding keys by attribute value. (settings max_reverse_dictionary_lookup_cache_size_bytes; functions dictGetKeys) (introduced in 25.12) #89197
    • e.g. SELECT dictGetKeys('my_dict', 'attribute_column', 'target_value');
  • Add areaCartesian, areaSpherical, perimeterCartesian, perimeterSpherical functions — Adds SQL functions areaCartesian, areaSpherical, perimeterCartesian, perimeterSpherical to compute area and perimeter of Geometry objects using Boost.Geometry. Users can now perform geometric calculations directly in SQL on geometry columns. (functions areaCartesian, areaSpherical, perimeterCartesian, perimeterSpherical) (introduced in 25.12) #89047
    • e.g. SELECT areaCartesian(geom) FROM table;
  • Add midpoint scalar function and avg2 alias for averaging values — Introduces the midpoint scalar function (and avg2 as a synonym for two arguments) that computes the average of its arguments, supporting numeric and temporal types. Provides a concise way to compute averages of two or more values, particularly useful for date/time arithmetic. (functions midpoint, avg2) (introduced in 25.11) #89029
    • e.g. SELECT midpoint(3, 7); -- returns 5
  • Add case-insensitive startsWith and endsWith functions — Adds optimized case-insensitive variants of startsWith and endsWith: startsWithCaseInsensitive, endsWithCaseInsensitive, and their UTF8 counterparts (startsWithCaseInsensitiveUTF8, endsWithCaseInsensitiveUTF8). Enables efficient case-insensitive prefix/suffix matching without needing to use lower() first, and improves ILIKE rewrite performance. (functions startsWithCaseInsensitive, endsWithCaseInsensitive, startsWithCaseInsensitiveUTF8, endsWithCaseInsensitiveUTF8) (introduced in 25.10) #87374
    • e.g. SELECT startsWithCaseInsensitive('Hello', 'hel'); -- 1
  • Implement quantilePrometheusHistogram aggregate functions — Adds aggregate functions quantilePrometheusHistogram and quantilesPrometheusHistogram that compute quantiles from Prometheus histogram bucket boundaries and cumulative counts using linear interpolation. Enables direct compatibility with Prometheus classic histograms, simplifying analysis of Prometheus metrics in ClickHouse. (functions quantilePrometheusHistogram, quantilesPrometheusHistogram) (introduced in 25.10) #86294
    • e.g. SELECT quantilePrometheusHistogram(upper_bounds, cumulative_counts) FROM prometheus_histogram_data
  • Add timeSeriesChangesToGrid and timeSeriesResetsToGrid aggregate functions — Implements PromQL-style changes and resets for time series data, counting value changes or decreases within a sliding window on a regular time grid, returning Array(Nullable(Float64)). Enables Prometheus-like monitoring queries directly in ClickHouse without external tools. (functions timeSeriesChangesToGrid, timeSeriesResetsToGrid) (introduced in 25.9) #86010
    • e.g. SELECT timeSeriesChangesToGrid(start, end, step, lookback)(timestamp, value) FROM time_series
  • Add studentTTestOneSample aggregate function — Adds the studentTTestOneSample aggregate function that performs a one-sample Student’s t-test, returning t-statistic and p-value. Enables statistical hypothesis testing directly in SQL without external tools. (functions studentTTestOneSample) (introduced in 25.10) #85436
    • e.g. SELECT studentTTestOneSample(value) FROM table
  • Add isValidASCII function to check ASCII-only strings — Adds the isValidASCII scalar function that returns 1 if the string contains only ASCII characters, otherwise 0. Provides a simple way to validate string encoding directly in SQL. (functions isValidASCII) (introduced in 25.9) #85377
    • e.g. SELECT isValidASCII('Hello')
  • New conv function for base conversion (2-36) — Adds the conv() function to convert numbers between bases 2 to 36. Provides built-in base conversion without requiring external functions or UDFs. (functions conv) (introduced in 25.10) #83058
    • e.g. SELECT conv('FF', 16, 10) AS result;
  • Add arrayExcept function — Returns elements from the first array that are not present in the second array, treating arrays as sets (set difference). Provides a missing set operation for arrays, enabling cleaner queries. (functions arrayExcept) (introduced in 25.9) #82368
    • e.g. SELECT arrayExcept([1,2,3], [2,4])
  • Add flipCoordinates function to swap pointers in arrays — Added flipCoordinates function that unwraps the required number of dimensions in an array and swaps pointers inside the Tuple column. Enables transformation of coordinate-like data (e.g., swapping x and y values in an array of tuples). (functions flipCoordinates) (introduced in 25.11) #79469
    • e.g. SELECT flipCoordinates([(1.0, 2.0), (3.0, 4.0)]) AS swapped_coords
  • Add naiveBayesClassifier function for text classification — Introduces the naiveBayesClassifier function that classifies text using a Naive Bayes model with n-grams and Laplace smoothing. Models are configured server-side via nb_models config. Enables in-database text classification without external ML tools, useful for spam detection, sentiment analysis, or any text categorization task. (functions naiveBayesClassifier) (introduced in 25.10) #78700
    • e.g. SELECT naiveBayesClassifier('model_name', body) AS category FROM emails
  • Add HMAC SQL function — Adds the HMAC(algorithm, message, key) function for keyed‑hash message authentication. Enables authenticated hash computations directly in SQL, useful for data integrity and security checks. (functions HMAC) (introduced in 25.12) #73900
    • e.g. SELECT HMAC('SHA256', 'my message', 'secret')
  • Add arrayRemove function — Adds the arrayRemove(arr, elem) function to remove all elements equal to elem from an array. Provides a convenient way to filter array elements by equality directly in SQL queries. (functions arrayRemove) (introduced in 25.11) #52099
    • e.g. SELECT arrayRemove([1, 2, 3, 2], 2) → [1, 3]
  • Incremental improvements for WASM UDF support — Adds incremental improvements to the WASM UDF infrastructure, enhancing experimental support for user-defined functions compiled to WebAssembly. Moves the WASM UDF feature closer to production readiness, expanding UDF options for advanced users. (introduced in 26.3) #99373
  • Support has() function with primary key indexes for constant arrays — Allows the has() function to leverage primary key and data skipping indexes when the first argument is a constant array. Speeds up queries using has(constant_array, column) by avoiding full table scans. (introduced in 25.12) #90980
    • e.g. SELECT * FROM table WHERE has([1, 2, 3], indexed_column);
  • searchAll and searchAny work without text index — Makes searchAll and searchAny functions work on columns without a text index by falling back to brute-force scan using the default tokenizer. Users can now use these search functions on any string column even without a text index, though performance may be slower. (introduced in 25.10) #87722
    • e.g. SELECT searchAll(text_col, 'term') FROM table
  • Add allow_reentry option to windowFunnel — Adds an optional allow_reentry parameter to the windowFunnel aggregate function that, when used with strict_order, ignores out-of-order events instead of stopping the funnel analysis. Enables accurate funnel analysis for user journeys with refreshes or back-navigation without underreporting conversion rates. (introduced in 25.12) #86916
    • e.g. SELECT windowFunnel(3600)(1, time, event) WITH allow_reentry FROM events

MergeTree-related

  • Bucketed serialization for Map columns in MergeTree — Introduces hash-based bucketed serialization for Map columns, enabling single-key lookups to read only one bucket instead of the entire column, with speedup 2-49x. Adds settings: map_serialization_version, max_buckets_in_map, etc. Supports skip indexes and subcolumn rewrite. Dramatically improves performance for queries accessing individual Map keys in MergeTree tables. (settings map_serialization_version, max_buckets_in_map, map_buckets_strategy, map_buckets_coefficient, map_buckets_min_avg_size, map_serialization_version_for_zero_level_parts) (introduced in 26.3) #100900
    • e.g. CREATE TABLE t (m Map(String, Int64)) ENGINE = MergeTree ORDER BY tuple() SETTINGS map_serialization_version = 'with_buckets'; SELECT m['key'] FROM t;
  • Introduce new syntax and framework for projection index — Adds a new syntax and framework to simplify and extend the projection index feature, following the prior preliminary work. Provides a more intuitive and powerful way to define and use projections for faster queries. (introduced in 26.1) #91844
  • Add projection-level settings via WITH SETTINGS clause — Introduces projection-level settings through the new WITH SETTINGS clause in ALTER TABLE … ADD PROJECTION, allowing projections to override MergeTree storage parameters like index_granularity on a per-projection basis. Enables fine-grained tuning of storage and indexing parameters for individual projections, optimizing query performance for specific access patterns. (introduced in 25.12) #90158
    • e.g. ALTER TABLE my_table ADD PROJECTION my_proj (SELECT ...) WITH SETTINGS index_granularity = 8192
  • Add setting to disable partition pruning — Introduces the use_partition_pruning setting (alias use_partition_key) that, when set to false, disables partition key pruning for MergeTree tables, allowing debugging of partition-based filtering. Helps diagnose issues with partition pruning by providing a way to bypass it. (settings use_partition_pruning) (introduced in 26.3) #97888
    • e.g. SET use_partition_pruning = 0;
  • Add table_readonly setting for MergeTree tables — Introduces the MergeTree setting table_readonly that, when enabled, prevents inserts and mutations on the table while still allowing ALTER MODIFY SETTING to toggle the flag. Provides a lightweight way to mark tables as read-only without changing permissions, useful for archival or maintenance scenarios. (settings table_readonly) (introduced in 26.3) #97652
    • e.g. ALTER TABLE t MODIFY SETTING table_readonly = 1;
  • New mergeTreeTextIndex table function for text index introspection — Added the mergeTreeTextIndex(database, table, index) table function that allows reading data directly from a text index for introspection or aggregation. Enables advanced troubleshooting and analysis of text index data like tokens, cardinalities, and posting flags. (functions mergeTreeTextIndex) (introduced in 26.3) #97003
    • e.g. SELECT * FROM mergeTreeTextIndex('default', 'my_table', 'my_idx')
  • Add OPTIMIZE DRY RUN to simulate merges without committing — Introduces OPTIMIZE <table> DRY RUN PARTS <part names> query to simulate merges of specified parts without committing the result part, optionally validating with checkDataPart. Enables safe testing of merge correctness, deterministic reproduction of merge bugs, and reliable merge performance benchmarking. (settings optimize_dry_run_check_part) (introduced in 26.2) #96122
    • e.g. OPTIMIZE table DRY RUN PARTS 'part1', 'part2';
  • Add server setting insert_deduplication_version for unified dedup hash migration — Introduces the server setting insert_deduplication_version to allow migrating from separate sync/async deduplication hashes to a unified hash, with stages old_separate_hashes, compatible_double_hashes, and new_unified_hash. Enables safe migration of insert deduplication behavior across sync and async inserts, avoiding duplicates or missed deduplication during upgrade. (settings insert_deduplication_version) (introduced in 26.2) #95409
  • New setting use_primary_key to disable primary key pruning — Introduces a setting to control whether the primary key index is used for granule pruning in MergeTree tables. Useful for debugging index-related issues or when the primary key provides little benefit. (settings use_primary_key) (introduced in 26.1) #93319
    • e.g. SET use_primary_key = 0;
  • New setting limits dynamic subcolumns in merged Wide parts — Adds the MergeTree setting merge_max_dynamic_subcolumns_in_wide_part to cap the number of dynamic subcolumns in a Wide part after merge, independent of the data type parameters. Gives operators control over the growth of JSON subcolumns during merges, preventing excessive part complexity and potential performance degradation. (settings merge_max_dynamic_subcolumns_in_wide_part) (introduced in 25.10) #91308
    • e.g. ALTER TABLE my_table MODIFY SETTING merge_max_dynamic_subcolumns_in_wide_part = 1000;
  • Add table setting min_level_for_wide_part — Introduces a new table setting ‘min_level_for_wide_part’ that specifies the minimum part level for creating a part as Wide format instead of Compact. Provides fine-grained control over data part format, enabling users to manage storage trade-offs and optimize performance for different part levels. (settings min_level_for_wide_part) (introduced in 25.10) #88179
    • e.g. CREATE TABLE t (id UInt32) ENGINE = MergeTree ORDER BY id SETTINGS min_level_for_wide_part = 5
  • Add setting to limit dynamic subcolumns in merged Wide parts — Introduces the MergeTree setting merge_max_dynamic_subcolumns_in_wide_part to cap the number of dynamic subcolumns in a Wide part after merge, independently of data type parameters. Gives operators control over dynamic subcolumn metadata size, preventing excessive growth and improving part storage efficiency. (settings merge_max_dynamic_subcolumns_in_wide_part) (introduced in 25.11) #87646
    • e.g. ALTER TABLE my_table MODIFY SETTING merge_max_dynamic_subcolumns_in_wide_part = 1000
  • Auto-create statistics on MergeTree columns with auto_statistics_types setting — Adds table-level setting auto_statistics_types to automatically create specified statistics types (e.g., minmax, uniq, countmin) on all suitable columns in MergeTree tables. Simplifies statistics management by allowing automatic creation of column statistics without manual per-column configuration. (settings auto_statistics_types) (introduced in 25.10) #87241
    • e.g. ALTER TABLE my_table MODIFY SETTING auto_statistics_types = 'minmax,uniq'
  • Start deduplication hash migration to compatible double hashes — Changes the default deduplication hashing to use compatible double hashes, unifying sync and async insert deduplication. Ensures new writes use compatible hashes across insert types, improving deduplication consistency and future migration. (introduced in 26.2) #97562
  • Support direct nested loop join for MergeTree tables — Introduces support for direct (nested loop) join algorithm for MergeTree tables, controlled by the setting join_algorithm = 'direct'. It pushes join key filters directly to the storage layer and builds a hash map on the fly, currently supporting INNER and LEFT joins with single-column equality keys. Enables efficient join execution by pushing filters directly to the storage layer, improving performance for join patterns that benefit from nested loop joins. (introduced in 25.12) #89920
    • e.g. SET join_algorithm = 'direct'; SELECT * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
  • Add text index support for Array columns — Enables full-text indices (using preprocessing like lowercasing) on columns of type Array in MergeTree tables by applying the preprocessing per array element. Extends full-text search capabilities to array data, improving search flexibility and query performance. (introduced in 26.1) #89895
    • e.g. CREATE TABLE t (arr Array(String), INDEX idx arr TYPE full_text GRANULARITY 1) ENGINE = MergeTree ORDER BY tuple();
  • Add preprocessor argument for text index construction — Allows users to specify an arbitrary expression as a preprocessor for text indexes, transforming each document before tokenization. Enables custom preprocessing of text data (e.g., normalization, stripping HTML) at index time for improved search behavior. (introduced in 25.11) #88272
    • e.g. CREATE TABLE t (content String, INDEX idx content TYPE text WITH preprocessor = lower(content)) ENGINE = MergeTree ORDER BY tuple();
  • Add sparse_gram bloom filter index — Adds a new sparse_gram bloom filter index for efficient long substring search using a convex-hull algorithm. Improves substring search performance for large text columns in MergeTree tables. (introduced in 25.10) #79985
    • e.g. CREATE TABLE t (s String, INDEX idx s TYPE sparse_gram(3, 4) GRANULARITY 1) ENGINE = MergeTree ORDER BY s

Performance

  • Add Parquet metadata SLRU cache to reduce re-downloads — Introduces an SLRU (Segmented LRU) cache for Parquet file metadata, avoiding re-downloading the metadata on subsequent reads of the same Parquet file, with configurable size and policy. Significantly speeds up repeated queries on Parquet files by caching metadata, reducing I/O and improving latency. (settings use_parquet_metadata_cache, parquet_metadata_cache_policy, parquet_metadata_cache_size, parquet_metadata_cache_max_entries, parquet_metadata_cache_size_ratio) (introduced in 26.3) #98140
    • e.g. SET use_parquet_metadata_cache = 1; -- enabled by default; customize with server settings
  • Add SLRU cache for Parquet metadata — Added a new SLRU cache for Parquet file metadata (footer, column chunks, index pages) to avoid re-downloading files when reading metadata. The cache can be dropped with SYSTEM DROP PARQUET METADATA CACHE. Improves reading performance by caching metadata, reducing latency and network traffic for repeated queries. (settings parquet_metadata_cache_policy, parquet_metadata_cache_size, parquet_metadata_cache_max_entries, parquet_metadata_cache_size_ratio) (introduced in 26.2) #89102
    • e.g. SYSTEM DROP PARQUET METADATA CACHE
  • Distribute vector index search across replicas for large indexes — Enables distributed loading and searching of vector index parts across replicas, allowing vector indexes to exceed single-node memory capacity. Supports large-scale vector search workloads that cannot fit on a single VM, improving scalability. (introduced in 26.2) #95876
  • Add setting to control streams in Cluster table functions — Introduces the setting max_streams_for_files_processing_in_cluster_functions to limit the number of streams used for parallel reading of files in *Cluster table functions. Allows fine-tuning of parallelism for distributed file processing, avoiding excessive resource usage. (settings max_streams_for_files_processing_in_cluster_functions) (introduced in 25.12) #90223
    • e.g. SET max_streams_for_files_processing_in_cluster_functions = 4;
  • Split Cache Strategy Improves Server Startup Time — Enable splitting data and system files in cache into separate segments, using a separate eviction policy to keep system files longer. Reduces server restart times by reducing S3 requests for system files. (settings filesystem_cache_use_split_cache, filesystem_cache_split_ratio) (introduced in 26.2) #87834
    • e.g. Set filesystem_cache_use_split_cache=1andfilesystem_cache_split_ratio=0.2.

Codecs / compression

  • Add ALP floating-point compression codec — Introduces the ALP compression codec for Float32/Float64 columns, providing improved compression ratios compared to existing codecs. Reduces storage footprint for floating-point data without sacrificing performance. (introduced in 26.3) #91362
    • e.g. CREATE TABLE metrics (timestamp DateTime, value Float64 CODEC(ALP, ZSTD)) ENGINE = MergeTree ORDER BY timestamp;

Other small SQL

  • Alias table engine becomes experimental — Moves the Alias table engine behind a new setting allow_experimental_alias_table_engine (default false). Existing tables continue to work, but new creation requires the setting to be enabled. Operators must enable the experimental setting to create new Alias tables, ensuring this engine is used cautiously and signaling its non-production readiness. (settings allow_experimental_alias_table_engine) (introduced in 25.10) #89843
    • e.g. SET allow_experimental_alias_table_engine = 1; CREATE TABLE t ... ENGINE = Alias;
  • Add Alias table engine for proxying operations to target table — Creates a new Alias table engine that acts as a proxy to another table, forwarding all reads, writes, and DDL operations to the target table while storing no data itself. Provides a lightweight way to rename or redirect access to a table without moving or duplicating data. (introduced in 25.10) #87965
    • e.g. CREATE TABLE my_alias ENGINE = Alias('mydb.target_table')

JSON data type

  • Add has() function for JSON type to check path existence — Enables the has() function on JSON type to check whether a given path exists, similar to the Map type. Provides a consistent and efficient way to test JSON path existence, simplifying queries on JSON data without parsing errors. (functions has) (introduced in 26.3) #96927
    • e.g. SELECT * FROM events WHERE has(data, 'metrics.latency')
  • Add experimental lazy type hints for JSON columns — When enabled via allow_experimental_json_lazy_type_hints, ALTER TABLE … MODIFY COLUMN json JSON(path TypeName) becomes metadata-only, adding type hints without rewriting historical data. Old parts apply hints at query time; new data materializes them during inserts and merges. Speeds up schema evolution for JSON columns by avoiding full data rewrites. (introduced in 26.3) #97412
    • e.g. ALTER TABLE events MODIFY COLUMN data JSON(metrics.count UInt64);
  • Add setting to skip invalid typed paths in JSON columns — Adds a new setting type_json_skip_invalid_typed_paths that disables exceptions when inserting JSON with values that cannot be cast to explicit typed paths, falling back to null/zero values. Allows more lenient handling of JSON data with type mismatches, enabling inserts of imperfect data without errors. (settings type_json_skip_invalid_typed_paths) (introduced in 25.12) #89886
    • e.g. SET type_json_skip_invalid_typed_paths = 1; INSERT INTO t_json VALUES ('{"path": "invalid"}');

ObjectStore - S3/Azure/GCS

  • Make filesystem background download configurable per query — Allows disabling background download of nearby part data on a per-query basis via the filesystem_cache_allow_background_download setting. Gives users control to avoid unnecessary S3 egress or latency for specific queries. (settings filesystem_cache_allow_background_download) (introduced in 25.11) #89524
    • e.g. SET filesystem_cache_allow_background_download = 0;

Datalakes & catalogs

  • Add Paimon REST catalog support — Adds support for the Paimon REST catalog as a new DataLake catalog type, allowing ClickHouse to interact with Paimon tables via REST API. Enables querying Paimon tables stored in a REST catalog directly from ClickHouse, expanding data lake integration. (settings allow_experimental_database_paimon_rest_catalog) (introduced in 26.1) #92011
  • Add Microsoft OneLake catalog integration for Iceberg — Adds support for Microsoft OneLake as a catalog type for Iceberg tables, using Azure Entra ID authentication via settings for tenant, client ID, and client secret. Enables querying Iceberg tables stored in Microsoft OneLake directly from ClickHouse using catalog semantics. (settings onelake_tenant_id, onelake_client_id, onelake_client_secret) (introduced in 25.11) #89366
    • e.g. CREATE DATABASE db ENGINE = Iceberg(catalog_type = 'OneLake', onelake_tenant_id = 'tenant', onelake_client_id = 'client', onelake_client_secret = 'secret')
  • Add system.iceberg_metadata_log for Iceberg metadata debugging — Introduces a system table to log Iceberg metadata files (root metadata, manifest lists, manifests) during SELECT, controlled by the iceberg_metadata_log_level setting. Improves debuggability of Iceberg tables by providing insights into the metadata files accessed. (settings iceberg_metadata_log_level) (introduced in 25.9) #86152
    • e.g. CREATE TABLE my_iceberg (...) ENGINE = IcebergS3(...) SETTINGS iceberg_metadata_async_prefetch_period_ms = 60000; SELECT ... FROM my_iceberg SETTINGS iceberg_metadata_staleness_ms = 30000;
  • Add query support for Apache Paimon — Adds table functions paimon, paimonS3, and paimonAzure to allow direct querying of Apache Paimon tables. Enables ClickHouse to interact with Paimon data lake storage, expanding integration options. (functions paimon, paimonS3, paimonAzure) (introduced in 25.10) #84423
    • e.g. SELECT * FROM paimon('s3://...');
  • Add Google BigLake catalog integration — Introduces integration with Google BigLake catalog, enabling querying of tables managed by BigLake. Extends ClickHouse’s data lake capabilities to Google Cloud’s BigLake ecosystem, allowing seamless querying of external data. (introduced in 26.2) #95339
    • e.g. CREATE DATABASE biglake ENGINE = DataLakeCatalog('https://biglake.googleapis.com/iceberg/v1/restcatalog') SETTINGS catalog_type = 'biglake', google_adc_credentials_file = '/home/ubuntu/.config/gcloud/
  • New icebergLocalCluster table function for distributed Iceberg reads — Adds a table function to enable distributed reading of Iceberg tables stored on shared local disk across cluster nodes. Allows querying Iceberg tables in a distributed manner without external object storage. (functions icebergLocalCluster) (introduced in 26.1) #93323
    • e.g. SELECT * FROM icebergLocalCluster('path', 'format');
  • System table for Delta Lake metadata logging — Introduced system.delta_lake_metadata_log to log metadata files read from Delta Lake tables, controlled by the setting delta_lake_log_metadata. Helps debug and audit Delta table schema evolution by exposing metadata access logs. (settings delta_lake_log_metadata) (introduced in 25.10) #87263
    • e.g. SELECT * FROM system.delta_lake_metadata_log
  • Allow Iceberg and Delta Lake tables to use custom disk configurations — Introduces settings allowed_disks_for_table_engines and datalake_disk_name to let Iceberg and Delta Lake tables use user-specified disks instead of default ones. Enables storing datalake data on custom local or S3 disks, providing greater storage flexibility. (settings allowed_disks_for_table_engines, datalake_disk_name) (introduced in 25.9) #86778
    • e.g. CREATE TABLE test ENGINE = Iceberg('path/inside/disk') SETTINGS datalake_disk_name = 'my_disk';
  • Implement expire_snapshots for Iceberg tables — Adds the ALTER TABLE ... EXECUTE expire_snapshots('<timestamp>') command to expire old Iceberg snapshots and clean up associated files. Enables lifecycle management of Iceberg table snapshots directly from ClickHouse. (introduced in 26.3) #97904
    • e.g. ALTER TABLE iceberg_table EXECUTE expire_snapshots('2025-01-01 00:00:00');
  • Support ORDER BY in CREATE for Iceberg and sorting in INSERT — Enables specifying an ORDER BY clause in CREATE TABLE for Iceberg tables and supports sorted inserts into Iceberg. Improves data organization and query performance in Iceberg tables by allowing a defined sort order. (introduced in 25.12) #89916
    • e.g. CREATE TABLE t (id Int32) ENGINE = Iceberg S3(...) ORDER BY id;
  • Multistage PREWHERE for ParquetReaderV3 — Implemented multi-stage PREWHERE in ParquetReaderV3, splitting prewhere conditions into multiple steps to improve filter effectiveness for data lake formats (Iceberg, Delta Lake, Hudi). Significantly boosts query performance on data lakes by reducing the amount of data read after early filtering. (introduced in 26.1) #89101
  • Add ALTER UPDATE support for Iceberg tables — Adds the ability to perform UPDATE mutations on Iceberg table engine, previously only DELETE was supported. Enables full mutation support for Iceberg tables in ClickHouse, making them more flexible for data modification. (introduced in 25.9) #86059
    • e.g. ALTER TABLE iceberg_table UPDATE col = val WHERE condition

Integrations

  • Add NATS JetStream support to NATS engine — Allows users to specify nats_stream and nats_consumer settings in the NATS table engine to consume messages from NATS JetStream streams. Enables consumption from JetStream, extending ClickHouse’s message ingestion capabilities. (settings nats_stream, nats_consumer) (introduced in 25.9) #84799
    • e.g. CREATE TABLE test.nats (key UInt64, value UInt64) ENGINE = NATS SETTINGS nats_url = 'nats1:4444', nats_stream = 'test_stream', nats_consumer_name = 'test_consumer', nats_subjects = 'test_subject', nat
  • New setting to skip envelope bytes in Kafka messages for schema registries — Adds the ‘kafka_schema_registry_skip_bytes’ setting to skip a specified number of header bytes (e.g., 5 for Confluent, 19 for AWS Glue) before parsing the Kafka message payload. Enables ClickHouse to consume messages from schema registries that add metadata headers without requiring preprocessing or custom deserializers. (settings kafka_schema_registry_skip_bytes) (introduced in 25.11) #89621
    • e.g. CREATE TABLE ... ENGINE = Kafka ... SETTINGS kafka_schema_registry_skip_bytes = 19;
  • Add setting for Arrow Flight descriptor type for Dremio compatibility — Adds the arrow_flight_request_descriptor_type setting to switch between path and command descriptors, enabling compatibility with Dremio and similar Arrow Flight servers. Allows ClickHouse to connect to Dremio and other servers that require command-style descriptors. (settings arrow_flight_request_descriptor_type) (introduced in 25.11) #89523
    • e.g. SET arrow_flight_request_descriptor_type = 'command';
  • Add Prometheus HTTP Query API support — Enables Prometheus HTTP Query API handlers (/api/v1/query_range and /api/v1/query) via a new configuration rule type ‘query_api’ in the section. Allows ClickHouse to serve as a Prometheus datasource, enabling PromQL queries on TimeSeries tables. (introduced in 25.11) #86132
    • e.g. <prometheus><rule type='query_api' ...></rule></prometheus>

S3Queue

  • Add move and tag actions for processed files in S3/Azure Queue — Extends the after_processing setting of S3Queue and AzureQueue tables with move (relocate processed file) and tag (add key‑value tags) actions. Enables more flexible post‑processing pipelines for queue‑based ingestion from object storage. (introduced in 25.12) #72944
    • e.g. CREATE TABLE queue (name String, value UInt32) ENGINE = S3Queue('s3://...') SETTINGS mode = 'unordered', after_processing = 'keep';

Formats

  • New Buffers format for lightweight binary I/O — Introduces the Buffers format that serializes data like Native but without column names, types, or metadata, reducing overhead for bulk transfers. Provides a more efficient binary format for scenarios where schema is known externally, lowering transfer size. (introduced in 25.12) #84017
    • e.g. SELECT number, toString(number) FROM numbers(5) FORMAT Buffers

Operations

  • Add settings to limit skipped unavailable shards — Introduces max_skip_unavailable_shards_num and max_skip_unavailable_shards_ratio settings to limit how many shards can be silently skipped when skip_unavailable_shards is enabled. If the threshold is exceeded, a TOO_MANY_UNAVAILABLE_SHARDS exception is thrown instead of returning incomplete results. Prevents returning incomplete query results without notification when many shards are unavailable, giving operators control over data completeness guarantees. (settings max_skip_unavailable_shards_num, max_skip_unavailable_shards_ratio) (introduced in 26.3) #99369
    • e.g. SET skip_unavailable_shards = 1; SET max_skip_unavailable_shards_num = 5; SET max_skip_unavailable_shards_ratio = 0.1;
  • Max-min fair scheduler for concurrency control — Introduces a max-min fair scheduler for concurrency control that allocates CPU slots more fairly under high oversubscription, preventing short queries from being starved by long-running queries. Improves query fairness and responsiveness in high-concurrency workloads. (introduced in 26.1) #94732
    • e.g. concurrent_threads_scheduler: max_min_fair
  • Add files column to system.parts for part file count — Adds a files column to the system.parts table that shows the number of files in each data part. Enables easier monitoring of storage efficiency and merge behavior per part. (introduced in 26.1) #94337
    • e.g. SELECT name, rows, marks, bytes, files FROM system.parts WHERE database = 'default' AND table = 'github_events'
  • Add restore_access_entities_with_current_grants setting — Adds a server setting that, when enabled, allows RESTORE to succeed even if the restoring user has fewer grants than the backup, by intersecting restored grants with the user’s grantable rights. Prevents RESTORE from failing with ACCESS_DENIED when restoring users/roles with more permissions than the restoring user can grant. (settings restore_access_entities_with_current_grants) (introduced in 26.3) #98795
    • e.g. SET restore_access_entities_with_current_grants = 1;
  • Add lazy_load_tables database setting for deferred table loading — Introduces a new database-level setting lazy_load_tables that defers table loading during database startup; a lightweight proxy is created and the real table engine loads on first access. Reduces startup time and memory usage for databases with a large number of tables. (settings lazy_load_tables) (introduced in 26.2) #96283
    • e.g. CREATE DATABASE mydb ENGINE=Atomic SETTINGS lazy_load_tables=1
  • Prevent dropping named collections still in use by tables — Introduces setting check_named_collection_dependencies (default true) that prevents DROP NAMED COLLECTION if any table depends on it. Avoids accidental data loss by protecting named collections referenced by existing tables. (settings check_named_collection_dependencies) (introduced in 26.2) #96181
  • Add startup and shutdown console log level options — Adds new configuration options to override the console log level during server startup and shutdown, enabling easier debugging of startup/shutdown issues. Allows operators to get more verbose logs during startup/shutdown without affecting normal operation log level. (settings logger.startup_console_log_level, logger.shutdown_console_log_level) (introduced in 26.2) #95919
    • e.g. Set in config.xml: <logger.startup_console_log_level>debug</logger.startup_console_log_level>
  • New setting max_insert_block_size_bytes for byte-based block formation — Introduces a new setting max_insert_block_size_bytes to control the maximum block size during insertion in bytes, working alongside max_insert_block_size_rows for finer control. Allows users to limit block sizes based on memory or file size constraints rather than only row count. (settings max_insert_block_size_bytes, max_insert_block_size_rows) (introduced in 26.1) #92833
    • e.g. SET max_insert_block_size_bytes = 104857600;
  • Add send_profile_events setting to reduce network traffic — Adds the send_profile_events setting that allows clients to disable sending of ProfileEvents packets over the native protocol, reducing network traffic when profile events are unused. Reduces unnecessary network traffic for clients that do not require profile events, improving performance in high-connection environments. (settings send_profile_events) (introduced in 25.11) #89588 #89972
    • e.g. SET send_profile_events = 0;
  • Limit number of named collections with new server settings — Adds max_named_collection_num_to_warn and max_named_collection_num_to_throw settings to control the maximum number of named collections, with a warning threshold (1000) and a hard limit (0 for unlimited). Also adds the NamedCollection metric and TOO_MANY_NAMED_COLLECTIONS error. Operators can now guard against excessive named collections that could degrade performance or cause management issues. (settings max_named_collection_num_to_warn, max_named_collection_num_to_throw) (introduced in 25.10) #87343
  • Add startup and shutdown log level configuration — New configuration options logger.startupLevel and logger.shutdownLevel allow overriding the root log level during server startup and shutdown phases. Helps debug startup/shutdown issues without enabling verbose logging permanently. (settings logger.startupLevel, logger.shutdownLevel) (introduced in 25.9) #85967
    • e.g. <logger><startupLevel>debug</startupLevel><shutdownLevel>trace</shutdownLevel></logger>
  • Add async metrics for kernel TCP buffer memory of HTTP connection pool — Introduces asynchronous metrics reporting the kernel TCP receive and transmit buffer memory (sk_rmem_alloc, sk_wmem_alloc) for HTTP connection pool sockets, including p50/p75/p90/p95 percentiles and totals per connection group. Provides deeper visibility into network memory usage, aiding in performance tuning and troubleshooting. (introduced in 26.2, 26.3) #102251 #102253
  • Distroless Docker image variants for server and keeper — Adds distroless Docker image variants tagged with -distroless for clickhouse-server and clickhouse-keeper, reducing image size and attack surface. Enhances security by providing minimal container images suitable for production. (introduced in 25.12) #101442
  • Allow custom HTTP handlers per port via config — Adds an optional key to type=http entries in , allowing each HTTP port to use a different set of HTTP routing rules defined in a separate <http_handlers_*> config section. Enables flexible request routing per HTTP port, e.g., to serve different endpoints on different ports within the same server. (introduced in 26.3) #98414
    • e.g. <type>http</type><port>8124</port><handlers>my_handlers</handlers>
  • Add system.fail_points table for failpoint inspection — Introduces system.fail_points that lists all registered failpoints, their types, and enable status, allowing dynamic introspection and management for testing. Enables easier automated testing and debugging by providing visibility into failpoints. (introduced in 26.2) #96762
    • e.g. SELECT * FROM system.fail_points
  • Introduce SYSTEM CLEAR … CACHE as clearer alias for DROP CACHE — Adds SYSTEM CLEAR … CACHE as an alias for SYSTEM DROP … CACHE to clearly indicate that caches are cleared, not disabled. Reduces confusion for operators managing caches, as the new syntax more accurately reflects the action. (introduced in 26.1) #93727
    • e.g. SYSTEM CLEAR DNS CACHE;
  • Add ClickHouse_Info metric to Prometheus /metrics — Introduced a new ClickHouse_Info metric to the Prometheus ‘/metrics’ endpoint that exposes version information as labels, enabling tracking of version distributions over time. Allows operators to monitor ClickHouse version deployments through existing Prometheus infrastructure. (introduced in 26.1) #91125
  • Add system.user_defined_functions table for UDF monitoring — Adds the system.user_defined_functions system table with columns for status, errors, configuration, and execution parameters to monitor user-defined function loading. Operators can now inspect UDF loading status and errors without relying on logs. (introduced in 26.2) #90340
    • e.g. SELECT * FROM system.user_defined_functions WHERE status != 'OK';
  • Add memory_usage to HTTP progress and summary headers — Adds a memory_usage field to X-ClickHouse-Progress and X-ClickHouse-Summary HTTP headers for real-time client-side memory consumption tracking. Enables clients to monitor query memory usage in real time, improving observability and resource management. (introduced in 25.11) #88393
  • Add configuration-based workload and resource definitions — Introduces WorkloadEntityConfigStorage to load WORKLOAD and RESOURCE definitions from the server configuration file under resources_and_workloads. Enables defining workload management entities declaratively in configuration, supporting dynamic reload without SQL statements. (introduced in 25.10) #87430
    • e.g. <resources_and_workloads><workload name="my_workload" .../></resources_and_workloads>
  • Add CPU and memory overload warnings to system.warnings — Adds warnings to the system.warnings table when CPU usage exceeds 90% or memory usage exceeds 90% for 10 minutes (thresholds configurable). Helps operators proactively monitor resource overload via a system table, improving operational visibility. (introduced in 25.9) #86838
    • e.g. SELECT * FROM system.warnings

CLI

  • ClickHouse client gains TLS SNI override option — Adds the –tls-sni-override option to clickhouse-client, allowing users to set the SNI hostname in the TLS handshake independently of the actual host. Enables connections through proxies or tunnels that require a specific SNI. (introduced in 26.1) #89761
    • e.g. clickhouse-client --host actual-host --tls-sni-override desired-sni
  • Enable OAuth login for ClickHouse Cloud via –login flag — Adds the –login flag to the ClickHouse client to authenticate with ClickHouse Cloud using OAuth device code flow and token exchange. Simplifies authentication to Cloud instances without requiring manual token management. (introduced in 25.12) #89261
    • e.g. clickhouse client --login --host https://myinstance.cloud.clickhouse.com
  • Add –semicolons_inline option to clickhouse-format — Adds a --semicolons_inline option to the clickhouse-format tool that places semicolons on the same line as the last line of the query instead of on a new line. Improves formatting convenience for use in IDEs and scripts where inline semicolons are preferred. (introduced in 25.10) #88018
    • e.g. clickhouse-format --semicolons_inline --query 'SELECT 1'
  • Add config option to swap Ctrl+R/Ctrl+T keybindings in clickhouse client — With <interactive_history_legacy_keymap>true</interactive_history_legacy_keymap>, the CLI client can now fall back to Ctrl R for regular search like before, while Ctrl T does fuzzy search. Users who prefer traditional shell-like search behavior can now customize keybindings. (introduced in 26.1) #87785
    • e.g. Set <interactive_history_legacy_keymap>true</interactive_history_legacy_keymap> in config.xml.
  • CLI client option to suppress version mismatch message — Adds --no-server-client-version-message flag to suppress the version mismatch warning message. Users can clean up CLI output when mismatched versions are intentional or non-issue. (introduced in 25.12) #87784
    • e.g. clickhouse-client --no-server-client-version-message
  • OAuth2 login for ClickHouse Cloud via –login flag — Adds a –login flag to clickhouse-client to authenticate to ClickHouse Cloud using OAuth2 device code flow or custom OAuth providers. Simplifies authentication for cloud instances without manual token management. (introduced in 25.10) #82753
    • e.g. clickhouse-client --login

Web UI

  • Add embedded ClickStack dashboard for debugging and local development — Introduces an embedded observability UI (ClickStack) accessible via /clickstack, providing logs, traces, and metrics directly from the ClickHouse server. Enables developers and administrators to debug and monitor ClickHouse locally without external tools. (introduced in 26.2) #96597
    • e.g. Open http://localhost:8123/clickstack in a browser.
  • Web UI adds download button for full results — Adds a download button in the Web UI that downloads the full result set, even if the UI only displays a portion. Allows users to export complete query results easily. (introduced in 25.11) #89768

Security

  • User impersonation via EXECUTE AS statement — Introduces the EXECUTE AS SQL statement to allow authenticated users to execute queries with the privileges and row policies of another user, controlled by the allow_impersonate_user setting and the IMPERSONATE grant. Enables secure privilege delegation and fine-grained access control in multi-user environments. (settings allow_impersonate_user; functions authenticatedUser) (introduced in 25.11) #39048
    • e.g. EXECUTE AS target_user SELECT * FROM table;
  • TOTP two-factor authentication support — Adds time-based one-time password (TOTP) as a second authentication factor for ClickHouse client connections. Enhances security by enabling two-factor authentication for database access. (introduced in 26.2) #71273
  • Automatic TLS certificate retrieval via ACME — Adds an experimental ACME client to automatically obtain and renew TLS certificates from providers like Let’s Encrypt, following RFC 8555. Simplifies TLS certificate management for ClickHouse servers, reducing manual renewal overhead. (introduced in 25.11) #66315
  • Add LDAP follow_referrals option to control referral chasing — Adds a per-server LDAP configuration option ‘follow_referrals’ (default false) to control whether the LDAP client follows referral responses, avoiding timeouts in Active Directory environments. Referral messages are moved from warn to trace log level. Prevents timeouts and hangs when using LDAP authentication with Active Directory domain-root base DN, and reduces log noise. (settings follow_referrals) (introduced in 26.3) #96765
    • e.g. <follow_referrals>false</follow_referrals>
  • Add data masking policy parser (Cloud-only) — Introduced the parser and interpreter infrastructure for Data Masking Policies, a new access control feature. Currently throws ‘SUPPORT_IS_DISABLED’ for self-managed users. Lays the groundwork for data masking policies to control column-level data visibility in ClickHouse Cloud. (introduced in 25.12) #90552

Database=Replicated

  • Allow ON CLUSTER for Replicated databases via new setting — Introduces ignore_on_cluster_for_replicated_database setting to allow DDL queries with ON CLUSTER clause to execute on Replicated databases by ignoring the cluster name. Simplifies migration from non-replicated to replicated databases without requiring DDL query changes. (settings ignore_on_cluster_for_replicated_database) (introduced in 26.1) #92872
    • e.g. SET ignore_on_cluster_for_replicated_database=1; CREATE TABLE ... ON CLUSTER 'any_cluster' ...
  • Support auxiliary ZooKeeper for DatabaseReplicated — Extends auxiliary ZooKeeper support to DatabaseReplicated, allowing it to use a non-default ZooKeeper cluster (specified via zookeeper name in the path), similar to ReplicatedMergeTree. Provides flexibility for multi-ZooKeeper deployments, reducing load on the main ZooKeeper cluster and enabling better isolation. (introduced in 26.2, 26.3) #91683 #95590
  • Async inserts now support parallel quorum — Enables parallel quorum for async inserts: data is replicated to the quorum before acknowledging, and duplicates wait for prior replication to complete. Provides strong consistency for async inserted data while maintaining high throughput. (introduced in 26.2) #93356
  • New system table database_replicas for replicated database status — Adds system.database_replicas containing information about replicated databases, similar to system.replicas for tables. Operators can now monitor replication health at the database level. (introduced in 25.9) #83408
    • e.g. SELECT * FROM system.database_replicas;

Parallel replicas

  • Automatic parallel replicas based on runtime statistics — Introduces an experimental setting to automatically execute queries using parallel replicas based on collected statistics from single-node execution, controlled by automatic_parallel_replicas_mode. Allows query performance to benefit from parallel replicas without manual opt-in for complex queries. (settings automatic_parallel_replicas_mode, automatic_parallel_replicas_min_bytes_per_replica) (introduced in 25.12) #87541
    • e.g. automatic_parallel_replicas_mode
  • Distributed index analysis for SharedMergeTree — Introduces the experimental setting distributed_index_analysis to offload index analysis to replicas via consistent hashing, improving query performance on large clusters with shared storage. Reduces query latency for large primary keys and huge data volumes on shared storage by parallelizing index analysis. (settings distributed_index_analysis) (introduced in 26.1) #86786
    • e.g. SET distributed_index_analysis = 1

Keeper

  • New ‘rcfg’ command for dynamic Keeper cluster reconfiguration — Introduces a new four-letter command rcfg that allows programmatic changes to Keeper cluster configuration via JSON, including member removal/addition, leadership transfer, and priority setting with preconditions. Enables automated cluster reconfiguration without restarts, improving operational flexibility. (introduced in 26.1) #91354
    • e.g. rcfg{"preconditions":{"leaders":[1,2]},"actions":[{"transfer_leadership":[3]},{"remove_members":[1,2]}]}
  • Add system.zookeeper_info table for ZooKeeper introspection — Introduces a new system table system.zookeeper_info that provides combined introspection metrics from all configured ZooKeeper nodes, including cluster name, host, port, connection status, latency, packet counts, leader info, and file descriptor counts. Enables comprehensive monitoring and debugging of ZooKeeper clusters directly from ClickHouse without external tools. (introduced in 26.1) #88014
    • e.g. SELECT * FROM system.zookeeper_info
  • Add SYSTEM RECONNECT ZOOKEEPER command — Adds a new SYSTEM command SYSTEM RECONNECT ZOOKEEPER to force a disconnect and reconnect to ZooKeeper/Keeper. Allows operators to rebalance connections after keeper restarts without waiting for long fallback session timeouts. (introduced in 25.10) #87318
    • e.g. SYSTEM RECONNECT ZOOKEEPER
  • HTTP API and embedded Web UI for ClickHouse Keeper — Adds an HTTP API and a built-in Web UI to ClickHouse Keeper, allowing users to interact with Keeper via REST endpoints and a browser interface for monitoring and management. Provides a convenient, out-of-the-box way to inspect and manage Keeper state without external tools, simplifying operations. (introduced in 26.1) #78181
    • e.g. keeper_server: http_control: port: 9182
  • Support ZooKeeper persistent watches in ClickHouse Keeper — Adds support for ZooKeeper persistent watches in ClickHouse Keeper, enabling more efficient watch handling with new request/response types and a feature flag. Improves Keeper’s compatibility and performance for ZooKeeper-based workloads by reducing watch-related overhead. (introduced in 25.12) #88813
  • Keeper support for ZooKeeper create2 operation — Adds support for the ZooKeeper create2 operation, which returns statistics on node creation, improving compatibility with ZooKeeper clients. Increases compatibility with ZooKeeper clients that require stat responses on create, easing migration. (introduced in 25.12) #88797
  • Add recursive cp and mv commands to Keeper client — Adds cpr (recursive copy) and mvr (recursive move) commands to the ClickHouse Keeper client for subtree operations on znodes. Enables easier management of hierarchical data in Keeper. (introduced in 25.10) #88570
    • e.g. cpr /path/source /path/dest
  • Add aggregated ZooKeeper log system table — Introduces system.aggregated_zookeeper_log table with aggregated statistics (count, latency, errors) of ZooKeeper operations grouped by session, path, and operation type, periodically flushed to disk. Provides a lightweight monitoring alternative to the detailed ZooKeeper log for production use. (introduced in 25.9) #85102
    • e.g. SELECT * FROM system.aggregated_zookeeper_log

Introspection

  • Introduce mergeTreeAnalyzeIndexes table function for index introspection — Adds a new table function mergeTreeAnalyzeIndexes that shows which parts and ranges are selected by primary key and skip indexes for a given query, enabling deep index usage analysis. Helps users understand and optimize index usage in MergeTree tables. (functions mergeTreeAnalyzeIndexes) (introduced in 26.1) #92954
    • e.g. SELECT * FROM mergeTreeAnalyzeIndexes(default, github_events, repo_name = 'ClickHouse/ClickHouse')
  • Add runtime instrumentation with LLVM XRay for production debugging — Introduces LLVM XRay-based runtime instrumentation that allows dynamic addition and removal of instrumentation points, enabling deterministic profiling and debugging in production without rebuilding ClickHouse. Operators can now profile and debug live ClickHouse instances with minimal overhead, gaining visibility into performance bottlenecks and hard-to-reproduce issues. (introduced in 25.12) #74249
    • e.g. Use system.xray_instrumentation to enable/disable instrumentation points at runtime.
  • Native macOS symbol introspection via Mach-O parsing — On macOS, ClickHouse can now parse Mach-O symbol tables to resolve addresses to symbols, exposed through SymbolIndex, addressToSymbol function, system.symbols table, and buildId. Enables debugging and introspection capabilities on macOS builds of ClickHouse, matching existing Linux support. (functions addressToSymbol) (introduced in 26.3) #99014
    • e.g. SELECT addressToSymbol(addr) FROM ...
  • Add server-side AST fuzzer settings — Introduces ast_fuzzer_runs and ast_fuzzer_any_query settings to run randomized AST mutations after query execution for testing. Helps find bugs by fuzzing queries server-side without external tools. (settings ast_fuzzer_runs, ast_fuzzer_any_query) (introduced in 26.2) #97568
    • e.g. SET ast_fuzzer_runs = 10;

Misc

  • Add experimental support for Elbrus (e2k) CPU architecture — Adds experimental support for the e2k (Elbrus-2000) CPU architecture, including CMake toolchain, architecture detection, and conditional compilation to avoid unsupported instructions. Extends ClickHouse to run on Elbrus processors, broadening deployment options for users in relevant environments. (introduced in 25.11) #90159

👆 Back to v26.3 versus 25.8 overview

Performance and optimizations

Functions

  • Move vector out of loop in reverseSplit function to avoid per-iteration allocations — Optimizes the internal implementation of the reverse_split function by moving std::vector allocation outside the loop, avoiding per-iteration memory allocations. Reduces memory allocation overhead when using functions like reverseSplit, improving query performance. (introduced in 26.2) #95178
  • Improve levenshteinDistance performance with Myers algorithm — Optimizes the levenshteinDistance function by implementing the Myers algorithm for short strings and block Myers for medium strings, achieving up to 16x speedup for short strings and 8-9% for longer strings. Significantly speeds up fuzzy string matching and similarity computations, benefiting data quality and deduplication workflows. (introduced in 26.3) #94543
    • e.g. SELECT levenshteinDistance('kitten', 'sitting')
  • Optimize distinctJSONPaths to read only paths from data parts — Optimizes the distinctJSONPaths aggregate function to read only JSON paths from data parts instead of the entire JSON column, reducing I/O and improving query performance. Speeds up queries that need only distinct JSON paths, especially on large datasets with JSON columns. (introduced in 25.12) #92711
    • e.g. SELECT distinctJSONPaths(json_col) FROM table;
  • Improve performance of tokens and related functions — Refactors tokenization in tokens, hasAllTokens, and hasAnyTokens to use a callback pattern, eliminating per-row heap allocations and reducing virtual function overhead. Makes string token analysis significantly faster for large datasets. (introduced in 25.10) #88416

MergeTree-related

  • Optional .size subcolumn for String columns in MergeTree — Adds an optional .size subcolumn for top-level String columns in MergeTree tables, improving compression and enabling efficient subcolumn access; introduces settings for serialization version and empty string optimization. Reduces storage footprint and speeds up length queries on String columns. (settings optimize_empty_string_comparisons, serialization_info_version, string_serialization_version) (introduced in 25.10) #82850
    • e.g. SELECT col.size FROM table;
  • MergeTree PREWHERE optimized with in-place filtering — Implements in-place filtering for MergeTree PREWHERE to reduce memory allocation, improving performance for low-selectivity filters. Reduces memory overhead and speeds up queries using PREWHERE with low selectivity filters. (introduced in 25.12) #87119
  • Batch ZooKeeper requests during clone replica for many parts — Batches ZooKeeper create requests into multi requests when cloning a replica, with a new setting clone_replica_zookeeper_create_get_part_batch_size to control batch size. Significantly improves clone replica performance for tables with many parts. (settings clone_replica_zookeeper_create_get_part_batch_size) (introduced in 26.2) #94847
  • Heuristic to reduce merge widths based on partition fullness — Introduces a heuristic that dynamically lowers max_parts_to_merge_at_once when a partition’s part count approaches parts_to_throw_insert, controlled by the new setting merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_once. Helps prevent TOO_MANY_PARTS errors by performing more narrower merges when a partition is near its part limit, at the cost of increased write amplification. (settings merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_once) (introduced in 25.12) #91163
    • e.g. SET merge_selector_enable_heuristic_to_lower_max_parts_to_merge_at_once = 1;
  • Optimize vertical merge after lightweight delete — Improves vertical merge performance after lightweight deletes by applying delete filtering during the merge instead of forcing horizontal merge, reducing memory usage. Reduces memory consumption and improves merge speed in tables with lightweight deletes. (settings vertical_merge_optimize_lightweight_delete) (introduced in 25.9) #86169
  • Use skip indexes for WHERE clauses with OR conditions — Extends skip index analysis to WHERE clauses with mixed AND/OR conditions, controlled by setting use_skip_indexes_for_disjunctions (default: on). Previously only pure conjunctions were supported. Queries with complex filter logic can now leverage skip indexes, reducing full table scans and improving performance. (settings use_skip_indexes_for_disjunctions) (introduced in 25.12) #75228
    • e.g. SELECT * FROM table WHERE (col1 = 1) OR (col2 = 2)
  • Fix key condition analysis for DateTime64 primary keys with integer constants — Corrects key condition analysis to properly handle DateTime64 primary keys compared with integer constants, enabling granule pruning that was previously missing. Significantly improves query performance on DateTime64 primary keys by allowing index-based granule skipping instead of full scans. (introduced in 26.3) #98410
    • e.g. SELECT * FROM table WHERE dt = 1700000000; -- now uses index efficiently
  • Partial materialized text index read optimization — Previously, text index direct read optimization required all parts to have a materialized text index. This change allows parts with materialized indexes to use the optimization, while parts without fall back to executing the original filter expression. Improves query performance for tables where only some parts have materialized text indexes. (introduced in 26.2) #96411
  • Enable marks caching and disable direct IO for MergeTreeLazy reader — Enables saving marks in cache and disables direct IO for the MergeTreeLazy reader, improving read performance. Reduces disk I/O and speeds up reads for MergeTree tables using lazy materialization. (introduced in 25.9) #90371
  • Cache marks and avoid direct IO in MergeTreeLazy reader — Enables caching of marks and disables direct IO for the MergeTreeLazy reader, improving read performance. Reduces IO overhead when reading from MergeTree tables. (introduced in 25.10) #87989
  • Zero-copy final aggregation for any/anyLast on large types — Reduces memory allocation and copy for SimpleAggregateFunction(anyLast) columns during SELECT … FINAL from AggregatingMergeTree by using reference-based, zero-copy final merge. Improves memory efficiency and speed for queries using FINAL on tables with large string, array, or map types. (introduced in 25.10) #84428
    • e.g. SELECT * FROM table FINAL

Performance

  • Join reorder uses statistics for bushy join trees — Integrates table statistics from MergeTree data parts into the join order optimizer to enable bushy join trees, achieving dramatic speedups (e.g., TPC-H Q5 from 5s to 100ms). Massively improves query performance for complex joins by using accurate statistics to choose optimal join order. (settings allow_statistics_optimize) (introduced in 25.9) #86822
    • e.g. SET allow_statistics_optimize = 1; SET query_plan_optimize_join_order_limit = 10
  • Rewrite ANY JOIN to SEMI/ANTI and FULL JOIN to LEFT/RIGHT based on filter conditions — Optimizes JOINs by converting LEFT/RIGHT ANY JOIN to SEMI/ANTI and FULL ALL JOIN to LEFT ALL/RIGHT ALL when filter conditions guarantee certain rows are never matched, controlled by setting query_plan_convert_any_join_to_semi_or_anti_join. Significantly improves query performance for common JOIN patterns by selecting more efficient join types. (settings query_plan_convert_any_join_to_semi_or_anti_join) (introduced in 25.9) #86028
    • e.g. SELECT * FROM large_table LEFT ANTI JOIN small_table USING (id)
  • Trim CachedOnDiskReadBufferFromFile size 50x, saving up to 90 GiB RAM — Reduces memory usage of CachedOnDiskReadBufferFromFile by 50x by removing per-file-segment profiling counters, using global counters instead. Drastically lowers RAM consumption for file cache buffers, saving up to 90 GiB in large deployments. (introduced in 26.2) #96098
  • ANTI JOINs get runtime filter speedup — Adds support for JOIN runtime filters for ANTI JOINs, significantly improving performance (e.g., TPC-H Q21 drops from 29s to 12.8s). The implementation is also refactored to reduce lock contention. Greatly speeds up ANTI JOIN queries, making them comparable to INNER JOIN performance. (introduced in 25.12) #89710
  • Push more filters down joins — Allows constant predicates to be pushed further in JOIN execution, removing a check that prevented pushdown when one side had a constant column. Improves query performance for JOINs with filter conditions. (introduced in 26.1) #85556
    • e.g. SET use_join_disjunctions_push_down;
  • 8x faster SELECT on tables with 10K+ parts via reduced lock contention — Reduces lock contention on the data parts mutex by introducing shared locks for read-only access and caching shared parts list for queries, enabling up to 8x faster SELECT queries with heavy partition pruning on tables with 10K+ parts. Dramatically improves performance for partition-heavy workloads, enabling faster queries on large tables. (introduced in 25.11) #85535
  • Extend JIT compilation to more functions — Enables JIT compilation for decimal and bigint types and additional SQL functions, and changes the default of min_count_to_compile_expression to 0. Speeds up queries with many function evaluations, though compilation overhead may increase for very short queries. (introduced in 26.1) #73509
    • e.g. SELECT caseFoldUTF8('Straße') = caseFoldUTF8('STRASSE')
  • Optimize text index dictionary with renamed tokens cache — Renames the text index dictionary block cache to tokens cache and adds a new bulk get method, improving text index analysis performance. Reduces latency for text index operations; existing configurations using old cache setting names must be updated. (settings text_index_tokens_cache_policy, text_index_tokens_cache_size, text_index_tokens_cache_max_entries, text_index_tokens_cache_size_ratio, use_text_index_tokens_cache) (introduced in 26.3) #97519
  • Reduce INSERT/merge memory usage for wide tables with adaptive write buffers — Introduces adaptive write buffers that reduce memory usage during INSERTs and merges for tables with many columns, enabled when column count exceeds min_columns_to_activate_adaptive_write_buffer (default 500). Also adds support for encrypted disks. Lowers memory consumption for very wide tables during writes and merges. (settings min_columns_to_activate_adaptive_write_buffer) (introduced in 26.1) #92250
  • Parallelize non-joined row processing in ParallelHashJoin — Speeds up RIGHT/FULL JOINs by processing non-joined rows from the right table in multiple threads instead of one, controlled by the new setting ‘parallel_non_joined_rows_processing’ (enabled by default). Provides significant performance improvement for joins with complex predicates on large tables. (settings parallel_non_joined_rows_processing) (introduced in 26.2) #92068
    • e.g. SET parallel_non_joined_rows_processing = 1;
  • Implement DPsize join reordering for INNER JOINs — Introduces a new experimental setting query_plan_optimize_join_order_algorithm that allows using DPsize algorithm for better join order optimization, with fallback to greedy. Improves query performance for complex queries with many INNER JOINs by finding more optimal join orders. (settings query_plan_optimize_join_order_algorithm) (introduced in 25.12) #91002
    • e.g. SET query_plan_optimize_join_order_algorithm='dpsize,greedy';
  • High-performance tokenization via forEachToken callback interface — Refactors tokenization to a new high-performance forEachToken callback interface, replacing the old iterator-style API to support SIMD and stateful tokenizers. Provides faster tokenization for text processing workloads, enabling better performance in full-text search and text analysis. (functions {'name': 'tokensForLikePattern', 'kind': 'scalar'}) (introduced in 26.3) #90268
  • Optimize ORDER BY … LIMIT N queries with skip indexes and dynamic filtering — Implements optimizations using minmax skip index and dynamic threshold filtering to skip irrelevant granules, reducing rows processed for top-K queries; adds settings use_skip_indexes_for_top_k, use_top_k_dynamic_filtering, query_plan_max_limit_for_top_k_optimization. Significantly reduces query latency and memory for ORDER BY LIMIT queries. (settings use_skip_indexes_for_top_k, use_top_k_dynamic_filtering, query_plan_max_limit_for_top_k_optimization) (introduced in 25.12) #89835
  • Optimize read order through joins for better performance — Introduces a new optimization to preserve read order from the left table in LEFT/INNER JOINs, allowing subsequent steps to benefit; adds setting query_plan_read_in_order_through_join. Reduces unnecessary re-sorting after joins, improving query performance. (settings query_plan_read_in_order_through_join) (introduced in 25.12) #89815
  • Add cache for text index posting lists — Introduces a cache for text index posting lists (the largest data component) to improve performance on consecutive queries; new settings control cache policy, size, and enablement (disabled by default). Significantly reduces latency and increases throughput for repeated text index queries when the cache is enabled. (settings text_index_postings_cache_policy, text_index_postings_cache_size, text_index_postings_cache_max_entries, text_index_postings_cache_size_ratio, use_text_index_postings_cache) (introduced in 25.11) #88912
  • Text index dictionary block cache for faster token lookups — Improves text index performance by caching dictionary blocks and using hash tables for token lookups instead of binary search. Adds configurable cache settings. Significantly reduces latency and increases throughput for text index queries, especially with large numbers of queries. (settings use_text_index_dictionary_cache, text_index_dictionary_block_cache_policy, text_index_dictionary_block_cache_size, text_index_dictionary_block_cache_max_entries, text_index_dictionary_block_cache_size_ratio) (introduced in 25.11) #88786
    • e.g. SET use_text_index_dictionary_cache = 1;
  • Improve filtering with text index hint for like/equals/has — Adds a preliminary filter hint from the text index to improve filtering performance for predicates using functions like like, equals, has. Controlled by new settings query_plan_text_index_add_hint and text_index_hint_max_selectivity. Also improves text index usage for Map columns. Significantly speeds up queries with text-based filters on columns with text index. (settings query_plan_text_index_add_hint, text_index_hint_max_selectivity) (introduced in 25.12) #88550
    • e.g. SET query_plan_text_index_add_hint = 1;
  • Distributed execution: split tasks by row groups for better parallelism — Improves task splitting in CLUSTER table function from file-level to row-group level, reducing skew and improving parallelism for large Parquet files. Queries on large Parquet files via cluster table function become faster and more balanced across nodes. (settings cluster_table_function_split_granularity, cluster_table_function_buckets_batch_size) (introduced in 25.11) #87508
  • Optimize LIKE with prefix/suffix by rewriting to startsWith/endsWith — A new setting optimize_rewrite_like_perfect_affix (default on) rewrites LIKE expressions with fixed prefix or suffix into startsWith or endsWith functions for better performance. Improves query performance for LIKE patterns with leading/trailing wildcards. (settings optimize_rewrite_like_perfect_affix) (introduced in 25.10) #85920
    • e.g. SELECT * FROM t WHERE name LIKE 'prefix%' -- automatically rewritten to startsWith(name, 'prefix')
  • Push down disjunction JOIN predicates to inputs — Introduces optimization that pushes OR-connected parts of JOIN conditions down to the respective input sides, enabling early filtering. Controlled by setting use_join_disjunctions_push_down (default off). Can significantly reduce data read and speed up JOIN queries with OR conditions. (settings use_join_disjunctions_push_down) (introduced in 25.10) #84735
    • e.g. SET use_join_disjunctions_push_down = 1; SELECT ... FROM t1 JOIN t2 ON (t1.a = 1 AND t2.b = 2) OR (t1.a = 2 AND t2.b = 1);
  • Fix INSERT performance regression when deduplicate_insert=enable — Optimizes data hash computation during INSERT by deferring it from squashing to the sink stage and using batch column hashing via updateHashWithValueRange, reducing overhead from ~2.5s to ~0.5s for 5M rows with 22 columns. Fixes a significant performance regression caused by the default deduplication setting, improving INSERT throughput. (introduced in 26.2) #101914
  • Fix INSERT performance regression with deduplicate_insert enabled — Defer data hash computation from squashing to sink and use batch column hashing, reducing overhead from ~2.5s to ~0.5s for 5M rows with 22 columns. Restores INSERT performance when deduplication is enabled, avoiding significant slowdown. (introduced in 26.3) #101736
  • Avoid unnecessary computation of String .size subcolumn during enumeration — Avoids computing the .size subcolumn for String columns when not needed during subcolumn enumeration. Reduces overhead for queries that enumerate subcolumns, improving performance. (introduced in 26.3) #100600
  • Optimize PrefetchingHelper with integer arithmetic — Replaces floating-point math with pure integer arithmetic in PrefetchingHelper::calcPrefetchLookAhead, reducing cycle overhead and improving instruction cache layout during aggregation loops. Provides approximately 3.5% performance improvement in high-cardinality aggregations. (introduced in 26.3) #99327
  • Reduce cache contention in RIGHT and FULL JOINs — Adds a check-then-store pattern for JoinUsedFlags atomic flags to avoid unnecessary memory store operations when the flag is already set. Significantly improves performance in high-contention scenarios for RIGHT and FULL joins. (introduced in 26.3) #99274
  • Read-in-order optimization for reverse-order reads — Extends the read_in_order_use_virtual_row optimization to support reverse-order reads, reducing unnecessary data scanning in ORDER BY DESC + LIMIT queries on MergeTree tables. Speeds up descending order queries with LIMIT, improving query performance. (introduced in 26.3) #99198
    • e.g. SELECT * FROM table ORDER BY timestamp DESC LIMIT 10;
  • Optimise INTERSECT ALL and EXCEPT ALL with branch removal (~13% speedup) — Removes a branch in the row filtering logic for INTERSECT ALL and EXCEPT ALL, simplifying the inner loop and reducing query latency by about 13%. Faster execution of set operations. (introduced in 26.3) #99097
  • Enable read-in-order and key pruning for CAST to Nullable(T) — Allows read-in-order optimization and primary-key pruning when the CAST target type is Nullable(T) and the conversion is monotonic, enabling efficient ORDER BY and filter pushdown for expressions like x::Nullable(UInt64). Improves query performance for tables with primary keys on columns that are cast to Nullable types, enabling faster order-by and filtering via index usage. (introduced in 25.12, 26.1, 26.2, 26.3) #98482 #99048 #99050 #99052
    • e.g. SELECT * FROM table WHERE x::Nullable(UInt64) > 500000 ORDER BY x::Nullable(UInt64)
  • Add compareTrackAt method to IColumn for sorted merges — Adds a new method compareTrackAt to the IColumn interface, enabling more efficient comparisons during sorted merge operations. Improves performance of sorted merges by providing a dedicated comparison track function, reducing overhead in merge processing. (introduced in 26.3) #99013
  • Reduce memory and improve performance for parallel window functions and arrayFold — Replaces heuristic average-size preallocation with exact row counts and skips empty output chunks in scatter transforms, reducing memory usage and page-fault pressure. Improves query stability under tight memory limits and speeds up window function and arrayFold workloads. (introduced in 26.3) #98892
  • Optimize avgWeighted aggregation by up to 27% for Nullable inputs — Uses local accumulators in avgWeighted aggregate function to avoid per-row store-forwarding through aggregate state, improving performance for Nullable inputs by up to 27%. Faster aggregation for weighted averages. (introduced in 26.3) #98793
  • Enable optimize_syntax_fuse_functions by default — Changes the default value of the setting optimize_syntax_fuse_functions to true, enabling fusion of aggregate functions like sumIf into sum(if(…)) automatically. Automatically improves performance for queries using conditional aggregates without requiring manual rewriting. (introduced in 26.3) #98424
    • e.g. SELECT sumIf(x, cond) FROM t; -- now automatically rewritten to sum(if(cond, x, 0))
  • Improve performance of queries with constant long arrays or maps — Improves performance of queries with constant expressions that generate very long arrays or maps by removing redundant type calculations. Speeds up queries involving large constant array/map constructions. (introduced in 26.3) #98287
  • Improve text index analysis for combined indexed/non-indexed conditions — Fixes early exit optimization in text index analysis that was incorrectly disabled when queries combine indexed and non-indexed columns, improving performance (backport to 26.2). Speeds up queries that use text indexes alongside non-indexed filters. (introduced in 25.12, 26.2) #98182 #98184
  • Improve text index analysis with combined conditions — Improves performance of text index analysis for queries with combined conditions involving both indexed and non-indexed columns by correctly determining when all tokens must be read. Speeds up queries with full-text search on mixed indexed and non-indexed columns. (introduced in 26.3) #98096
  • Skip storing original block for single-token sync inserts — For synchronous inserts, the original block was always stored for deduplication. This optimization skips storing the full block for single-token sync inserts, computing the hash on the fly to save memory. Reduces memory usage during synchronous inserts, improving overall server efficiency. (introduced in 26.2, 26.3) #96661 #97942
  • Speed up LZ4 decompression on ARM by removing slower NEON path — Removes a slower NEON code path for 16-byte blocks during LZ4 decompression on ARM, replacing it with a faster scalar fallback. This improves decompression speed, especially on Graviton 4 instances. Faster decompression means improved query performance on ARM-based infrastructure. (introduced in 26.3) #97774
  • Optimizer swaps join sides for ANTI, SEMI, and FULL joins using statistics — Enables the optimizer to swap the build and probe sides of ANTI, SEMI, and FULL joins based on table size statistics, choosing the smaller table as the build side. Improves join performance for these join types, especially when table sizes differ. (introduced in 26.3) #97498
  • Optimize minmax skip index computation during INSERT — Removed unnecessary data copy and enabled vectorized min/max calculation using std::minmax for numeric columns during minmax skip index updates on INSERT. Reduces minmax skip index overhead from ~30% to ~1.6%, significantly improving INSERT performance. (introduced in 26.2) #97392
  • Replace hardcoded cache line size with arch-specific constant — Replaces the hardcoded cache line size of 64 with an architecture-specific constant CH_CACHE_LINE_SIZE, fixing performance regressions on ARM caused by LLVM’s inflated hardware_destructive_interference_size. Improves performance on ARM architectures by using the correct cache line size, and adds a style check to prevent regressions. (introduced in 26.3) #97357
  • Optimize PrimaryKeyExpand in FINAL queries to skip unnecessary granule scanning — If a FINAL query uses a primary key condition for filtering followed by skip indexes, the PrimaryKeyExpand processing step now only checks the initial shortlisted primary key ranges for intersection, preventing unnecessary granule scanning. Improves query performance for FINAL queries that use skip indexes, reducing I/O and CPU usage. (introduced in 25.12) #97061
  • Apply lazy materialization to all UNION ALL branches — Extends the lazy materialization optimization to every branch of a UNION ALL query, not just the first one, reducing I/O for multi-branch sorted limited reads. Faster UNION ALL queries combining sorted reads from multiple MergeTree tables. (introduced in 26.2) #96832
  • LZ4 decompression 1.46x faster for 32-byte blocks on x86 — Optimizes LZ4 decompression for 32-byte blocks using SSSE3 SIMD instructions, achieving up to 1.46x speedup on large files. Improves performance for compressed data workloads, especially with small block sizes. (introduced in 26.2) #96778
  • Add minmax and bloom_filter indexes on system log tables for faster filtering — Adds minmax secondary indexes on time columns and bloom_filter indexes on query_id/initial_query_id columns to MergeTree-based system log tables (e.g., query_log, trace_log). Speeds up time-range queries and query ID lookups on system log tables, reducing latency when diagnosing issues. (introduced in 26.2) #96712
  • Improve build time by avoiding boost/multiprecision headers on ARM — Avoids including heavy boost/multiprecision headers on platforms with adequate long double (e.g., ARM), reducing build time by about 7.9%. Faster compilation for developers and build systems. (introduced in 26.2) #96633
  • Skip storing original_block in DeduplicationInfo when deduplication disabled — Avoids storing original_block in DeduplicationInfo when deduplication is not enabled, reducing memory usage during INSERTs. Lowers peak memory consumption for insert-heavy workloads without deduplication. (introduced in 26.2) #96503
  • Enable runtime filters for RIGHT OUTER JOINs — Extends runtime join filter optimization to RIGHT OUTER JOINs (ALL and ANY), reducing memory usage and speeding up queries. Improves performance for queries using RIGHT OUTER JOINs, which previously could not benefit from this optimization. (introduced in 26.2) #96183
  • Optimize HashTable resize for empty tables — HashTable::resize now skips copying data when the table is empty, avoiding unnecessary overhead during resize operations like set_index construction. Improves performance for operations that frequently resize empty HashTables. (introduced in 26.2) #96180
  • Reduce CachedOnDiskReadBufferFromFile memory usage by 50x — Removes per-file-segment profiling counters from CachedOnDiskReadBufferFromFile, reducing its structure size by ~50x and saving up to 90 GiB of RAM in large deployments. Significantly lowers memory footprint for systems with many concurrent reads using the filesystem cache. (introduced in 25.11) #96175
  • Revert 64-byte alignment for ProfileEvents::Counter to reduce memory usage — Removes 64-byte alignment from ProfileEvents::Counter, significantly reducing memory consumption (~4x less) for the Counters object. Lowers memory footprint, especially in deployments with many counters, saving tens of GiB. (introduced in 26.2) #96097
  • Batch decimal conversion speeds up casting by hoisting loop-invariant computations — Optimizes decimal type conversions by adding batch processing functions that hoist scale comparison and multiplier computation outside the loop, reducing per-element overhead. Faster casting between decimal types, especially in bulk operations. (introduced in 26.3) #95923
  • Speed up uniq over numeric types with batched hash inserts — Optimizes the uniq aggregate function for numeric types by batching 8 values at a time into the hash set, achieving ~1.23x speedup. Faster COUNT(DISTINCT) queries on numeric columns with no additional configuration. (introduced in 26.2) #95904
  • Postpone PREWHERE optimization for runtime filter pushdown — Defers PREWHERE optimization until after JOIN runtime filters are added, so runtime filters can also be pushed into the PREWHERE step. Improves query performance for joins with runtime filters by enabling better filter pushdown. (introduced in 26.2) #95838
  • Optimize PrimaryKeyExpand in FINAL queries with skip indexes — In FINAL queries that use a primary key filter followed by skip indexes for other conditions, PrimaryKeyExpand now only checks the initial primary key ranges for intersection, avoiding unnecessary granule scans. Reduces query latency and I/O for FINAL queries with multiple filters, particularly on large MergeTree tables. (introduced in 26.2) #94903
  • Improved devirtualization with linker flags — Adds linker options to improve devirtualization during ThinLTO compilation, leading to general performance improvements across queries. Provides a performance boost with no user configuration changes. (introduced in 26.2) #94737
  • Optimize memory for named tuple AST objects — Stores named tuple element names directly as strings instead of using AST literal nodes, reducing memory consumption for queries and metadata involving named tuples. Reduces memory usage for queries and schemas with named tuples, especially beneficial for large schemas. (introduced in 26.2) #94704
  • Optimize Enum AST memory with specialized node — Introduces ASTEnumDataType to store enum values as (string, integer) pairs instead of ASTLiteral children, reducing memory consumption for large enums. Reduces memory footprint for queries involving large Enum types. (introduced in 26.1) #94178
  • Optimize read-in-order by skipping constant ORDER BY columns from WHERE clause — The read-in-order optimization now ignores ORDER BY columns that are constant due to WHERE conditions, allowing efficient reverse-order reads (e.g., InReverseOrder) instead of a full sort for queries like WHERE tenant=‘42’ ORDER BY tenant, event_time DESC. Significantly improves performance for multi-tenant queries by enabling optimal read direction without sorting. (introduced in 26.1) #94103
    • e.g. SELECT * FROM events WHERE tenant='42' ORDER BY tenant, event_time DESC
  • Skip reading left side of hash join when right side is empty — Optimizes hash joins by skipping reading the left side entirely when the right side is empty, instead of reading until first non-empty block. Improves performance and reduces memory consumption for queries with empty right-side tables. (introduced in 26.1) #94062
  • Reduce ASTLiteral memory footprint by removing optional token iterators — Removes std::optional fields from ASTLiteral, storing token information only when needed for highlighting and VALUES parsing. Reduces memory usage for query ASTs, especially beneficial for complex or numerous queries. (introduced in 26.2) #93974
  • Optimize isValidASCII for all-ASCII inputs — Reapplied an optimized implementation of isValidASCII using an optimistic byte check (OR all bytes, compare to 0x7F) yielding 1.7–4.4x speedup for common all-ASCII inputs. Queries using isValidASCII on ASCII-heavy data execute significantly faster without any behavioral change. (introduced in 26.1) #93611
  • Optimize isValidASCII for all-ASCII input — Optimizes isValidASCII function for positive outcomes (all-ASCII) with up to 4.4x speedup, while non-ASCII cases see a slight slowdown. Accelerates ASCII detection in workloads with predominantly ASCII text. (introduced in 26.1) #93347
  • Optimize uniqExact for consecutive duplicates — Improves performance of uniqExact aggregation by skipping insertion of consecutive identical elements, achieving up to 35% faster execution on real queries. Faster aggregation for workloads with repeated values, reducing query time. (introduced in 26.1) #93268
  • Use fastrange for parallel partitioning in query pipeline — Replaces modulus-based partitioning with the fastrange (Daniel Lemire) method for data distribution in the query pipeline, improving performance for parallel sorting and JOINs. Faster query execution for parallel operations on large datasets. (introduced in 26.1) #93080
  • Optimize full-text search by reducing searched tokens with sparseGrams — Improves performance of full-text search using text index with sparseGrams tokenizer by reducing the number of tokens searched in the index through compaction and filtering of already covered tokens. Faster full-text search queries, especially on large text datasets. (introduced in 26.1) #93078
  • Extend join condition pushdown to ANY, SEMI, ANTI joins — Pushes filters from the ON clause to the appropriate side when the filter references only one side, now also for ANY, SEMI, and ANTI joins. For ANTI joins, the condition is negated to maintain semantics. Reduces data processed during joins, improving query performance for these join types. (introduced in 26.1) #92584
  • Optimize granule skipping for pointInPolygon with large polygons — Improves granule skipping for pointInPolygon queries with large polygons and fixes an index analysis error during primary key pruning. Significantly speeds up geospatial queries on large polygon datasets. (introduced in 26.3) #91633
  • Avoid needless parts filtering by virtual columns — Skips expensive parts filtering via virtual columns when no virtual columns are used in the WHERE clause. Improves query performance by avoiding unnecessary computation on virtual columns. (introduced in 26.1) #91588
  • Speed up sorting of single numeric block via dynamic dispatch — Adds dynamic dispatch to the column comparison function, enabling AVX2/AVX512BW code paths for sorting single numeric blocks, improving sorting throughput. Delivers faster sorting performance for numeric data, benefiting queries with ORDER BY and other sorting operations. (introduced in 25.12) #91213
  • Speed up column-to-bool conversion with AVX2/AVX512BW dynamic dispatch — Speeds up converting columns to boolean values (used in WHERE clauses) using AVX2 and AVX512BW dynamic dispatch optimizations. Improves query performance for WHERE clauses that involve implicit or explicit boolean conversions. (introduced in 25.12) #91203
  • Optimize memory usage of fractional LIMIT/OFFSET — Optimizes performance and memory usage for fractional LIMIT and OFFSET by early-detecting blocks that can be dropped or pushed to output while still reading, reducing peak memory. Reduces memory consumption for queries with fractional limits and offsets, improving stability and enabling larger datasets. (introduced in 26.1) #91167
  • Fix Parquet v3 Prefetcher to use faster random read logic — Fixes the Parquet v3 Prefetcher to use the faster readBigAt path for object storage reads by adding missing method overrides in wrapper buffers. Improves I/O performance for Parquet reads from S3/Azure/GCS. (introduced in 26.1) #90890
  • Speed up T64 decompression via SIMD dynamic dispatch — Optimized T64 decompression by using SIMD dynamic dispatch (AVX512BW/AVX2) for reverseTranspose, achieving >2x throughput improvement. Faster data decompression improves query performance, especially for workloads using T64 codec. (introduced in 25.12) #90610
  • JIT: Avoid unnecessary result column zero-initialization — Optimizes JIT functions by not initializing result columns to zero unnecessarily, saving CPU cycles. Yields ~25% throughput improvement for certain queries using JIT compilation. (introduced in 25.12) #90449
  • Use advanced SIMD for logical functions via dynamic dispatch — Adds AVX512BW and AVX2 SIMD implementations for logical functions (and, or, xor) with runtime dispatch to select the best implementation. Improves performance of logical operations on supported hardware. (introduced in 25.12) #90432
  • Speed up minmax index load by caching serialization and datatype pointers — Caches serialization and datatype pointers in minmax index granules to avoid repeated computations during deserialization, reducing latency for large minmax indexes with millions of granules. Improves query planning performance for tables with large minmax indexes. (introduced in 25.12) #90428
  • Optimize topK aggregate function performance — Adds batch processing for numeric types in topK, fixes potential overflow in SpaceSaving alpha values that could cause incorrect results, and improves accuracy on drops/merges. Faster and more accurate topK computations for numeric data. (introduced in 25.12) #90091
  • Increase lazy materialization limit default from 10 to 100 — Raises the default value of query_plan_max_limit_for_lazy_materialization from 10 to 100, allowing lazy materialization to apply to queries with larger LIMIT clauses. Improves performance for many queries by reducing unnecessary data materialization. (introduced in 25.11) #89772
  • Speed up countDistinct with faster HashSetTable::merge — Reduces overhead in HashSetTable::merge by early returning for empty tables, preemptive resizing, and saving hash recomputation, which accelerates countDistinct aggregate operations. Queries using countDistinct (e.g., uniq, uniqExact) become faster, especially on large datasets. (introduced in 25.11) #89727
  • Reduce atomic operations in async logging queue — Reduces atomic reference counting operations per entry during async log message enqueuing by using std::move instead of copying shared_ptr. Decreases overhead in high-throughput logging scenarios, improving overall performance. (introduced in 25.11) #89651
  • Allow lazy materialization with read-in-order sorting — Enables the lazy materialization optimization to work simultaneously with optimize_read_in_order, improving performance for ORDER BY … LIMIT queries on sorted keys. Faster query execution for large sorted datasets. (introduced in 25.10, 25.9) #89504 #89506
  • Rewrite ANY LEFT/RIGHT JOIN to ALL INNER JOIN when possible — Allows the optimizer to rewrite ANY LEFT JOIN or ANY RIGHT JOIN to ALL INNER JOIN in certain cases, enabling more efficient join execution. Improves query performance by using more efficient join types when logically safe. (introduced in 25.11) #89403
  • Implement lazy columns replication in JOIN and ARRAY JOIN — Avoids converting special column representations (Sparse, Replicated) to full columns in JOIN and ARRAY JOIN, and in some output formats, reducing unnecessary data copying in memory. Reduces memory consumption and speeds up queries involving JOIN or ARRAY JOIN on tables with sparse or replicated columns. (introduced in 25.10) #89182
  • Disable ThreadFuzzer by default in non-server binaries — ThreadFuzzer now starts disabled by default in all binaries (except server) and only enables itself if effective, reducing unnecessary overhead. Improves startup performance for non-server binaries like clickhouse local and clickhouse client. (introduced in 25.11) #89115
  • Streaming LIMIT BY for sorted input data — When input sort order matches the LIMIT BY keys, a streaming transform is used instead of a hash table, reducing memory and CPU overhead. Improves performance and lowers memory consumption for LIMIT BY queries operating on already sorted data. (introduced in 25.11) #88969
  • Combine read in order with lazy materialization — Allows queries to benefit from both optimize_read_in_order and query_plan_optimize_lazy_materialization simultaneously. Improves query performance by enabling both optimizations together, reducing data read and materialization overhead. (introduced in 25.11) #88767
  • Lazy columns replication in JOIN and ARRAY JOIN — Implements lazy column replication in JOIN and ARRAY JOIN, avoiding conversion of special column representations (Sparse, Replicated) to full columns in output formats. Reduces unnecessary data copy in memory, improving query performance. (introduced in 25.11) #88752
  • Inline AddedColumns::appendFromBlock for join performance — Inlines the appendFromBlock method to reduce function call overhead, improving join performance in some cases. Provides a small performance boost for joins, particularly in scenarios with many columns. (introduced in 25.10) #88455
  • Improve LZ4 decompression speed by 5-10% — Optimizes LZ4 decompression by simplifying copy logic, removing AVX512 shuffle code, and tweaking algorithm selection. Benchmarks show a 4-10% throughput improvement across various CPU architectures. Faster decompression improves overall query performance, especially for compressed data reads. (introduced in 25.11) #88360
  • Optimize failpoint checks to reduce overhead when failpoints are disabled — Removes the slowdown_index_analysis failpoint and adds an atomic fast-path to skip failpoint checks entirely when no failpoints are enabled. Eliminates unnecessary performance overhead in production environments where failpoints are not used. (introduced in 25.10) #88196
  • Push outer filter into view to enable PREWHERE with parallel replicas — Pushes down outer filters into views, allowing PREWHERE optimization to be applied on local and remote nodes when parallel replicas are used. Improves query performance by reducing data transferred from remote nodes and enabling more efficient filtering. (introduced in 26.1) #88189
  • Optimize FINAL queries on ReplacingMergeTree with is_deleted column — FINAL queries on ReplacingMergeTree tables using is_deleted now skip the final merge transform for non-intersecting ranges and single-part partitions, applying a simple filter instead, improving parallelism. Significantly accelerates SELECT … FINAL queries on tables with is_deleted, especially for large tables with many partitions. (introduced in 25.10) #88090
  • Skip redundant hash table statistics recalculation in join optimization — Avoids recalculating hash table statistics during join order optimization by caching the cache key in the logical join step, and adds ProfileEvents for join and query plan optimization timing. Reduces query planning time for joins by eliminating duplicate statistics computation, improving overall query performance. (introduced in 25.10) #87683
  • Optimize Field destructor for integer-heavy workloads — Reduces the overhead of the Field destructor by resetting the ‘which’ field before destruction and adding a likely hint, decreasing profile overhead from 15% to 6%. Improves query performance by ~10% for workloads with many integer fields, such as ClickBench Q19. (introduced in 25.10) #87631
  • Optimize text index build for rare tokens — Improves performance of building text indexes for documents with many rare tokens by using a small stack-allocated array for low-cardinality posting lists, delaying Roaring bitmap allocation. Faster index creation for full-text search on texts with many unique tokens. (introduced in 25.10) #87546
  • DB::SharedMutex gets ~10% performance boost — Applies micro-optimizations to DB::SharedMutex, including a fast path for lock when uncontested and removal of the writer_thread_id field. Improves shared mutex performance by approximately 10%. (introduced in 25.10) #87491
  • Disable sort order optimization for window functions by default — Disables the sort order optimization for window functions when the partition by clause matches the sorting key, improving parallel execution performance. Prevents single-threaded execution and speeds up window function queries with matching sorting keys. (introduced in 26.1) #87299
  • Optimize patch join cache with btree_map and hint insertion — Replaced flat_hash_map with btree_map for offsets and added insertion hints to reduce overhead from hash map merges when applying patch parts in join mode. Improves JOIN performance by reducing CPU and memory overhead during patch application. (introduced in 25.9) #87094
  • Optimize MarkRanges by using devector — Replaces the internal container for MarkRanges from deque to devector, yielding ~39% QPS improvement for fast queries with many parts. Speeds up queries on tables with a large number of parts, reducing latency and improving throughput. (introduced in 25.9) #86933
  • Optimize SELECT DISTINCT using aggregate projections — Enables SELECT DISTINCT queries to use aggregate projections when the distinct columns are a subset of projection keys, avoiding full scans and recomputation. Significantly improves performance for SELECT DISTINCT queries on tables with pre-defined aggregate projections. (introduced in 25.11) #86925
  • RadixSort boosted with SIMD unrolling and Intel prefetching — Adds loop unrolling to help compilers use SIMD, and Intel-specific software prefetching via dynamic dispatch, improving throughput up to 10% on both AMD and Intel CPUs. Faster sorting improves performance of query operations relying on sorting (ORDER BY, GROUP BY, etc.). (introduced in 25.9) #86378
  • HashJoin performance improved for unmatched rows in LEFT/RIGHT joins — Optimizes HashJoin by inlining the appendDefaultRow function, improving performance by ~10% for LEFT/RIGHT joins with a large number of unmatched rows. Speeds up join-heavy queries, especially those with many non-matching rows, reducing query execution time. (introduced in 25.9) #86312
  • Fix VDSO symbol lookup on AArch64 for better performance — Fixes VDSO symbol lookup on AArch64 Linux systems that use GNU hash tables (e.g., Ubuntu AMIs), enabling proper VDSO usage and avoiding frequent clock_gettime syscalls. Improves performance on ARM64 systems by restoring efficient time functions. (introduced in 25.11) #86096
  • Fix GROUP BY performance regression for large string keys — Adds a heuristic to fall back to per-row serialization when total key size exceeds 4x L2 cache or average key size >= 128 bytes, restoring performance for large string/number composite keys. Fixes performance degradation in GROUP BY queries with many or large string columns. (introduced in 25.10) #85924
  • Optimize AggregateFunctionHistogram by sorting tail only — Optimizes AggregateFunctionHistogram by sorting only the tail of the points array and skipping sort for monotonic inputs, achieving ~10% speedup. Improves performance of histogram aggregation for large datasets. (introduced in 25.12) #85760
  • Improve prewhere optimizer for function-on-primary-key and IN conditions — Enhances the prewhere optimizer to correctly handle conditions that cannot use primary index (e.g., func(primary_column) = 'xx') and improves selectivity estimation for IN operators. Better ordering of prewhere conditions can significantly improve query performance. (introduced in 25.9) #85529
  • Allow filter pushdown using equivalent sets for SEMI JOIN — Enables filter pushdown for SEMI JOIN queries using equivalent sets, reducing the amount of data processed. Speeds up SEMI JOIN queries that involve equality conditions. (introduced in 26.1) #85239
  • Allow index pruning for integral column compared with float literal — Enables primary key index pruning and filter pushdown when an integral column is compared with a float literal (e.g., WHERE x < 10.5), and fixes unbounded execution for table functions like primes() and numbers() with such filters. Significantly improves query performance for mixed-type comparisons and prevents runaway queries. (introduced in 26.3) #85167
    • e.g. SELECT * FROM numbers WHERE number < 1e5
  • Prefetch keys during hash table iteration — Prefetches keys during hash table iteration to reduce cache misses, improving performance in hash table heavy operations like GROUP BY. Reduces query execution time for operations involving large hash tables. (introduced in 25.12) #84708
  • Allow WHERE clause in distributed INSERT SELECT for parallel execution — Removes constraints that previously prevented WHERE clauses in distributed INSERT SELECT queries, restoring the ability to use parallel distributed execution with filtering. Improves performance for distributed INSERT SELECT queries that filter data. (introduced in 25.12) #84611
    • e.g. INSERT INTO table SELECT * FROM s3Cluster('cluster', ...) WHERE condition
  • Improve string search performance with StringZilla library — Integrates the StringZilla library to accelerate case-sensitive string search operations (e.g., LIKE, substring matching) using SIMD CPU instructions. Faster filtering on string columns, benefiting queries with LIKE or substring patterns. (introduced in 25.10) #84161
    • e.g. SELECT * FROM table WHERE URL LIKE '%google%'
  • Micro-optimizations for small query speed — A series of micro-optimizations in the pipeline executor and MergeTree reader reduce overhead for small queries. Improves latency for lightweight queries. (introduced in 25.10) #83096
  • Compress logs and profile events in native protocol — Enables compression for logs and profile events sent over the native protocol between ClickHouse instances. Reduces network bandwidth usage significantly on clusters with many replicas, improving responsiveness on slow connections. (introduced in 25.10) #82533
  • Apply query condition cache earlier to reduce index analysis overhead — Moves Query Condition Cache (QCC) filtering before primary key and skip index analysis, and caches index analysis results for multiple range filters, reducing redundant computation. Significantly speeds up queries dominated by index analysis, especially those using skip indexes like vector or inverted indexes. (introduced in 25.10) #82380
  • Optimize ColumnVector::replicate with dynamic dispatch — Implemented dynamic dispatch with AVX512, AVX2, SSE42 for ColumnVector::replicate, speeding up hash join operations. Provides significant performance improvements for hash joins on modern CPUs. (introduced in 26.2) #79573
  • RIGHT and FULL JOINs now use ConcurrentHashJoin — RIGHT and FULL JOIN implementations now utilize ConcurrentHashJoin, enabling parallel execution and improving performance up to 2x for various join cases. Queries using RIGHT or FULL JOINs will run faster with higher degrees of parallelism, reducing execution time for analytical workloads. (introduced in 25.11) #78027
  • Optimize query plans by removing unused columns — Adds an optimization to eliminate columns not needed by the query from the execution plan, reducing I/O and processing overhead. Queries reading wide tables will benefit from faster scans and lower memory usage. (introduced in 25.12) #75152
  • Parallel merge for fixed hash map aggregation states — When grouping by a small integer column, ClickHouse now merges aggregation states in parallel, exploiting the fixed hash map structure. Speeds up GROUP BY queries over low-cardinality integer keys by utilizing multiple threads for state merging. (introduced in 25.11) #63666
  • Fail fast on query row limit hits — When a query reaches its row limit (e.g., LIMIT clause), execution stops early instead of continuing unnecessary processing. Reduces wasted work and delivers results faster for queries with row limits. (introduced in 25.12) #61872
  • Sparse serialization for Nullable columns — Enables sparse serialization for columns of Nullable type, reducing storage overhead when most values are NULL. Improves storage efficiency and query performance for datasets with sparse null values. (introduced in 25.12) #44539
  • Allow partition pruning through deterministic function chains — Enables partition pruning when predicates use comparison operators on partition keys wrapped in deterministic functions (e.g., toYYYYMM(x) < 2026). Reduces data scanned by skipping irrelevant partitions even with transformed partition keys. (introduced in 26.3) #28800
    • e.g. SELECT * FROM t WHERE toYYYYMM(date_col) = 202601;
  • Improve performance of Decimal comparison operations — Optimizes the comparison operations for Decimal data types for faster execution. Speeds up queries that filter or sort on Decimal columns. (introduced in 25.12) #28192
  • Allow any deterministic expression in Primary Key for data skipping — Enables primary keys with deterministic expressions (e.g., cityHash64(user_id)) to be used for data skipping with =, IN, has, and if injective also !=, NOT IN, NOT has. Extends primary key indexing to non-trivial expressions, improving query performance for predicates on transformed values. (introduced in 26.2) #10685
    • e.g. SELECT * FROM t WHERE cityHash64(user_id) = 12345;
  • Optimize repeated inverse dictionary lookups — Speeds up repeated inverse dictionary lookups by caching possible key values in a precomputed set. Improves performance for queries that frequently perform reverse dictionary lookups. (introduced in 25.12) #7968
  • Improve DISTINCT performance on LowCardinality columns — Optimizes DISTINCT execution for LowCardinality columns by leveraging faster dictionary lookups. Reduces query latency when deduplicating low-cardinality data. (introduced in 26.1) #5917

Codecs / compression

  • Accelerate T64 codec compression with CPU dispatch on x86 — Speeds up T64 codec compression by using dynamic dispatch to leverage AVX-512, AVX2, and SSE4.2 instructions on x86. Improves compression performance for tables using the T64 codec, especially on modern CPUs. (introduced in 26.2) #95881

Other small SQL

  • Avoid full scan for system.tables with uuid filter — Optimizes queries on system.tables by prefiltering using the extracted uuid column, avoiding a full table scan when filtering by uuid. Speeds up system.tables lookups by uuid (common when using UUIDs from logs or ZooKeeper paths). (introduced in 25.10) #88379
    • e.g. SELECT * FROM system.tables WHERE uuid = 'abcd-ef12-3456-7890'

JSON data type

  • Optimize JSON type parsing with direct serialization — Improved JSON type parsing performance by directly serializing values into shared data buffers, avoiding temporary column allocations and adding safety checks. Faster parsing of JSON columns reduces query latency for workloads with large JSON data. (introduced in 26.2) #93614
  • Optimize distinctJSONPaths to skip reading full JSON column — Optimizes the distinctJSONPaths aggregate function to only read JSON paths from data parts instead of the entire JSON column. Improves performance for queries that need distinct JSON paths, especially on large datasets. (introduced in 26.1) #92196

ObjectStore - S3/Azure/GCS

  • Reduce S3 listing by pushing down _path filter values for glob tables — Improves query performance for S3 tables created with glob patterns by extracting _path values from query filters and using them to directly iterate over matching files instead of performing listing operations. Controlled by the new setting s3_path_filter_limit. Significantly reduces S3 listing costs and improves query speed when querying a subset of files matching a glob pattern. (settings s3_path_filter_limit) (introduced in 25.12) #91165
    • e.g. SELECT * FROM s3('http://bucket/*.parquet') WHERE _path LIKE '%important%' SETTINGS s3_path_filter_limit = 100;
  • Add checksum-based key prefixes for S3 backup sharding — Introduces data_file_name_generator and data_file_name_prefix_length BACKUP settings to name backup files using content hash prefixes, improving S3 key distribution. Reduces risk of S3 request throttling for large backups by spreading load across partitions. (settings data_file_name_generator, data_file_name_prefix_length) (introduced in 25.11) #88418
    • e.g. BACKUP TABLE my_table TO S3('bucket/path') SETTINGS data_file_name_generator='checksum', data_file_name_prefix_length=3
  • Allow WHERE clause in distributed INSERT SELECT from s3cluster — Restores the ability to use WHERE clauses in INSERT SELECT FROM s3cluster() queries for parallel distributed execution, which was previously restricted. Enables more efficient filtered data ingestion from S3 clusters with better parallelism. (introduced in 25.10, 25.11) #92310 #92312
    • e.g. INSERT INTO table SELECT * FROM s3cluster(default, 'http://...', 'key', 'secret') WHERE size > 100

Datalakes & catalogs

  • Optimize read-in-order for Iceberg tables — Enables reading data in the declared sort order of Iceberg tables, reducing unnecessary sorting overhead. Improves query performance for Iceberg tables, especially when queries can benefit from sorted data. (introduced in 25.10) #88454
    • e.g. CREATE TABLE hits ( ... ) ENGINE = IcebergS3(...) ORDER BY (CounterID, EventTime DESC)
  • Iceberg gains async metadata cache prefetch and staleness settings — Adds iceberg_metadata_async_prefetch_period_ms for background metadata refresh and iceberg_metadata_staleness_ms to serve old metadata without contacting the catalog. Reduces query latency by minimizing catalog calls and allowing cached metadata reuse within a staleness window. (settings iceberg_metadata_async_prefetch_period_ms, iceberg_metadata_staleness_ms) (introduced in 26.3) #96191
    • e.g. CREATE TABLE X (...) ENGINE = Iceberg(...) SETTINGS iceberg_metadata_async_prefetch_period_ms = 60000; SELECT ... SETTINGS iceberg_metadata_staleness_ms = 600000;
  • Partition pruning for Paimon table functions — Adds partition pruning for Paimon table functions, controlled by experimental setting use_paimon_partition_pruning, skipping irrelevant partitions during data file iteration. Significantly improves query performance on Paimon tables by reducing I/O when filtering on partition columns. (settings use_paimon_partition_pruning) (introduced in 25.12) #90253
    • e.g. SELECT * FROM paimonTable WHERE partitionDate = '2023-01-01'
  • Optimize pipeline resizing for data lake queries — Fixes reading from object storage for data lakes to resize the query pipeline to the number of processing threads, improving parallelism. Significantly improves query performance on data lakes by utilizing all available threads. (introduced in 26.3) #99548
  • Improve performance of icebergCluster — Optimizes icebergCluster queries by making ManifestFileEntry non-copyable and using shared_ptr, reducing overhead and yielding up to 5x performance improvement. Iceberg catalog queries are significantly faster, reducing latency for users querying Iceberg tables. (introduced in 26.1) #91462

Integrations

  • Enable parallel reads from YTsaurus table engine — Enables parallel reads from the YTsaurus table engine by splitting static table reads into multiple row-range streams, and adds optional transaction and lock support for consistent snapshots. Significantly improves query performance on YTsaurus tables by utilizing multiple threads for parallel reads. (settings use_lock, transaction_timeout_ms, min_rows_for_spawn_stream, max_streams) (introduced in 26.3) #97343

S3Queue

  • S3Queue ordered mode uses StartAfter to skip already-processed keys — In ordered mode, S3Queue now resumes listing from a persisted checkpoint using StartAfter, reducing the number of ListObjectsV2 calls. Reduces S3 API costs and improves performance for S3Queue in ordered mode. (introduced in 26.3) #96370

Formats

  • Enable Parquet reader v3 by default — Switches the default Parquet reader to version 3, improving read performance and adding CRC checksum verification for data integrity. Users may see faster Parquet imports and better detection of data corruption. (introduced in 25.11) #88827

Analyzer

  • Optimizer: Push filter steps over BuildRuntimeFilterStep — Improves the query optimizer to push newly added runtime filter steps over existing BuildRuntimeFilterStep-s when multiple joins and multiple runtime filters are present. Speeds up complex queries with multiple joins by enabling more efficient runtime filter propagation. (introduced in 25.11) #89725
  • Optimize ConstantNode for large arrays in analyzer — Caches the AST for ConstantNode to avoid unnecessary string building for large constant arrays, fixing a 100x slowdown. Eliminates severe performance regression for queries with large constant arrays in scalar subqueries. (introduced in 25.11) #72880

Parallel replicas

  • Push down filter into views with parallel replicas — Allows the query optimizer to push down an outer filter into a view, enabling the use of PREWHERE on both local and remote nodes when parallel replicas are enabled. Reduces data transfer and improves query performance for SELECTs on views with parallel replica execution. (introduced in 25.12) #95532

Keeper

  • Reduce Keeper memory with CompactChildrenSet — Replaces absl::flat_hash_set with CompactChildrenSet for storing node children, storing 0-1 children inline without heap allocation, reducing KeeperMemNode size from 144 to 128 bytes. Lowers memory usage in Keeper, beneficial for deployments with many nodes. (introduced in 26.3) #99860
  • Optimize aggregated ZooKeeper log with CityHash64 and lock-free error counter — Optimizes the aggregated ZooKeeper log by replacing SipHash with CityHash64 for hashing and replacing a mutex-guarded unordered_map with a lock-free atomic array for error counting, reducing CPU consumption of ZooKeeper::observeOperations from >20% to ~5.7%. Reduces CPU overhead on ZooKeeper receive thread, improving overall system performance in ZooKeeper-heavy deployments. (introduced in 26.2) #95962

👆 Back to v26.3 versus 25.8 overview

Improvements

SQL / Main features

  • Promote QBit data type from Experimental to Beta (in 26.1) #93816
  • Experimental join order optimization and fix USING column semantics (in 25.9) #80848
  • Full-text search index graduates to GA (in 26.2) #96794
  • QBit data type promoted to General Availability (in 26.2) #95358
  • Support extended table aliases for JOINs (in 26.2) #95131
  • Add allow_nullable_tuple_in_extracted_subcolumns setting (in 26.2) #98785
  • Add setting apply_row_policy_after_final for ReplacingMergeTree (in 25.12) #90986
  • Enable Time and Time64 data types by default (in 25.12) #89345
  • Add setting aggregate_function_input_format for INSERT of AggregateFunction columns (in 25.12) #88088
  • Inject random order for SELECT queries without ORDER BY via setting (in 25.10) #87261
  • Rename arrowFlight table function to camelCase (in 25.10) #87249
  • Limit query plan description length in EXPLAIN with new setting (in 25.9) #86741
  • UNION uses Variant type for type unification with new setting (in 25.11) #82772
  • Allow ALTER MODIFY COLUMN TTL without column type (in 26.3) #99208
  • Support parenthesized table joins in FROM clause (in 26.3) #97650
  • …and 30 more in SQL / Main features.

Functions

  • Add toDaysInMonth() function (in 26.3) #99227
  • Add tokensForLikePattern function for LIKE pattern tokenization (in 26.3) #97872
  • Add distanceCosine alias for cosineDistance (in 26.2) #96065
  • Add singular aliases for hasAnyTokens and hasAllTokens functions (in 25.10) #88162
  • Add h3PolygonToCells function for filling polygons with H3 hexagons (in 25.11) #33991
  • Text indexes support Nullable and Array string columns (in 26.3) #98118
  • Unify argument validation for tupleConcat function (in 26.3) #97672
  • Remove 64-token limit for hasAnyTokens and hasAllTokens (in 26.1) #95152
  • flipCoordinates now supports Geometry type (in 26.1) #93303
  • Text index support for mapContainsKeyLike and mapContainsValueLike (in 26.1) #93049
  • joinGet now supports temporary tables (in 26.1) #92973
  • Allow implicit type conversion for Array to QBit casts (in 25.10, 25.11) #92301 #92303
  • Allow ngram length of 1 in ngram tokenizer (in 25.12) #91529
  • Support array input for hasAnyTokens and hasAllTokens (in 25.11) #89124
  • hasAny/hasAllTokens now accept string input with automatic tokenization (in 25.10) #88679
  • …and 11 more in Functions.

MergeTree-related

  • Allow vertical merge for tables with DELETE TTL rules (in 26.3) #97332
  • Control secondary index behavior during column mutations (in 25.12) #77797
  • Text index now GA, unaffected by compatibility setting (in 26.2, 26.3) #101866 #101868
  • Enable statistics by default and mark as GA (in 26.3) #99397
  • Allow deduplication with async inserts and materialized views (in 26.1) #93957
  • Add ALTER TABLE REWRITE PARTS command (in 25.10) #87774
  • Add statistics column to system.parts_columns (in 25.9) #87259
  • Use projections as secondary index for row filtering (in 25.11) #80343
  • Prewarm secondary index marks with prewarm_mark_cache (in 26.2) #98186
  • Prewarm marks of secondary indexes now supported (in 26.3) #97772
  • Improve subcolumns reading with correct size calculations (in 26.3) #96251
  • Add settings to gate distributed index analysis by parts count and index size (in 26.2) #95216
  • Add setting to control statistics materialization on merge (in 26.1) #93379
  • Automatically create minmax indexes for date/time columns (in 26.2) #93355
  • Squash parallel materialized view inserts to reduce parts (in 25.10) #87280
  • …and 36 more in MergeTree-related.

Performance

  • Column statistics GA with auto minmax and uniq for new columns (in 26.3) #97487
  • Runtime bloom filters for JOIN to skip left-side rows (in 25.10) #84772
  • Eagerly free vector similarity index cache entries on part drop (in 25.12) #90750
  • Reduce memory usage with per-table ColumnsDescription cache for parts (in 25.11) #89352
  • Run jemalloc dirty page purging in separate thread to avoid OOM risk (in 25.11, 25.12) #95166 #95167
  • Dynamic jemalloc dirty page decay adjustment under memory pressure (in 26.2) #95145
  • Run jemalloc dirty page purging in separate thread to reduce OOM risk (in 25.10) #95141
  • Run jemalloc dirty page purging in separate thread to avoid OOM (in 26.1) #94902
  • Add threshold-based dirty page purging for jemalloc (in 26.1) #93500
  • Randomize heavy cache correctness checks to reduce overhead (in 26.1) #93439
  • Dynamically disable join runtime filters to reduce overhead (in 26.1) #91578
  • Add configurable cache for text index headers (in 25.11) #89513
  • Cache table-level statistics to reduce query overhead in MergeTree (in 25.11) #88670
  • Add temporary_files_buffer_size setting and optimize scatter for LowCardinality (in 25.10) #88237
  • Add joined_block_split_single_row setting to reduce hash join memory usage (in 25.10) #87913
  • …and 57 more in Performance.

Other small SQL

  • IN operator now accepts non-constant second arguments (in 25.12) #77906
  • New setting allow_nullable_tuple_in_extracted_subcolumns for subcolumn compatibility (in 26.1) #98885
  • Add alias use_statistics for allow_statistics_optimize (in 26.1) #94366
  • Change default stderr_reaction to log_last for executable UDFs (in 26.3) #99232
  • Enable GraceHash join with WITH TOTALS (in 26.3) #98144
  • view_duration_ms now shows actual group active time instead of sum of thread durations (in 25.12) #95438
  • Enable number-to-Enum conversion check by default (in 26.1) #94384
  • QBit type now supports equality comparisons (in 26.1) #94078
  • Reduce output on syntax errors to avoid flooding (in 26.1) #93876
  • Support EXPLAIN indices = 1 as alias for EXPLAIN indexes = 1 (in 26.1) #92483
  • Add system.completions to always accessible tables (in 25.12) #91166
  • Explicit schema shown for parameterized views (in 26.1) #88875
  • Fix EXCHANGE TABLES support for Alias engine (in 25.10) #88233
  • Make yesterday() function case-insensitive (in 25.9) #86914
  • Simplify Time/Time64 parsing in best_effort format (in 25.9) #84730
  • …and 2 more in Other small SQL.

JSON data type

  • Native JSON/Object input for JSONExtract functions (in 26.3) #88370
  • Add restart-only setting for nullable Tuple subcolumns (in 26.3) #97299
  • Add settings to limit dynamic subcolumns in JSON columns (in 26.1) #94184
  • Add setting to allow duplicated JSON keys with literal and nested object (in 26.1) #93604
  • Enable relaxed JSON parsing for duplicated keys by default (in 26.3) #97423
  • Schema inference respects allow_experimental_nullable_tuple_type (in 26.2) #95525
  • Optimize JSON/Variant part loading by releasing file streams early (in 26.2) #94848
  • Optimize JSON column squashing with fast path (in 26.1) #94247
  • Fix thread pool starvation when reading JSON column samples (in 25.10, 25.11) #91252 #91254
  • Respect deserialization thread pool setting for JSON subcolumn sampling (in 25.12) #91208
  • Pretty-print JSON columns in Vertical format (in 25.10) #81794
  • Support JSON type in tupleElement function (in 25.12) #81630

ObjectStore - S3/Azure/GCS

  • Add virtual column _tags for S3 blob tags (in 25.11) #72945
  • Cache S3 credentials from STS endpoint (in 25.11) #89734
  • Backups gain dedicated S3 retry policy settings (in 25.9) #88480
  • Backups use dedicated S3 client settings for native copy (in 25.10) #87660
  • Extend S3 retryable error slowdown to all S3 storage (in 25.9) #85918
  • Configurable S3 retry strategy with hot-reloadable disk settings (in 25.9) #82642
  • Add ObjectStorage ProfileEvents for file listing and reading (in 25.12, 26.2, 26.3) #100070 #100072 #100104
  • S3 table engine gains {_schema_hash} placeholder for schema isolation (in 26.3) #98265
  • Improve S3 authentication error messages with credential hints (in 26.2) #95648
  • Fallback to read-write copy for Azure Blob on native copy failure (in 25.10, 25.11, 25.12) #93373 #93375 #93377
  • Add blob_storage_log for Local, HDFS, and improve logging (in 26.1) #93106
  • Enable blob_storage_log for Azure Blob Storage (in 26.1) #93105
  • Add MinIO error code mapping to AWS S3 SDK (in 26.1) #93082
  • Cache EC2 instance profile credentials to avoid throttling (in 26.1) #92891
  • Improve resilience of Azure Blob Storage copy operations (in 26.1) #92888
  • …and 19 more in ObjectStore - S3/Azure/GCS.

Datalakes & catalogs

  • Add rows/bytes limits for Delta Lake INSERT data files (in 25.9) #86357
  • Add Google Cloud Storage support for data lakes (in 26.1) #93866
  • Iceberg expire_snapshots with named arguments and dry-run (in 26.3) #99130
  • Optimize SHOW TABLES in DataLakeCatalog to fetch only table names (in 26.2) #93835
  • Add role-based access to Glue catalog with aws_role_arn (in 26.2) #90825
  • Support reading DeltaLake Change Data Feed via deltaLake table function (in 25.12) #90431
  • Multiple data files per partition in Iceberg writes (in 25.9) #86275
  • Add experimental setting for Delta Lake writes (in 25.9) #86180
  • Add Delta Lake cluster functions for S3 and Azure (in 25.9) #85358
  • Iceberg tables now support ALTER TABLE RENAME COLUMN (in 26.2) #97455
  • Add SYSTEM RELOAD DELTA KERNEL TRACING command (in 26.2) #96763
  • Optimize Delta Lake metadata scan with lazy parsing and improved shutdown (in 26.2) #96686
  • Skip object storage reads for DeltaLake in system.tables (in 25.12) #96434
  • DeltaLake gets accurate table stats from metadata with snapshot caching (in 26.2) #96190
  • Skip S3 reads for DeltaLake tables in system.tables queries (in 26.1, 26.2) #95899 #96034
  • …and 24 more in Datalakes & catalogs.

Integrations

  • Add sslmode parameter to PostgreSQL dictionary sources (in 26.3) #98014
  • Add iif KQL function (in 26.2) #94790
  • Add kafka_consumer_reschedule_ms setting for Kafka engine (in 25.12) #89204
  • Add Kafka compression codec settings for table engine (in 25.11) #89073
  • YTsaurus: redirect heavy requests to dedicated heavy proxies (in 25.10) #87342
  • Add encode_utf8 setting for YTsaurus tables (in 25.10) #87150
  • Rename PromQL setting evaluation_time to promql_evaluation_time (in 25.9) #86459
  • Faster query cancellation for MongoDB and MySQL (in 26.3) #98187
  • Prevent dropping named collections used by dictionary sources (in 26.3) #98127
  • Support cancellation of SQLite table engine queries (in 26.3) #97944
  • Fix crash in MaterializedPostgreSQL attach on replication slot error (in 26.2) #96871
  • S3Queue auxiliary Zookeeper support using keeper_path (in 26.2) #95203
  • Enable named collections for YTsaurus dictionaries and tables (in 26.1) #94582
  • Dynamic S3 token refresh for long-running Unity Catalog queries (in 26.2) #93981
  • Add column description support for YTsaurus dictionary source (in 26.1) #92391
  • …and 13 more in Integrations.

S3Queue

  • Support partition key bucketing for S3Queue ordered mode (in 26.1) #94698
  • S3Queue ordered mode adds regex-based partition tracking (in 26.1) #94321
  • Add commit_on_select setting for S3Queue (in 25.12) #91450
  • Persistent bucket locks for S3Queue ordered mode (in 25.10) #86628
  • S3Queue gains persistent processing nodes to avoid duplicates on ZK loss (in 25.9) #85995
  • S3Queue cleans up failed nodes in Ordered mode under tracking limits (in 26.1) #94412
  • S3Queue respects disable_insertion_and_mutation setting (in 25.11) #89048
  • Hive partitioning tracking for S3Queue ordered mode (in 26.1) #71161

Formats

  • Add output_format_trim_fixed_string setting (in 26.3) #97558
  • Output Date as Arrow date32 in Arrow/ArrowStream formats (in 26.2) #96860
  • Add input_format_max_block_wait_ms setting for streaming inserts (in 26.2) #94509
  • Add configurable maximum message size for CapnProto format (in 25.12) #91888
  • Parquet no-timezone timestamps now treated as UTC by default (in 25.11) #87469
  • Protobuf input oneof presence column (in 25.9) #82885
  • Display named tuples as Pretty JSON in Pretty format (in 25.12) #65022
  • Tolerate missing padding in Parquet files (in 26.3) #99857
  • Support mixed geometry types in GeoParquet columns (in 26.3) #97851
  • Schema inference now respects allow_experimental_nullable_tuple_type setting (in 26.1) #97291
  • Make Hash output format independent of block sizes (in 26.1) #94503
  • Print simple types inline in Pretty JSON (in 26.1) #93836
  • Support empty tuples in Parquet (in 26.1) #92868
  • Read Tuple/Map columns as JSON from Parquet (in 26.1) #92864
  • Fix Array and Map binary deserialization size limit check (in 25.11) #88744
  • …and 3 more in Formats.

Operations

  • Add jemalloc_profiler_sampling_rate server setting (in 26.2, 26.3) #97945 #98481
  • Introduce backup setting to skip refreshable MV targets (replace strategy) (in 25.10) #94551
  • Add backup setting for refreshable materialized view targets (in 25.11) #94476
  • Add setting to skip backing up refreshable MV targets (replace strategy) (in 25.12) #94383
  • Add backup setting for refreshable materialized view data (in 26.1) #93658
  • Add backup setting to skip refreshable materialized view targets (in 26.1) #93076
  • Add setting to limit profile event tracing to a list (in 26.1) #92298
  • Add setting insert_select_deduplicate for INSERT SELECT deduplication (in 25.12) #91830
  • Add hard limit to HTTP client connections to prevent resource exhaustion (in 25.11, 25.12) #91016 #91193
  • Add iceberg_insert_max_partitions setting to limit insert partitions (in 25.12) #90365
  • Expose only Keeper metrics in server for separate deployments (in 25.12) #90244
  • Skip mlock executable on low-memory systems (<5GB) (in 25.11) #89751
  • Add setting to disable PSI metrics collection (in 25.12) #88557
  • Add setting keeper_hosts to expose ZooKeeper hosts (in 25.10) #87718
  • Support composite log rotation by size and time (in 26.1) #87620
  • …and 83 more in Operations.

CLI

  • Shell-like tab completion in clickhouse-keeper-client (in 26.3) #99312
  • Clear error for non-existent file argument in clickhouse (in 26.3) #98048
  • clickhouse-keeper-client gets tab completion for commands and paths (in 26.3) #97828
  • Fix query obfuscator to produce parseable SQL (in 26.2) #97584
  • Update chdig to v26.2.1 with MacOS support (in 26.2) #96113
  • Update chdig CLI tool to v26.1.1 (in 26.1) #94290
  • Fix clickhouse git-import tool for large or invalid commits (in 26.1) #93202
  • Highlight digit groups in numeric literals in client (in 26.1) #93100
  • Allow spaces around equals sign in command-line arguments (in 26.1) #93077
  • Ctrl+R search executes current query when no history match (in 26.1) #92749
  • Update chdig terminal UI to v25.11.2 (in 25.12) #90773
  • Update chdig tool to v25.11.1 (in 25.11) #89957
  • ClickHouse client supports XDG Base Directory config location (in 25.12) #89882
  • Highlight matching identifiers in interactive client (in 25.11) #89689
  • Update chdig interactive client to v25.10 (in 25.11) #89452
  • …and 12 more in CLI.

Web UI

  • Show chart title in dashboard on empty result or error (in 26.3) #98975
  • Add copy-to-clipboard button for raw query results in play.html (in 26.2) #97532
  • Show loading indicator in play.html sidebar while fetching tables (in 26.2) #97531
  • Extract web components from play.html for better encapsulation (in 26.2) #97529
  • Toggle database list in Web UI left panel (in 26.2) #96884
  • Fix Web UI cache error on system tables (in 26.2) #96869
  • Web UI play page gets Ctrl+/ shortcut to toggle query line comments (in 25.12) #91160
  • Web UI makes table properties clickable for system.tables and SHOW TABLE (in 25.11) #89771
  • Fix type hint overflow and tooltip in Web UI (in 25.11) #89753
  • Improve query textarea resizer in Web UI to full-width (in 25.11) #89457
  • Show double-sided bar charts for negative values in Web UI (in 25.11) #89016
  • System dashboards get customizable time ranges via from and to parameters (in 25.10) #87823
  • Check Web UI credentials only on paste (in 25.10) #85777
  • Improve Web UI: favicon indicates running query, show auxiliary errors (in 26.2) #85055

Security

  • Add setting to disallow config-defined profiles for SQL-defined users (in 26.3) #98662
  • New setting to throw exception on missing row policies for user (in 26.2) #95014
  • Add early total memory limit check before user authentication (in 26.2) #95003
  • Introduce input_format_binary_max_type_complexity setting to limit nested types (in 26.1) #92519
  • ACME config: rename parameters and change interval to seconds (in 25.12) #92211
  • Disable AI SQL generation in embedded client to protect environment variables (in 26.1, 26.2, 26.3) #102311 #102314 #102324
  • Reduce locking during access control (in 26.3) #97894
  • Impersonate feature enabled by default (in 26.3) #97870
  • Move allow_impersonate_user to access_control_improvements section (in 26.2) #96451
  • Fix uninitialized memory access with password-protected TLS keys (in 26.1) #94182
  • Mask passwords from URL storage engine in query log (in 26.1) #93245
  • Safer ACCESS_DENIED hints: column names hidden without SHOW_COLUMNS privilege (in 26.3) #91067
  • Hide server version in unauthenticated HTTP error responses (in 25.12) #91003
  • Fix libssh vulnerability CVE-2025-5318 (in 25.10, 25.11) #90807 #90808
  • Cache bcrypt authentication results for repeated logins (in 25.10) #89650
  • …and 5 more in Security.

Network

  • Make TCP and HTTP external table duplicate handling consistent (in 25.10) #88032
  • Restrict network_compression_method to supported generic codecs (in 25.9) #87097

Analyzer

  • Add setting to control hash table stats for join reordering (in 26.1) #93912
  • Postpone correlated subquery materialization for better optimization (in 25.10) #88990
  • Cap column list in Analyzer error messages to 10 entries (in 26.3) #99002
  • Show deferred filters in EXPLAIN output for Row Policies/PREWHERE with FINAL (in 25.12, 26.1, 26.2) #98108 #98110 #98112
  • Reuse index analysis for parallel replicas to avoid redundant work (in 26.2) #94854
  • Fix runtime filter pushdown with multiple Expression steps (in 25.11) #89741
  • Enable new analyzer for DDL default expression validation (in 25.10) #88087
  • Fix redundant equal expression optimization with LowCardinality type mismatch (in 25.10) #82651

Database=Replicated

  • Add internal_replication setting to Replicated database engine (in 26.3) #97228
  • Allow creating Replicated database without arguments (in 25.10) #88044
  • ON CLUSTER DDL uses original user context (in 25.11) #71334
  • Defer cluster cache update in Replicated database to reduce Keeper load (in 26.2) #96897
  • Support with_data Keeper extension for Database Replicated table fetching (in 26.2) #96090
  • Increase default replicated deduplication window to 10000 (in 25.9) #86820
  • Improve dropping database replica with ZooKeeper path (in 25.10) #85637

Parallel replicas

  • Only connectable replicas participate in distributed index analysis (in 26.2) #98749
  • Cap automatic parallel replicas to actual cluster size (in 26.3) #98668
  • Only use alive replicas for distributed index analysis (in 26.3) #98521
  • Clarify interaction between enable_parallel_replicas and automatic_parallel_replicas_mode (in 26.3) #97517
  • Fix estimation accuracy for queries with selective PREWHERE in parallel replicas (in 26.2) #97231
  • Improve cache reuse in automatic parallel replicas statistics (in 26.2) #93636
  • Allow all replicas to steal orphaned ranges in parallel replicas (in 26.1) #91374
  • Support direct reading from text indexes with parallel replicas (in 25.10) #88262
  • Skip index analysis on remote replicas when no projections present (in 25.10) #87096

Keeper

  • Skip stale Keeper requests for finished sessions (in 26.3) #99246
  • Add OpenTelemetry tracing for Keeper requests (in 26.2) #91332
  • Add max_requests_append_bytes_size setting for Keeper append request batch (in 25.12) #90342
  • Keeper: add configurable ACL check on node removal (in 25.10) #88513
  • Add max_request_size setting to limit Keeper request sizes (in 25.10) #87952
  • New server setting keeper_hosts exposes ZooKeeper hosts (in 25.9) #87934
  • Add keeper_server.tcp_nodelay config parameter for Keeper (in 25.10) #87363
  • Reduce lock contention in Keeper dispatcher (in 26.3) #99751
  • Prevent Keeper mntr command from getting stuck due to lock contention (in 26.3) #99472
  • Immediately mark ZooKeeper session expired on finalization start to reduce reconnect delay (in 26.3) #99102
  • Keeper-bench gains request pipelining, warmup, per-operation stats, and reproducible seeds (in 26.3) #98906
  • Add profile event for Keeper subrequests (in 26.2) #98488
  • Add KeeperRequestTotalWithSubrequests profile event for subrequest monitoring (in 26.3) #98348
  • Add MaxAllocatedEphemeralLockSequentialNumber metric (in 26.3) #98243
  • Keeper CLI find_super_nodes no longer stalls on large trees (in 26.3) #97819
  • …and 19 more in Keeper.

Introspection

  • Log data skipping indices used during query execution in query_log (in 26.3) #78676
  • Add system.jemalloc_profile_text table for jemalloc heap profiling (in 26.2) #93248
  • Update jemalloc and add global and per-query profiling (in 25.9) #85438
  • Reduce memory usage and fix duplicate output in jemalloc profile system table (in 26.2) #99378
  • Add is_subrequest column to aggregated_zookeeper_log (in 26.3) #99169
  • Reduce memory usage and fix duplicate output in jemalloc_profile_text (in 26.3) #99121
  • Make system.stack_trace work on macOS (in 26.3) #98982
  • Add system.jemalloc_stats table and interactive web UI for jemalloc statistics (in 26.2) #97077
  • Add jemalloc bin fragmentation columns to system.jemalloc_bins (in 25.12, 26.1) #96905 #96908
  • Enhanced jemalloc introspection with new fragmentation metrics (in 26.2) #96840
  • Fix socket timeout handling with proper EINTR tracking for profilers (in 26.2) #96601
  • Enhance system.crash_log with signal and query details (in 26.2) #95857
  • Fix address adjustment in jemalloc profile symbolization (in 26.1) #94837
  • Enhance system.crash_log with signal details and stack traces (in 26.2) #94112
  • Write symbolized jemalloc profiles for offline analysis (in 26.1) #93099
  • …and 9 more in Introspection.

Misc

  • Replace insert_select_deduplicate with new enum deduplicate_insert_select (in 25.12) #94210
  • Rework insert_select_deduplicate into deduplicate_insert_select enum (in 26.1) #92951
  • Set badbit exceptions for std streams in Poco (in 25.12, 26.1) #100462 #100464
  • Strict deserialization for aggregate function states (in 26.3) #98786
  • Upgrade SimSIMD vector similarity library (in 26.3) #98767
  • Update clickstack to 2.20.0 (in 26.3) #98252
  • Reapply previous improvement after bug fix (in 26.2) #97064
  • Set badbit on stream exceptions for internal POCO streams (in 26.2) #96455
  • Reduce flakiness in test_merges_memory_limit (in 26.1) #93532
  • Use minimal debug info instead of no debug for heavy translation units (in 26.1) #93079
  • Fix crash on old statistics format, require ALTER MATERIALIZE STATISTICS (in 25.11) #90983
  • Fix crash on old statistics format, require regeneration (in 25.12) #90904
  • Update internal croaring library to v4.4.3 (in 25.12) #90891
  • Forbid time zones for Time type (in 25.9) #84689
  • Revert marks cache metrics to exclude merges (in 25.12) #83415

👆 Back to v26.3 versus 25.8 overview

Notable bug fixes

  • Fix column rollback in Buffer engine to prevent in-memory corruption on insertion failure data-loss — Fixes column rollback in Buffer engine when an exception occurs during appending a new block, preventing corrupted in-memory state by restoring columns to their pre-transaction state. Ensures data integrity when using the Buffer engine, preventing silent corruption on insertion errors. (introduced in 25.12, 26.1, 26.2) #98647 #98649 #98651
  • Fix column corruption rollback in Buffer engine on insertion failure data-loss — Fixes rollback logic in StorageBuffer::appendBlock to use column checkpoints, preventing in‑memory column corruption when an exception occurs during block insertion. Ensures data integrity and avoids inconsistent state in Buffer engine tables after partial insert failures. (introduced in 26.3) #98551
  • Fix Keeper data loss on restart with Azure s3_plain log storage data-loss — Fixes a bug in path handling when Keeper uses Azure Blob Storage with s3_plain metadata, preventing data loss on restart by replacing std::filesystem::path operations with string concatenation (backport to 26.1). Prevents critical data loss for Keeper deployments using Azure Blob Storage with s3_plain metadata. (introduced in 25.12, 26.1, 26.2) #98172 #98174 #98176
  • Fix Keeper data loss on restart with Azure s3_plain log disk data-loss — Fix a bug in ContainerClientWrapper where absolute path replacement caused Keeper log files to become invisible after restart when using Azure Blob Storage with s3_plain metadata for log storage, leading to data loss. Operators using Keeper with Azure Blob Storage for log storage risk silent data loss on restart; this fix ensures all log files are visible and Keeper recovers correctly. (introduced in 26.3) #97987
  • Fix mutation corruption with exists() and mutations_execute_subqueries_on_initiator data-loss — Fixes a bug where the exists() function in ALTER TABLE UPDATE mutations caused mutation corruption when the setting mutations_execute_subqueries_on_initiator = 1 was enabled, potentially crashing the server or making the table unloadable. Prevents data corruption and crashes during UPDATE mutations involving scalar subqueries with exists(). (introduced in 26.2) #97347
  • Fix data loss race in sharded HASHED dictionary parallel loading data-loss — Fixes a TOCTOU race condition in the sharded HASHED dictionary parallel loader that could cause worker threads to exit early, leaving some rows unloaded. Prevents missing rows in dictionaries, ensuring all data is loaded correctly and avoiding silent data loss. (introduced in 26.2) #96953
  • Fix JSON SKIP path prefix matching causing data loss data-loss — Fixes a bug where JSON(SKIP path) incorrectly skipped all keys whose prefix matched the skip path (e.g., skipping ‘path’ also skipped ‘pathpath’), causing data loss. Now only exact path prefix with dot separator is skipped. Prevents unintended data loss when using JSON SKIP path feature. (introduced in 25.11, 25.12, 26.1, 26.2) #95948 #96211 #96213 #96215
    • e.g. CREATE TABLE t (j JSON(SKIP path)) ... -- now only key 'path' is skipped, not 'pathpath'
  • Fix data corruption in concurrent async inserts with same parameter names data-loss — Resets template state when query parameters change to prevent cross-contamination of values from concurrent async inserts using identical parameter names. Prevents silent data corruption in async insert workloads with parameterized queries. (introduced in 26.2) #96035
  • Improve rollback reliability in plain-rewritable unlink metadata operations data-loss — Fixes the rollback logic in plain-rewritable unlink metadata operations so that the source blob is restored even if the removal fails, preventing data loss or inconsistency. Ensures consistency and prevents data loss in object storage metadata operations. (introduced in 26.1, 26.2) #95302 #95419
  • Fix data loss race in ReplicatedMergeTree DROP PARTITION with concurrent INSERT data-loss — Fix a race condition where DROP PARTITION could remove parts created by later log entries due to non-atomic block number allocation; corrects a timeout bug and throws an exception if a ZooKeeper path does not disappear in time. Prevents data loss when concurrent INSERT and DROP PARTITION operations occur, ensuring data integrity. (introduced in 25.10, 25.11, 25.12) #94635 #94636 #94637
  • Fix FILE_DOESNT_EXIST after sparse column mutation with ratio change data-loss — Fixes an error where UPDATE mutations on sparse columns fail with FILE_DOESNT_EXIST if the sparse serialization ratio was altered to 1.0, due to leftover files not being cleaned up. Prevents data loss and failed mutations when changing sparse column storage parameters. (introduced in 25.10, 25.11, 25.12) #93180 #93182 #93184
  • Fix FILE_DOESNT_EXIST error after sparse column mutation with altered serialization ratio data-loss — Fixes an error where UPDATE mutations did not clean up old sparse serialization files when the column storage format changed, causing FILE_DOESNT_EXIST. Prevents data errors when altering sparse column serialization settings. (introduced in 26.1) #93016
    • e.g. ALTER TABLE my_table MODIFY SETTING ratio_of_defaults_for_sparse_serialization = 1.0; -- after mutation, no longer crashes.
  • Avoid caching partition key with non-deterministic functions in S3 engine data-loss — Prevents the S3 table engine from caching partition keys computed from non-deterministic functions, ensuring each insert computes a fresh partition value. Eliminates data corruption where multiple inserts would incorrectly use the same partition key for non-deterministic expressions. (introduced in 26.1) #92844
  • Fix serialization inconsistency in Tuple columns with sparse and nullable substreams data-loss — Resolves a serialization inconsistency between sparse and nullable substreams in Tuple columns that could lead to corrupted parts or crashes during reading. Improves data integrity and stability when using Tuple columns with sparse or nullable subcolumns. (introduced in 25.12) #91932
  • Fix data corruption when merging JSON columns in Summing/Aggregating/Coalescing MergeTree data-loss — Fixes merging of JSON columns in Summing, Aggregating, and Coalescing MergeTree engines. Previously, merges could produce unexpected dynamic paths during writing to data parts, leading to potential data corruption. Prevents possible data loss or query errors when using JSON columns in these specialized MergeTree engines. (introduced in 25.10, 25.11, 25.12, 25.9) #91151 #91265 #91267 #91269
  • Fix Buffer engine background flush never triggers with frequent INSERTs data-loss — Ensures the background flush of Buffer table engine is immediately scheduled when the flush time has already elapsed, preventing unbounded row accumulation during frequent INSERTs. Prevents data loss and unbounded memory growth in Buffer tables, ensuring rows are flushed to the destination table as expected. (introduced in 25.10, 25.11, 25.9) #90933 #90935 #90937
  • Fix Buffer engine background flush not triggering with frequent INSERTs data-loss — Fixes a bug where the Buffer table engine’s background flush would never schedule when inserts were frequent, causing data to remain buffered indefinitely. Prevents unbounded memory growth and potential data loss in Buffer tables. (introduced in 25.12) #90892
  • Fix data loss when merge task is canceled data-loss — Immediately removes the partially created resulting part when a merge or mutate task is canceled, preventing the disk transaction revert that could wrongly delete data from S3. Avoids potential data loss due to canceled merge tasks. (introduced in 25.10) #90215
  • Fix move operation for plain-rewritable disks with nested directories data-loss — Fixes the move operation on plain-rewritable disks to correctly handle directories of arbitrary depth, preventing data inconsistency. Ensures data integrity when moving folders on plain-rewritable disks. (introduced in 25.10) #88586
  • Fix data corruption in MergeTree tables with column TTL and sparse serialization data-loss — Fixes a data corruption bug in MergeTree tables with column TTL when sparse serialization is used. The fix clears serialization caches and removes a problematic setColumns call that caused incorrect handling of serialization info during TTL-based column removal. Prevents potential data loss or silent corruption in tables using column TTL, ensuring data integrity. (introduced in 25.10) #88095
  • Hash MergeTree file names on case-insensitive filesystems to avoid corruption data-loss — Always hashes MergeTree file names on case-insensitive filesystems to prevent collisions when column/subcolumn names differ only in case. Prevents data corruption on case-insensitive filesystems (e.g., MacOS) and ensures safe upgrades. (introduced in 26.1) #86559
  • Fix Materialized View failure after drop and recreate with same name data-loss — Fixes a bug where a Materialized View could stop working after being dropped and recreated with the same name due to double dependency removal. Ensures Materialized Views remain functional after typical DDL operations. (introduced in 25.9) #86413
  • Fix logs_to_keep=0 causing perpetual replica loss in DatabaseReplicated data-loss — Changes logs_to_keep setting type from UInt32 to NonZeroUInt64 to reject zero, preventing a bug where setting logs_to_keep=0 would cause a replica to be permanently lost. Prevents data loss and administrative overhead from misconfiguration. (introduced in 25.9) #86142
  • Fix optimize_skip_unused_shards with new analyzer for distributed tables in IN subqueries silent-wrong-result — Fixes shard pruning for Distributed tables used inside IN subqueries when the new analyzer is active, ensuring optimize_skip_unused_shards works correctly. Prevents incorrect UNABLE_TO_SKIP_UNUSED_SHARDS errors and allows proper shard skipping in complex distributed queries. (introduced in 26.3) #99436
  • Fix comparison between Time[64] and DateTime[64] types silent-wrong-result — Promotes Time[64] values to DateTime[64] by adding the date part 1970-01-01 when comparing with DateTime[64] types, aligning with existing Date/DateTime comparison behavior. Ensures correct and intuitive comparison results between time and datetime types. (introduced in 26.3) #99267
  • Fix incorrect ANY LEFT JOIN to SEMI JOIN conversion silent-wrong-result — Prevents the query plan optimizer from incorrectly converting an ANY LEFT JOIN with an IN subquery into a SEMI JOIN when the subquery set is not yet built, which could return missing rows. Ensures correct query results for joins involving subqueries, fixing a silent wrong-result bug. (introduced in 25.12) #99214
  • Fix insert_deduplication_token ignored for INSERT SELECT without ORDER BY ALL silent-wrong-result — Makes insert_deduplication_token sufficient to enable deduplication for INSERT SELECT queries even without ORDER BY ALL, preventing duplicate rows when a token is provided. Ensures that explicitly set deduplication tokens are respected, avoiding data duplication in unsorted INSERT SELECT operations. (introduced in 26.3) #99206
    • e.g. SET insert_deduplication_token = 'my_token'; INSERT INTO target SELECT * FROM source;
  • Fix incorrect ANY LEFT JOIN to SEMI JOIN conversion with unbuilt IN subquery set silent-wrong-result — Fixes an optimizer bug that incorrectly converted ANY LEFT JOIN to SEMI JOIN when the IN subquery set was not yet built, causing missing rows in results. Prevents incorrect query results for queries using ANY LEFT JOIN with IN subqueries. (introduced in 26.3) #99112
  • Fix error when reading Delta Lake structs with dotted field names silent-wrong-result — Fixes a bug where reading Delta Lake tables using column mapping ’name’ mode with struct fields containing dots in their names caused DUPLICATE_COLUMN exceptions or silent NULLs. Ensures correct data retrieval from Delta Lake tables with complex struct field names. (introduced in 26.2) #99072
  • Fix windowFunnel strict_deduplication returning incorrect level silent-wrong-result — Fixes a bug where windowFunnel with strict_deduplication returned the previous event’s index instead of the actual maximum matched level when encountering duplicate events. Ensures correct funnel analysis results in strict_deduplication mode. (introduced in 26.3) #99003
  • Fix wrong results in LEFT ANTI JOIN with multiple join keys and runtime filters silent-wrong-result — Uses tuple-based NOT IN filter instead of per-column AND-combined filters for LEFT ANTI JOIN with runtime filters, and adds NULL bypass to avoid filtering out NULL keys. Ensures correct results for LEFT ANTI JOIN with multiple join key columns when enable_join_runtime_filters=1 (default). (introduced in 26.3) #98871
  • Fix set skipping-index detection with OR false constant silent-wrong-result — Fixes a bug where a set skipping-index was incorrectly considered usable when an OR condition included a constant false, leading to missed optimizations. Ensures that set skip indexes are only applied when they can actually filter rows, improving query performance and correctness. (introduced in 25.12, 26.1, 26.2) #98834 #98836 #98838
  • Fix sumCount aggregate function compatibility with older serialized states silent-wrong-result — Fixes sumCount aggregate function to correctly read older serialized states that were written before the introduction of Nullable(Tuple). Prevents errors or incorrect results when upgrading and querying tables with pre-existing sumCount aggregate states. (introduced in 26.1, 26.2) #98818 #98820
  • Fix set skipping-index detection for OR with constant false silent-wrong-result — Correctly ignores constant false children in OR predicates when evaluating set skip index applicability. Prevents incorrect index selection that could lead to wrong results or performance degradation. (introduced in 26.3) #98776
  • Fix zombie data resurrection after TRUNCATE/DETACH/ATTACH silent-wrong-result — Fixes a race condition where outdated data parts could be resurrected after cleaning up empty covering parts. Prevents data inconsistency and potential return of stale data after TRUNCATE and DETACH/ATTACH operations. (introduced in 26.3) #98698
  • Fix filter push-down corrupting output with non-boolean WHERE expressions silent-wrong-result — Fixes filter push-down optimization that caused BAD_GET and wrong results when non-boolean expressions appear in both WHERE and SELECT with a JOIN. Prevents silent wrong results and crashes in JOIN queries with complex expressions. (introduced in 26.3) #98681
  • Fix hasPartitionId returning true for non-existent partition IDs silent-wrong-result — Fixed a bug where hasPartitionId incorrectly returned true for partition IDs that did not exist but had a higher partition ID in the data part set. Prevents incorrect partition existence checks, which could lead to wrong query results or data operations. (introduced in 25.12, 26.1) #98565 #98567
  • Fix wrong results when distributed index analysis and query condition cache are both enabled silent-wrong-result — Fixed incorrect query results that occurred when using both distributed index analysis (experimental) and query condition cache, due to unsorted part ranges. Ensures correctness for users who enable both experimental features. (introduced in 26.2) #98563
  • Fix null-safe comparison with const Dynamic/Variant columns and NULL silent-wrong-result — Fixes a Bad cast from type ColumnConst to ColumnDynamic exception in <=> / IS NOT DISTINCT FROM and incorrect 0 results in IS DISTINCT FROM when comparing const Dynamic or Variant columns with NULL. Corrects query results and eliminates crashes for null-safe comparisons involving Dynamic/Variant types. (introduced in 26.3) #98553
  • Fix incorrect partition pruning with Nullable partition keys silent-wrong-result — Fixes min-max index merging for Nullable partition key columns by using accurate comparison instead of std::min/max, which inverted bounds and caused incorrect partition pruning. Prevents silently missing rows in query results when tables use Nullable partition keys, ensuring data correctness. (introduced in 26.3) #98405
  • Fix incorrect FINAL query results with mixed primary key and non-primary key skip indexes silent-wrong-result — Fix incorrect results of FINAL queries on ReplacingMergeTree when both primary key and non-primary key skip indexes are used; ensure deletion recovery is correctly handled. Prevents silent data loss or missing rows in FINAL queries with mixed skip indexes. (introduced in 26.1, 26.2) #98308 #98310
  • Fix wrong results with distributed index analysis and query condition cache silent-wrong-result — Fixes wrong results when using both distributed index analysis (experimental) and query condition cache, caused by unsorted part ranges. Ensures correct query results when both features are enabled. (introduced in 26.3) #98269
  • Fix incorrect FINAL results with mixed primary key and skip indexes silent-wrong-result — Fixes incorrect results in FINAL queries on ReplacingMergeTree when using both primary key and non-primary key minmax skip indexes, where the skip index could incorrectly disable deletion recovery. Ensures correct deduplication results when using skip indexes on non-primary key columns. (introduced in 25.12, 26.3) #98097 #98201
  • Fix text index inconsistency for has/mapContains functions silent-wrong-result — Fixes a bug where the has, mapContainsKey, and mapContainsValue functions could return different results when a text index was used versus without it, by correcting the index analysis logic. Prevents silent wrong results in text index queries, ensuring consistent behavior regardless of index usage. (introduced in 25.12) #98113
    • e.g. SELECT has(col, 'value') FROM table_with_text_index;
  • Remove incorrect replaceRegexpOne to extract rewrite silent-wrong-result — Removes the incorrect query rewrite that replaced replaceRegexpOne with extract, which produced wrong results when the regex didn’t match. Also fixes a LOGICAL_ERROR when used with GROUP BY … WITH CUBE and group_by_use_nulls=1. Ensures correct results for replaceRegexpOne queries and prevents crashes with CUBE. (introduced in 26.2) #98037
  • Remove incorrect replaceRegexpOne to extract rewrite causing wrong results silent-wrong-result — Removes an incorrect query rewrite that replaced replaceRegexpOne with extract, which produced wrong results when the regex didn’t match; also fixes a LOGICAL_ERROR when replaceRegexpOne is used with GROUP BY … WITH CUBE and group_by_use_nulls=1. Prevents silent wrong results and crashes in queries using replaceRegexpOne. (introduced in 25.12, 26.1, 26.3) #97546 #98033 #98035
  • Fix DUPLICATE_COLUMN and NULLs for Delta Lake struct fields with dots silent-wrong-result — Fix a bug where Delta Lake struct fields containing dots in their names caused DUPLICATE_COLUMN errors or silent NULLs when using column mapping ’name’ mode, by replacing faulty dot-splitting logic with correct prefix stripping. Ensures correct reading of Delta Lake tables with complex struct field names that contain dots, preventing silent data corruption. (introduced in 26.3) #98013
  • Fix parseDateTimeBestEffort parsing words starting with month/weekday prefixes silent-wrong-result — Corrects the parsing of strings that begin with month or weekday names (e.g., ‘Married’) to avoid erroneously interpreting them as dates. Prevents incorrect DateTime conversions of non-date strings. (introduced in 26.3) #97965
  • Fix partition pruning with row policy/PREWHERE and FINAL silent-wrong-result — Prevents indexes from incorrectly pruning data when querying with FINAL combined with row policy or PREWHERE, ensuring correct deduplication. Fixes a silent wrong-result issue that could return incomplete data. (introduced in 25.12) #97964
  • Fix incorrect results in GraceHashJoin with non-equi joins silent-wrong-result — Fixes a bug where leftover unprocessed blocks due to size constraints caused wrong join results when using the grace_hash algorithm with non-equi joins. Ensures correct query results for complex joins using the grace_hash algorithm. (introduced in 25.12, 26.1, 26.2) #97915 #97917 #97919
  • Fix incorrect results in grace_hash join with non-equi conditions and size limits silent-wrong-result — Corrects a bug in the GraceHashJoin algorithm where left blocks could be partially processed due to max_joined_block_size_rows constraints, leading to wrong results in non-equi joins. Ensures correct join results when using the grace_hash algorithm with non-equi conditions and result size limits. (introduced in 26.3) #97866
  • Fix unexpected results with read_in_order_use_virtual_row and monotonic functions silent-wrong-result — Fixes incorrect query results when the read_in_order_use_virtual_row setting is enabled and monotonic functions are used in ORDER BY or other contexts. Ensures correct query results in scenarios involving virtual row ordering with monotonic functions. (introduced in 26.3) #97837
  • Fix silent data corruption in INSERT SELECT with UNION ALL and JOIN silent-wrong-result — Fixes a regression where INSERT SELECT with UNION ALL and JOIN could produce incorrect string values in MergeTree tables due to ColumnConst not being materialized before squashing. Prevents silent data corruption that could occur in complex INSERT SELECT queries. (introduced in 25.12, 26.1, 26.2) #97019 #97763 #97765
  • Fix hasPartitionId returning false positive for non-existent partition IDs silent-wrong-result — Fixes hasPartitionId to return false when a partition with the requested ID does not exist, even if a higher partition ID exists in the data part set. Prevents incorrect detection of partition existence, which could affect queries and optimizations depending on partition info. (introduced in 26.3) #97748
  • Fix incorrect partition pruning for pre-epoch DateTime64 and Date32 silent-wrong-result — Fixes incorrect partition pruning when using toDate() with pre-epoch DateTime64 values, which could cause missing rows due to overflow. Ensures correct query results for partitions containing dates before epoch, preventing silent data loss. (introduced in 26.3) #97746
  • Fix incorrect ROLLUP/CUBE results with nested nullable LowCardinality silent-wrong-result — Fixed a logical error when using GROUP BY ... WITH ROLLUP/CUBE with keys that include LowCardinality(Nullable(...)) inside Nullable(Tuple(...)). The error caused key deserialization corruption due to incorrect serialized size calculation. Ensures correct aggregation results for complex key types in ROLLUP and CUBE queries. (introduced in 26.1) #97689
  • Fix incorrect ROLLUP/CUBE results on LowCardinality nullable columns in Nullable(Tuple) silent-wrong-result — Adds proper serialized value size calculation for ColumnLowCardinality when containing Nullable dictionaries, preventing key deserialization corruption during GROUP BY with ROLLUP or CUBE. Prevents silent wrong results in aggregation queries on columns of type LowCardinality(Nullable(…)) inside Nullable(Tuple(…)). (introduced in 26.2) #97647
    • e.g. SELECT k, count() FROM t GROUP BY k WITH ROLLUP
  • Fix index interaction with row policy/PREWHERE and FINAL silent-wrong-result — Fixed a bug where partition pruning and skip indexes could incorrectly prune data needed by FINAL for correct deduplication when row policies or PREWHERE are used. Prevents incorrect query results when using FINAL with row policies or PREWHERE. (introduced in 26.1) #97409
  • Fix sumCount aggregate function reading older serialized states silent-wrong-result — Fixed sumCount aggregate function to correctly read and finalize serialized states that were created prior to the introduction of Nullable(Tuple) format. Prevents incorrect NULL results when reading older sumCount states after upgrading. (introduced in 26.3) #97370
  • Fix min(timestamp) returning epoch after TTL merge when all rows filtered silent-wrong-result — Prevents the minmax index from returning incorrect epoch values when a TTL merge produces an empty block, causing min(timestamp) to return 1970-01-01. Ensures correct results from min aggregate on timestamp columns after TTL merges. (introduced in 25.12, 26.1) #97206 #97208

…and 746 more fixes in this range (see the changelog).

👆 Back to v26.3 versus 25.8 overview

Known issues and regressions

Misc

  • ALTER TABLE UPDATE freezes transitive MATERIALIZED columns at INSERT-time value (regression from #99281) — Description PR #99281 introduced && affected_materialized.contains(column.name) at line 863 of MutationsInterpreter.cpp to avoid recalculating MATERIALIZED columns that depend on EPHEMERAL columns (which cannot be read from disk during mutations). However, this guard also silently skips transitively-dependent MATERIALIZED columns, freezing them at their INSERT-time value permanently. (state: open) #100613
  • Performance regression with multiIf() + ARRAY JOIN in new analyzer (25.8) — Company or project name No response ### Describe the situation ## Description After upgrading from ClickHouse 23.4 to 25.8, queries using complex multiIf() expressions in GROUP BY combined with ARRAY JOIN became 3x slower (from 3 seconds to 9 seconds in production). The issue is caused by the new experimental analyzer (allow_experimental_analyzer=1, which is enabled by defau (state: open) #91430
  • s3Cluster table function: Performance regression after upgrading from 23.8 to 25.10 — Company or project name No response ### Describe the situation The s3Cluster table function query execution time increased from over 700s to 1300s. ### Which ClickHouse versions are affected? 25.10 ### How to reproduce ~200k Parquet files on object storage (total size around 3TB) are queried using the s3Cluster table function. The cluster consists of 4 nodes, each with 8 CPUs. The que (state: open) #90722
  • s3() tar archive reader silently drops column data with schema_inference_mode=union on heterogeneous parquet schemas (26.3 regression) — Company or project name Nominal (https://nominal.io) ### Describe the unexpected behaviour When reading multiple parquet files with different schemas from a tar archive via s3() with schema_inference_mode=union, columns that only exist in some files are silently returned as all null — even for files that do contain that column. For example, test_1.parquet has columns (timestamp, a) (state: closed) #101543

Bugfix

  • Vertical merge of Nested arrays corrupts data — Vertical merge of nested arrays causes silent data corruption in ReplacingMergeTree. Data can be lost or replaced with data from another order key. Horizontal merge works correctly. (state: open) #86123
  • Can’t roll back to v25.3 after upgrading to v25.8 — Upgrading to v25.8 and then downgrading to v25.3 fails due to a backward incompatible change in the default value of write_marks_for_substreams_in_compact_parts for MergeTree tables. Users cannot roll back without manually setting the compatibility setting. (state: abandoned) #86837
  • Cherry pick #100537 to 26.1: Fix heap-buffer-overflow in usearch — A heap-buffer-overflow in usearch when using an extremely large LIMIT with vector similarity search was fixed in master (#100537), but the cherry-pick to the 26.1 release branch was abandoned. Users on 26.1 remain vulnerable until the fix is manually backported or they upgrade to a newer version. (state: abandoned) #101686
  • Different stored/displayed DateTime for same INSERT between 26.2.3 and 26.2.4 with session_timezone — The same INSERT into a DateTime column with session_timezone set produces different stored values in 26.2.4 compared to 26.2.3, due to the default change of async_insert to 1. Setting async_insert=0 restores the old behavior. The issue was reported but not fixed. (state: abandoned) #100614
  • forward compatibility 26.3 -> 26.2 JSON / propagate_types_serialization_versions_to_nested_types — A JSON serialization change in ClickHouse 26.3 (propagate_types_serialization_versions_to_nested_types) makes parts unreadable by 26.2, causing complete data loss on downgrade. The issue was reported as unexpected but acknowledged as an intended break in forward compatibility. (state: abandoned) #101429
  • CREATE OR REPLACE statement replaces {table} macro in zk path with a random string — CREATE OR REPLACE on replicated tables corrupts the {table} macro in ZooKeeper path, causing silent data replication inconsistencies across nodes. (state: open) #55611
  • ANY JOIN returns wrong result with WHERE clause — ANY JOIN returns inconsistent results when a WHERE clause filters on a column from the right table; the projection optimization creates an extra column leading to an incorrect count. (state: open) #79189
  • DateTime64 with timezone is incorrectly constant-folded in PREWHERE by analyzer — The new analyzer incorrectly constant-folds DateTime64 comparisons in PREWHERE when querying a Distributed table, leading to wrong results around DST transitions. (state: open) #92208
  • parallel_distributed_insert_select default value of 2 is a silent source of errors — An issue reports that the default value of 2 for parallel_distributed_insert_select in 25.7+ causes silent data distribution errors when the sharding keys of source and target distributed tables differ. It is suggested to either revert to default 1 or implement a fallback to 1 when sharding keys differ. The issue remains open. (state: open) #100788
  • boost::program_options::split_unix throws on backslash escapes that boost::split handled as literals — The executable table function’s argument parsing was changed to support shell-style quotes, but the new parsing using boost::program_options::split_unix rejects unrecognized backslash escapes, causing previously valid queries with literal backslashes to fail with STD_EXCEPTION. (state: open) #101565
  • WITH FILL … INTERPOLATE is lost inside subquery/CTE when analyzer is enabled — When ORDER BY … WITH FILL … INTERPOLATE is used inside a subquery or CTE with the new analyzer enabled, the filled rows disappear. The issue is that the analyzer loses the INTERPOLATE clause when it is applied without explicitly naming columns. (state: open) #86151
  • Fix compatibility of some aggregate function states with String argument — A bug where aggregate function states containing strings changed serialization format in 25.8, breaking cross-version compatibility. A PR attempted to fix by adding a trailing zero byte for compatibility, but was abandoned in favor of a different approach. (state: abandoned) #86969
  • Part larger than max_bytes_to_merge_at_max_space_in_pool can not be deleted by ttl — Parts larger than max_bytes_to_merge_at_max_space_in_pool (default 150GB) cannot be deleted by background TTL merges, causing TTL to stall for those large parts. The issue is confirmed on recent versions from 24.8 onward, but no fix has been merged. (state: abandoned) #80681
  • [CI crash] HashJoin transform failed during block structure check — A crash (LOGICAL_ERROR) in HashJoin::addBlockToJoin occurs when query plan optimizations (outer-to-inner join conversion with join_use_nulls, filter push-down) change the right pipeline header after HashJoin creation. A fix was proposed but not merged due to concerns about the approach. (state: abandoned) #85459
  • ‘SELECT EXISTS’ query incorrectly produces 0 on ClickHouse 25.8.1 — SELECT EXISTS query incorrectly returns 0 on ClickHouse 25.8 due to a regression in subquery execution. The workaround is to disable the analyzer. No fix has been merged yet. (state: abandoned) #86415
  • ClickHouse 25.8.1.5101 Keeper exception — Issue reports that in ClickHouse 25.8.1.5101, all cluster nodes try to acquire the same ephemeral Keeper node for DDL task queues, causing LOGICAL_ERROR and timeouts. The problem may be due to improper handling of loopback host identifiers, but no fix PR is attached to this issue. (state: abandoned) #86434
  • approx_top_sum state format changed between 25.7 and 25.8 - null bytes appear in finalized strings — The aggregate state serialization format for approx_top_sum and similar functions changed in 25.8, causing null bytes to appear when finalizing states created in 25.7. This breaks cross-version compatibility. No fix has been merged yet. (state: abandoned) #86915
  • Incorrect results with GROUP BY WITH ROLLUP and uniqExact under specific column values — Issue reports that uniqExact with GROUP BY WITH ROLLUP produces incorrect results (blinking between correct and incorrect) under specific column values. The bug affects versions 25.6+. No fix has been merged; the issue appears abandoned. (state: abandoned) #86931
  • 25.8.3.66,delete/update on cluster problem — Distributed DELETE and UPDATE with lightweight updates (lightweight_delete_mode=lightweight_update) only affect the connected node, ignoring other shards. Bug introduced in 25.8.3, fixed in 25.9 via PR #87043, not backported. (state: abandoned) #87221
  • **Assertion (n >= (static_cast<ssize_t>(pad_left_) ? -1 : 0)) && (n <= static_cast<ssize_t>(this->size()))' after upgrade** — A backward incompatible change in PR #87300 escaped filenames for Variant subcolumns, causing assertion failures and crashes when upgrading from older versions that have JSON columns in MergeTree parts. Users must disable the escape_variant_subcolumn_filenames` setting before upgrade to avoid crashes. (state: abandoned) #91668
  • replaceRegexpOne returns different results depending on the value of optimize_rewrite_regexp_functions. — The replaceRegexpOne function returns empty string instead of the unchanged string when the regex pattern with ^…$ is not matched and the replacement contains backreferences, due to a bug in the optimize_rewrite_regexp_functions optimization. This regression affects versions from 25.8 onward. (state: abandoned) #93434
  • CH 25.12.2.54 - Incorrect query result when using skip indexes — A bug was reported in ClickHouse 25.12.2.54 where skip indexes cause incorrect query results when the WHERE clause contains OR and NOT conditions. A workaround exists (use_skip_indexes_for_disjunctions = 0) but no fix has been merged in this cluster. (state: abandoned) #94020
  • file() and url() table functions broken in 25.12.3.21 and 25.11.1.1 — The file() and url() table functions produce incorrect results when used with views and SELECT with multiple columns, due to a regression in Parquet native reader v3 and prewhere optimization. The issue affects versions 25.11 and 25.12, and can be worked around by disabling the native reader or prewhere optimization. (state: abandoned) #94289
  • Logical error: Cannot modify size limits to A in size and B in elements: not enough space freed. Current size: C/D, elements: E/F (G) (STID: 4012-44fe) — A fuzz test revealed a logical error when dynamically resizing SLRU cache limits (s3_cache), causing a crash. PR #96142 attempted to fix this but a later comment suggests the fix may not be complete. (state: abandoned) #95983
  • Grace hash bad result since v25.8 — Bug report that grace hash join produces incorrect results when grace_hash_join_initial_buckets is changed, introduced in v25.8. No fix PR was created, issue abandoned. (state: abandoned) #96510
  • MAX()/MIN() on Decimal columns with GROUP BY returns incorrect results — MAX()/MIN() on Decimal columns with GROUP BY return incorrect results since v26.1, likely due to a regression in JIT-compilation of aggregate functions introduced in PR #88770. No fix has been merged. (state: abandoned) #100740
  • SIGSEGV in ColumnMap::takeOrCalculateStatisticsFrom during MergingSortedAlgorithm — Server crashes with SIGSEGV during merging of Map columns due to unconditional statistics path in ColumnMap::takeOrCalculateStatisticsFrom. The issue affects versions with the Map statistics feature (introduced by #99200, backported to 26.3). No fix has been merged yet. (state: abandoned) #102390
  • Refreshable MV does not save local data on shards. Possible bug in documentation or CH — Refreshable Materialized View on Replicated database does not preserve data on all shards; data appears only on one shard randomly, while other shards lose data after refresh. This may be a bug in documentation or ClickHouse itself. (state: open) #88329
  • Logical error: Wrong file position — Running SELECT with ORDER BY and LIMIT on MergeTree tables with encrypted storage causes a logical error ‘Wrong file position’. The issue is reproducible on version 25.8 and likely 25.3, and only occurs on encrypted disks. (state: open) #89280
  • Protobuf input_format_protobuf_oneof_presence duplicates rows causing LOGICAL_ERROR — Protobuf input with input_format_protobuf_oneof_presence=true crashes with a LOGICAL_ERROR when reading a file that contains multiple values in a oneof field (which ClickHouse can generate). The issue is open and a related PR attempts to handle this gracefully. (state: open) #90669
  • Parquet regression: Invalid array of tuples — A regression in Parquet native reader v3 (introduced in 25.11) causes a false ‘Invalid array of tuples’ error when reading deeply nested parquet files containing arrays of different lengths in separate columns. The workaround is to disable the native reader v3 via a setting. No fix has been merged yet. (state: open) #91580
  • Correlated EXISTS subquery on same table silently returns wrong result (0 instead of correct count) — Correlated EXISTS subquery that references the same table as the outer query returns 0 instead of the correct count. The subquery is not evaluated per-row as in standard SQL, causing incorrect results without error. (state: open) #99310
  • createLightweightDeleteCommand does not copy mutation_version from source command — An issue reports that createLightweightDeleteCommand does not copy mutation_version, causing incorrect evaluation of perform_alter_conversions when combining lightweight deletes with ALTER MODIFY COLUMN. No fix PR has been submitted yet. (state: open) #101874
  • MergeMutate pool permanently wedges on addFuturePartIfNotCoveredByThem — The MergeMutate background pool permanently wedges when background_merges_mutations_concurrency_ratio > 1, causing replication progress to stall with no CPU or memory pressure. The fix/workaround is to avoid that setting and use a lower ratio with increased pool size. (state: open) #103781

Discussion

  • ALTER USER RENAME applies changes even after throwing ACCESS_ENTITY_ALREADY_EXISTS, causing RBAC corruption — When renaming a user to an existing name, ALTER USER RENAME throws an error but still partially applies the rename, causing RBAC corruption. This leads to duplicate usernames in system.users and subsequent operations failing. The bug was introduced in version 25.11 and is not yet fixed. (state: abandoned) #90320
  • Losing Data After upgrade when using Ceph volumes and no replication — User reports data loss after upgrading from 25.3 to 25.4/25.8 when using Ceph volumes without replication. Error shows massive broken parts exceeding the default limit (1 GiB), causing table load failure. Requires investigation to determine if a code change introduced stricter handling of broken parts. (state: open) #92086
  • Parquet native reader v3 returns incorrect results when filtering nullable string columns — Parquet native reader v3 returns incorrect results (zero rows) when filtering on nullable string columns with bloom filters enabled, compared to correct results with v2. This bug is reproducible in versions 26.2-26.4 and can lead to silent wrong query results. (state: abandoned) #102231

👆 Back to v26.3 versus 25.8 overview

v26.3.16.10001

Released 2026-07-03

Build report - 26.3.16.10001 | Release page

Changes compared to upstream's v26.3.16.16-lts

Build/Testing/Packaging Improvements

Let’s Install!

Linux packages for both AMD64 and Aarch64 can be found at builds.altinity.cloud/#altinitystable as either .deb, .rpm, or .tgz. Linux packages for upstream builds are at packages.clickhouse.com.

Altinity Stable Build images are available at DockerHub as altinity/clickhouse-server:26.3.16.10001.altinitystable.

For more information on installing ClickHouse from either the Altinity Builds or the upstream builds, see the ClickHouse Altinity Stable Builds Install Guide.

Please contact us at info@altinity.com if you experience any issues with the upgrade.