news 2026/9/15 2:16:56

ClickHouse v21.6.5.37-stable 变更日志深度解析:14 项关键 Bug 修复的源码级解读

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse v21.6.5.37-stable 变更日志深度解析:14 项关键 Bug 修复的源码级解读

ClickHouse v21.6.5.37-stable 变更日志深度解析:14 项关键 Bug 修复的源码级解读

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

导读

本文以 ClickHouse 官方 v21.6.5.37-stable 版本的 变更日志 为骨架,逐条剖析该补丁版本中的 14 项 Bug 修复、1 项功能改进与 2 项内部优化。作为 v21.6.4.26-stable 的后续补丁版本,v21.6.5.37 集中修复了 21.6 主版本引入的回归问题(如LowCardinality参与IN时的类型转换崩溃)、长期存在的正确性隐患(如大整数CAST溢出返回错误结果)以及分布式场景下的异常行为(如Distributed Materialized View连接丢失列)。读完本文,你将掌握这些修复背后的代码机制、对应源码位置,以及如何通过查询设置与 SQL 复现、验证相关行为。

版本背景与修复概览

v21.6.5.37-stable 是 ClickHouse 21.6 稳定分支的第 5 个补丁版本,对比对象为 v21.6.4.26-stable。本次发布共包含 27 条条目,按类别划分如下:

