ClickHouse v24.5.7.31-stable 稳定版变更解析:九个关键缺陷修复的源码级解读
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
ClickHouse v24.5.7.31-stable 是 24.5 LTS 分支的一个维护性稳定发布,官方变更日志 v24.5.7.31-stable.md 记录了它相对 v24.5.6.45-stable 的全部九个用户可见的 Bug Fix,涉及 Parquet 读取路径、Schema 推断、日期函数、分布式表虚拟列、Variant 列与聚合函数等模块。本文逐条解读这些修复的具体问题、对应配置项与影响面,并结合当前仓库源码给出实现层面的佐证,帮助你在评估是否升级该版本时准确判断其收益与兼容性变化。
发布概览
该版本对应的提交为6c185e9aec1(基线为 v24.5.6.45-stable 的bdca8604c29),所有条目均标注为 "Backported in #xxxxx",表明它们是通过 backport 流程从 master 回合进 24.5 分支的。变更日志按三个区块组织:
- Bug Fix (user-visible misbehavior in an official stable release):9 条用户可见缺陷修复,是本次发布的全部内容主体;
- NO CL CATEGORY:1 条未分类条目(backport PR #68897);
- NOT FOR CHANGELOG / INSIGNIFICANT:2 条仅测试基础设施的修正(fault injection 开关、flaky 测试修复)。
这意味着这是一个"纯修复"型稳定版:没有新增功能,风险主要集中在个别行为兼容性变化上(后文第 3 节的schema_inference_make_columns_nullable是唯一一处需要关注行为变化的条目)。
日期函数修复:fromModifiedJulianDay 的上界纠正
问题:函数fromModifiedJulianDay把 Modified Julian Day 数值转换为YYYY-MM-DD文本日期。其声明支持的上界本应是9999-12-31,但此前被错误地设置成了9999-01-01,导致 12 月的合法输入被误判为越界。
源码佐证:当前仓库中该函数实现于 fromModifiedJulianDay.cpp,其文档注释明确写道:
This function supports day number from
-678941to2973483(which represent 0000-01-01 and 9999-12-31 respectively). It raises an exception if the day number is outside of the supported range.
即合法日号区间为-678941(0000-01-01)到2973483(9999-12-31),越界即抛异常。修复前实现与文档不一致,把9999-01-01当成了上界;修复后与文档注释声明的范围保持一致。对应 backport 追踪单为 #68996,修复 PR 为 #67583。
实战提示:如果你的 ETL 管道中存在依赖fromModifiedJulianDay处理 12 月份数据的逻辑(例如把 MJD 天号批量转成日期分区值),升级此版本后原本会抛异常的任务将恢复正常。
Parquet 读取修复:filter push down 遇到类型不匹配时不再崩溃
问题:当通过file()等表函数读取 Parquet 文件、且显式声明的列类型与文件实际类型差异很大时,Parquet 的 filter push down 路径会发生崩溃。变更日志给出的典型场景是:
SELECT * FROM file('a.parquet', Parquet, 'x String') -- 但文件中 x 实际是 Int64官方规避手段:在升级到本版本之前,可通过设置input_format_parquet_filter_push_down = 0关闭基于 WHERE/PREWHERE 与 Parquet 元数据 min/max 统计的 row group 跳过,作为临时规避。
源码佐证:当前仓库中该设置的定义见 FormatFactorySettings.h:
DECLARE(Bool, input_format_parquet_filter_push_down, true, R"( When reading Parquet files, skip whole row groups based on the WHERE/PREWHERE expressions and min/max statistics in the Parquet metadata. )", 0)其默认值为true,即默认启用 row group 级过滤跳过;相邻还有input_format_parquet_bloom_filter_push_down(默认开启)和input_format_parquet_dictionary_filter_push_down(默认 1024×1024 字节阈值)两项同类优化。对应 backport 追踪单 #68865,修复 PR #68131。
实战提示:这条修复对"宽表外部文件 + 显式 schema 声明"的容错能力是实质性提升——声明类型与物理类型不一致(StringvsInt64)不再意味着进程级崩溃。同时建议升级后检查是否还需要保留input_format_parquet_filter_push_down = 0的临时设置,可以安全移除以恢复读放大优化。
Schema 推断行为修正:schema_inference_make_columns_nullable 回归并新增 auto
这是本次发布中唯一一条行为兼容性相关的变更,需要重点理解:
- 此前 PR #61984 引入的改动使得即使设置
schema_inference_make_columns_nullable = 0,Parquet/Arrow 格式推断出的列仍可能变成Nullable,属于向后不兼容的行为漂移; - 本版本将其恢复为"0 = 永不推断 Nullable"的旧语义,同时为该设置引入新值
auto:仅当数据中带有可空性信息(样本中出现 NULL,或文件元数据声明了可空性)时才推断Nullable。
源码佐证:当前仓库中该设置的完整取值语义在 FormatFactorySettings.h 中有权威定义:
DECLARE(UInt64Auto, schema_inference_make_columns_nullable, 3, R"( Controls making inferred types `Nullable` in schema inference. Possible values: * 0 - the inferred type will never be `Nullable` (use input_format_null_as_default to control what do do with null values in this case), * 1 - all inferred types will be `Nullable`, * 2 or `auto` - the inferred type will be `Nullable` only if the column contains `NULL` in a sample that is parsed during schema inference or file metadata contains information about column nullability, * 3 - the inferred type nullability will match file metadata if the format has it (e.g. Parquet), always Nullable otherwise (e.g. CSV). )", 0)注意两点:类型是UInt64Auto(因此auto字符串可被接受),且当前仓库的默认值已是 3(跟随文件元数据)——这是 24.5 分支之后 master 继续演进的默认值,24.5.7.31 本身并未改变默认值,只是恢复了0的语义并让auto成为可用的显式选择。
实战提示:
- 显式使用
= 0且依赖"绝不出现 Nullable"的下游逻辑,升级后可放心; - 介于"全 Nullable"与"永不 Nullable"之间、希望由数据本身决定的场景,可以改用
= auto(或= 2)。
分布式查询修复:嵌套子查询中的 DateTime64 小常量不再被错误转成 Null
问题:分布式查询(Distributed 表场景)中,嵌套子查询返回的小型 DateTime64 常量会被错误地转换(transform)为 Null,进而导致查询报错甚至返回不正确的结果。这是变更日志中明确标注"possible incorrect query results"的严重性级别。
影响面:跨节点查询中,只要查询计划触发了嵌套子查询常量下推/提升路径、且常量为 DateTime64 小值(如toDateTime64('2024-01-01')之类),都可能命中该缺陷。对应 backport 追踪单 #68882,修复 PR #68323,同时关闭了长期存在的缺陷单 #50868。
实战提示:如果你的集群在 24.5 早期版本上出现过"同一查询本地正确、走 Distributed 表报错或结果偏 Null"的现象,且涉及 DateTime64,优先排查本条。
分布式表虚拟列回归:_table 与 _database 恢复
问题:虚拟列_table和_database在 24.3 版本之前一直可用(用于在查询 Distributed 表时标识数据来自哪个库/表),之后一度缺失。本版本将其重新加回。
实战提示:依赖_table/_database做多租户审计、来源统计的查询(例如SELECT _table, count() FROM distributed_table GROUP BY _table)升级后可直接恢复使用,无需再借助SETTINGS distributed_table_function_*之类的替代写法。对应 backport 追踪单 #69023,修复 PR #68672。
Variant 列修复:permutation 时的尺寸校验错误
问题:对 Variant 列做行重排(permutation,常见于ORDER BY物化、EXCHANGE等算子)时可能抛出错误:
Size of permutation (0) is less than required (...)错误信息中 permutation 尺寸为 0,说明 Variant 列在某些路径下没有正确实现 permutation 的尺寸契约。修复后该报错路径被消除。对应 backport 追踪单 #68858,修复 PR #68681。
实战提示:如果你已启用 Variant 列(实验性数据类型)并且排序大结果集时偶发此异常,本版本可直接解决。
哈希函数修复:sipHash(64/128)Keyed 的物化常量键
问题:在"以含数组为键的 Map 参与哈希"的场景下,sipHash64Keyed/sipHash128Keyed遇到物化常量键(materialized constant key)时处理不正确,导致哈希结果异常。
源码佐证:sipHash系列函数实现在 src/Functions/ 目录中(如 sipHash 相关实现文件),函数族由 FunctionFactory 统一注册;本条修复针对的是常量列在 Map-contains-array 键路径上参与 keyed 哈希时的取值。对应 backport 追踪单 #68784,修复 PR #68731。
实战提示:影响面相对窄,主要波及"常量键 + 复杂 Map 键 + keyed 哈希"三者同时出现的查询(例如对sipHash64Keyed(mapColumn, constKey)做去重或分桶)。常规无键哈希不受影响。
聚合函数修复:anyHeavy 状态合并可能产生错误结果
问题:近似去重/近似计数聚合函数anyHeavy在状态合并(partial state merge,即两阶段聚合的第二阶段)时可能返回错误结果。这类缺陷在单机小数据量下不易暴露,只在分布式/预聚合的分片状态合并时才显现。
对应 backport 追踪单 #69154,修复 PR #68950。
实战提示:如果你用anyHeavy做高基数近似 Top-N 且跨分片运行,建议升级;对结果精度敏感的关键报表可临时用精确集合聚合交叉验证。
其余修复与工程类条目
indexHint 大小写问题:fuzzer 发现的
indexHint函数大小写处理缺陷,backport 追踪单 #68564,PR #66286。涉及通过 indexHint 指定数据跳索引的查询解析。无分类条目:backport 单 #68940 / PR #68897,日志未给出描述("NO CL CATEGORY")。
测试基础设施(NOT FOR CHANGELOG):
- 关闭测试
01396_inactive_replica_cleanup_nodes_zookeeper中 insert 的 fault injection(#68828 / PR #68715); - 修复
01114_database_atomic的不稳定(flaky)表现(#69046 / PR #68930)。
这两条不影响用户行为,说明该稳定版同时清理了 CI 侧的测试噪声。
- 关闭测试
修复条目与 backport 追踪单对照表
| 模块 | 问题摘要 | Backport 单 | 修复 PR |
|---|---|---|---|
| Functions/indexHint | fuzzer 发现的大小写缺陷 | #68564 | #66286 |
| Functions/fromModifiedJulianDay | 上界误设为 9999-01-01 | #68996 | #67583 |
| Parquet reader | 类型不匹配时 filter push down 崩溃 | #68865 | #68131 |
| Schema inference | make_columns_nullable=0行为回归 + 新增auto | #69004 | #68298 |
| Distributed | 嵌套子查询 DateTime64 小常量被转为 Null | #68882 | #68323 |
| Distributed | 恢复_table/_database虚拟列 | #69023 | #68672 |
| Variant 列 | permutation 尺寸校验报错 | #68858 | #68681 |
| sipHash(64/128)Keyed | 物化常量键 + 数组键 Map 哈希错误 | #68784 | #68731 |
| anyHeavy | 状态合并可能产生错误结果 | #69154 | #68950 |
升级评估小结
v24.5.7.31-stable 是一个纯缺陷修复的稳定版,适合 24.5 用户直接跟进。按影响面排序,最需要关注的是:
- Distributed 场景下 DateTime64 常量被转 Null——唯一可能已造成"错误结果"的条目;
- Parquet 类型不匹配崩溃——外部文件读取容错性提升;
schema_inference_make_columns_nullable语义修正——唯一涉及行为变化的条目,0恢复旧语义、auto成为新选项(注意当前 master 默认值已演进为3,见 FormatFactorySettings.h,升级时以实际部署版本的设置默认值为准)。
其余条目(_table/_database虚拟列回归、Variant permutation、sipHashKeyed、anyHeavy、indexHint、MJD 日期上界)均为窄而明确的正确性修复。变更日志原文及各条目引用的源码路径(fromModifiedJulianDay.cpp、FormatFactorySettings.h)可在仓库中直接查阅复核。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考