类别数量主要内容
Improvement(改进)1后续 Bug 修复的准备工作(PR #23518)
Bug Fix(缺陷修复)14分布式、格式、聚合函数、类型系统、复制表、查询计划等核心模块的正确性修复
NOT FOR CHANGELOG(内部改动)2表达式编译与 ODBC 驱动适配

所有修复均以 backport(回移植)方式合入稳定分支,即先在主分支修复验证、再移植到 21.6 分支,因此每一条都带有对应的 backport 跟踪 issue 与原始 PR 编号。这些改动集中体现了补丁版本"只修 bug、不引功能"的发布策略。

Improvement:为后续修复铺路

本次唯一的 Improvement 条目来自 PR #23518(作者 Nikita Mikhaylov),其描述为"这里将列出我准备在此 PR 中修复的所有 bug"——这实际上是 ClickHouse 提交规范中用于聚合多个待修复问题清单的占位条目,其价值在于把分散的 issue 汇总到单一 PR 中进行统一跟踪和批量修复,属于流程性改进而非用户可见的功能变化。

14 项 Bug Fix 逐条源码解读

1. 修复Distributed Materialized View连接时的 "Missing columns" 异常

修复 PR:#24870(作者 Azat Khuzhin)

当用户通过Distributed表查询底层的Materialized View并执行JOIN时,可能抛出Missing columns异常。该问题的根因在于分布式查询在重组(rewrite)物化视图查询语句时,用于连接的列在部分执行节点上未正确推导,导致列名缺失。修复后,分布式物化视图与JOIN的组合查询能够稳定返回正确结果。

提示:分布式物化视图的列一致性依赖Distributed表引擎对查询的改写逻辑(见 src/Storages/Distributed 相关实现),若在集群中出现Missing columns,可优先排查视图定义与JOIN两侧表的列是否对齐。

2. 修复 Protobuf 格式拆分嵌套消息的序列化错误

修复 PR:#25000,对应 issue #24647(作者 Vitaly Baranov)

Protobuf输入/输出格式在序列化被拆分(split)的嵌套消息时存在错误:当一条 Protobuf 消息嵌套多层且字段被拆分到不同列时,序列化结果与原始结构不一致。修复后,Protobuf格式对嵌套Message类型的读写保持一致。该修复影响FORMAT Protobufinput_format_protobuf_*系列设置与对应字段映射逻辑,相关实现位于 src/Formats/FormatFactory.cpp 及 Protobuf 专属格式化器目录。

3. 区分不同表的KILL MUTATION,修复意外报错

修复 PR:#25025(作者 Azat Khuzhin)

此前执行KILL MUTATION时,如果集群中有多张表存在同名 mutation,命令可能错误地取消其他表的 mutation 并抛出Cancelled mutating parts异常。修复后的逻辑在定位 mutation 时严格绑定表标识,避免跨表误伤。这保证了 KILL MUTATION 语法(KILL MUTATION WHERE database = 'xxx' AND table = 'yyy')在多表并发变更场景下的精确性。

4. 修复CSVWithNames插入部分列时的报错

修复 PR:#25169,对应 issue #25129(作者 Nikita Mikhaylov)

使用CSVWithNames格式插入列的子集(非全部列)时,会抛出错误。修复后,CSVWithNames/CSVWithNamesAndTypes等带表头格式支持只提供部分列、按表头名匹配插入,与CSV系列格式的input_format_skip_unknown_fields等设置协同工作。该行为对数据导入工具的兼容性很重要,相关解析逻辑位于 src/Formats/FormatFactory.cpp。

5. 修复安装脚本中的 TOCTOU 竞态

修复 PR:#25277(作者 Alexey Milovidov)

TOCTOU(Time-of-check to time-of-use)是一类经典竞态漏洞:程序先检查文件状态、再基于该检查结果执行操作,而两者之间存在时间窗口可被利用。ClickHouse 官方安装脚本(curl | sh模式)中存在的该问题已被修复,提升了 安装脚本 的安全性。

6. 修复大整数CAST溢出:CAST(1e19 AS UInt128)不再返回 0

修复 PR:#25279(作者 Alexey Milovidov)

这是本次最值得关注的正确性修复之一。在旧版本中,浮点数1e19大于UInt64的最大值18446744073709551615(约 1.84e19)但小于UInt128的上限,CAST(1e19 AS UInt128)却错误地返回了0,同时伴随 UBSan(未定义行为消毒器)报告。根因是大整数转换路径中对浮点中间值到 128 位整数的转换存在溢出处理缺陷。

修复后:

SELECT CAST(1e19 AS UInt128); -- 正确返回 10000000000000000000

该修复同时消除了 UBSan 报错,说明问题本质是 C++ 层未定义行为(整数溢出)被正确规避。UInt128/UInt256的实现位于 src/Common/wide_integer.h,浮点转换逻辑位于 src/Common/wide_integer_to_string.cpp,读者可在其中看到大整数的内部表示与溢出边界处理。

7. 修复joinGetOrNull在非空列上的行为

修复 PR:#25288,对应 issue #24261(作者 Amos Bird)

joinGetOrNulljoinGet的区别在于:当 join key 在连接表中不存在时,joinGetOrNull返回NULL,而joinGet直接报错。旧版本中,当连接的取值列本身是非空列(not-nullable)时,joinGetOrNull在 key 缺失场景下没有正确构造Nullable包装,导致行为异常。修复后,无论取值列是否允许 NULL,joinGetOrNull都能正确返回NULL

从源码看,两个函数共用同一个 OverloadResolver(src/Functions/FunctionJoinGet.cpp),通过effective_or_null布尔标志区分,并在joinGetCheckAndGetReturnType中决定返回类型是否需包一层Nullable。官方文档示例(src/Functions/FunctionJoinGet.cpp内嵌文档):

-- 构造 Join 引擎表 CREATE TABLE id_val(`id` UInt32, `val` UInt32) ENGINE = Join(ALL, LEFT, id); INSERT INTO id_val VALUES (1, 11); -- joinGetOrNull:key 不存在时返回 NULL 而非报错 SELECT joinGetOrNull(id_val, 'val', toUInt32(1)), joinGetOrNull(id_val, 'val', toUInt32(999));

注意:Join引擎表及其joinGet系列函数对 key 的哈希布局敏感,此处示例仅为验证修复后的 NULL 语义,实际使用时请参照 Join 引擎文档 配置。

8. 修复LowCardinality参与IN时的Bad cast崩溃

修复 PR:#25290,对应 issue #25187(作者 Nikolai Kochetov)

这是 21.6 主版本引入的回归问题。当LowCardinality列作为IN子句的左侧参数时,会抛出:

Bad cast from type DB::ColumnLowCardinality to DB::ColumnVector<char8_t>

根因在于IN操作符在比较路径中未对LowCardinality列做解包(unwrap)处理,错误地试图将其直接转为ColumnVector<char8_t>。修复后,LowCardinality参数参与IN查询可正常工作,且不丢失低基数优化的性能收益。LowCardinality类型的实现位于 src/Columns/ColumnLowCardinality.h,该崩溃的报错文案"Bad cast from type"来自 src/Common/typeid_cast.cpp 中的类型转换失败路径。

9. 修复min/maxMapArray/Tuple上的 Logical Error

修复 PR:#25298(作者 Kruglov Pavel)

minMap/maxMap系列函数在参数为ArrayTuple类型时抛出Cannot sum Array/Tuple的 Logical Error。修复后,map 类聚合函数在计算键值对的 min/max 时不再误调用求和逻辑。相关实现位于 src/AggregateFunctions/AggregateFunctionsMinMaxMap.cpp,Map类型数据结构的定义可参考 src/DataTypes/DataTypeMap.h。

10.SummingMergeTree支持SimpleAggregateFunction(LowCardinality)

修复 PR:#25300,对应 issue #25134(作者 Nikolai Kochetov)

此前在SummingMergeTree表中声明SimpleAggregateFunction(...)包裹的LowCardinality列会报错。修复后,SummingMergeTree正确支持该组合:

CREATE TABLE t ( key UInt64, value SimpleAggregateFunction(sum, LowCardinality(UInt64)) ) ENGINE = SummingMergeTree ORDER BY key;

该修复让SummingMergeTree的预聚合列可以使用LowCardinality压缩存储,兼顾写入聚合与存储优化。SimpleAggregateFunction的解析与存储逻辑位于 src/DataTypes/DataTypeAggregateFunction.h 及 src/AggregateFunctions 目录。

11. 修复 ZooKeeper 断连时ReplicatedMergeTree后台任务阻塞重连

修复 PR:#25306(作者 Alexander Tokmakov)

这是一个可用性关键修复。当ReplicatedMergeTree表失去 ZooKeeper 连接时,后台任务(如 merge、mutation)会等待连接恢复,反而阻塞了表尝试重连的流程,形成互相等待。修复后,ZooKeeper 连接丢失时后台操作会被强制停止,表立即进入重连流程,缩短了复制表的故障恢复时间。相关实现位于 src/Storages/StorageReplicatedMergeTree.cpp,其 ZooKeeper 会话管理依赖 src/Common/ZooKeeper 目录下的客户端实现。

12. 修复quantileDeterministic等函数的非确定性行为

修复 PR:#25313,对应 issue #20480(作者 Alexey Milovidov)

quantileDeterministic这类函数要求:相同输入必须产生相同输出(确定性),因此它采用基于哈希的确定性水库抽样(ReservoirSampler),而非依赖随机数。旧版本中其行为可能出现非确定结果。修复后,quantileDeterministic及同类函数保证了跨节点、跨运行的确定性。

从源码结构看,NameQuantileDeterministic与底层确定性采样器位于 src/AggregateFunctions/AggregateFunctionQuantile.h,其有状态实现为 src/AggregateFunctions/ReservoirSamplerDeterministic.h。值得注意的是,src/Core/ProtocolDefines.h 中专门定义了"序列化quantileDeterministic状态的 skip degree",说明该修复还涉及状态合并时稀疏化(thinning)的一致性——这正是非确定性问题的来源之一。

13. 修复query_plan_filter_push_down优化丢失WHERE条件

修复 PR:#25370,对应 issue #25368(作者 Nikolai Kochetov)

这是查询优化器层面的关键正确性修复。新查询计划优化器(Query Plan)中的"过滤条件下推"优化在特定查询形状下会丢失WHERE条件,导致返回错误结果集。该优化由设置query_plan_filter_push_down控制,默认开启(1)。

从源码看,该设置定义于 src/Core/Settings.cpp:

query_plan_filter_push_down = 1(默认开启)
  • 0 - 禁用
  • 1 - 启用

官方注释明确:该优化将过滤器沿执行计划向下移动,且仅在query_plan_enable_optimizations = 1时生效,属于专家级调试设置。其核心实现在 src/Processors/QueryPlan/Optimizations/filterPushDown.cpp,该文件包含约 1430 行逻辑,针对FilterStepJoinStepAggregatingStepWindowStep等各步骤实现安全的下推规则(含分组集合、标识符归属检查等边界处理)。

如果你在生产环境中遇到"加了WHERE条件但结果没过滤"的可疑行为,可以临时执行:

SET query_plan_filter_push_down = 0; SET query_plan_enable_optimizations = 0;

复跑查询对比结果以确认是否触发该优化缺陷,同时向官方提交 issue 附带EXPLAIN PLAN输出。

14. 修复 DDL 中REPLACE列变换器的引号处理

修复 PR:#25391,对应 issue #23925(作者 Amos Bird)

REPLACE列变换器(column transformer)在用于 DDL(如CREATE TABLE ... AS SELECT ... REPLACE(...))时,格式化后的查询语句未正确加引号,导致含特殊字符的表达式执行失败。修复后,DDL 语句生成会对变换器内容做正确的引号转义。列变换器的解析与格式化实现位于 src/Parsers/ASTColumnsMatcher.cpp 与 src/Parsers/ASTColumnsTransformers.cpp,REPLACE变换器的完整语义见 SELECT 语句文档 中的COLUMNS变换器章节。

内部改动(NOT FOR CHANGELOG)

本版本还包含两条不面向用户的内部改动:

  1. ExpressionActions 只编译必要部分(PR #24273,作者 Maksim Kita):优化表达式动作(ExpressionActions)的编译范围,避免为不参与计算的动作生成多余代码,属于查询执行路径的性能打磨。
  2. ODBC 修复(PR #25045 中的 ODBC 相关 helper)的兼容性问题,保证 ODBC 表函数 正常工作。

升级建议与验证清单

v21.6.5.37-stable 没有引入任何破坏性变更,属于纯修复型补丁,建议所有 21.6 用户升级。升级后建议按以下清单回归验证:

  1. 类型与聚合:执行CAST(1e19 AS UInt128)应返回10000000000000000000;用LowCardinality列执行IN查询不再崩溃;minMap/maxMap传入Array/Tuple不再报 Logical Error;SummingMergeTree可正常声明SimpleAggregateFunction(sum, LowCardinality(UInt64))列。
  2. Join 与分布式joinGetOrNull在 key 缺失且取值列为非空列时返回NULLDistributed表连接Materialized View不再抛Missing columns
  3. 复制与故障恢复:模拟 ZooKeeper 断连,ReplicatedMergeTree应快速进入重连而非被后台任务阻塞;多表并发KILL MUTATION不再误取消。
  4. 格式与 DDLCSVWithNames部分列插入、Protobuf 拆分嵌套消息序列化、DDL 中REPLACE列变换器均回归正常。
  5. 查询优化器:默认开启的query_plan_filter_push_down优化不再丢失WHERE条件;如对结果存疑,可用SET query_plan_filter_push_down = 0对比验证。

完整变更条目清单见仓库 docs/changelogs/archive/v21.6.5.37-stable.md,更早版本的回溯可查阅 docs/changelogs 目录下的归档文件。

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 2:16:29

房产委托过户公证需要什么证件? 材料清单、异地远程办理操作指南

很多人因为身在外地&#xff0c;没法亲自到场办房产过户&#xff0c;就会选择办理房产委托过户公证&#xff0c;授权他人代为完成房产交易、过户相关手续&#xff0c;办理房产委托过户公证&#xff0c;核心需要委托人身份证、受托人的身份信息、不动产权证&#xff08;房产证&a…

作者头像 李华
网站建设 2026/9/15 2:14:01

LDW模型实战:行分类车道线检测从训练到端侧部署

简介&#xff1a;面向ADAS算法工程师、自动驾驶测试工程师以及车辆工程专业学生&#xff0c;这套车道偏离警告&#xff08;LDW&#xff09;模型实现与仿真验证资料&#xff0c;完整覆盖了从车道线特征提取、车辆轨迹预测到偏离报警策略的核心算法链路&#xff0c;可用于Simulin…

作者头像 李华
网站建设 2026/9/15 2:13:33

微电网中柴油发电机Simulink建模与仿真实践

1. 柴油发电机仿真系统概述柴油发电机作为微电网系统中的关键备用电源&#xff0c;其仿真建模对于系统稳定性分析和控制策略验证至关重要。在Matlab/Simulink环境下搭建柴油发电机模型&#xff0c;可以模拟其动态响应特性、燃油消耗率以及并网/离网切换过程。典型的仿真系统需要…

作者头像 李华
网站建设 2026/9/15 2:09:58

30天地图挑战复盘:用QGIS与Python打造数据可视化作品集

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 2:09:53

Agent技能评估三层次:Trigger校验、原子化拆解与闭环优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 2:08:33

AI 3D工作坊实战记录:从文本生成到3D打印的完整流程

第一次参加在京都办的AI 3D工作坊&#xff0c;说实话我本来是带着半好奇半怀疑的心态去的。作为长期用传统3D建模软件干活的人&#xff0c;我总觉着AI生成模型“只能看不能用”&#xff0c;但整场活动从演示到实操折腾下来&#xff0c;我的看法确实被改变了不少。这篇文章就把这…

作者头像 李华