ClickHouse v23.10.6.60-stable 更新详解:22 项 Bug 修复与源码定位
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
本文基于当前仓库中的版本更新日志 v23.10.6.60-stable.md,逐项解读 ClickHouse v23.10.6.60-stable(对照 v23.10.5.20-stable)这一稳定补丁版本的全部变更:22 项 Bug 修复、2 项功能改进与 1 项构建修复。文中每一项变更都尽量回溯到仓库中的源码实现位置(如 src/Interpreters/、src/Functions/、src/Storages/MergeTree/),帮助你在升级到该版本前评估其对 Nested 类型、ALTER 语句、投影(Projection)、物化变更(Mutation)、JSON 格式解析与复制表监控等具体场景的实际影响。
版本概览
- 版本标识:v23.10.6.60-stable,构建 commit
68907bbe643 - 对照基线:v23.10.5.20-stable(commit
e84001e5c61) - 变更构成:Improvement 2 项、Build/Testing/Packaging 1 项、Bug Fix 22 项、内部/无分类变更若干
- 发布性质:v23.10 系列稳定分支上的补丁版本(patch release),按惯例仅包含 bug 修复、回移(backport)修复与工程化改进,不包含新功能的默认行为变更
作为运维或开发者的判断基准:如果你运行的是 v23.10.5.x,本版本属于"可放心跟进"的稳定性补丁;尤其涉及 Nested 建表、复制表监控、Kafka 消费者状态表的用户,下文相关条目与你的线上行为直接相关。
改进(Improvement)
回移修复:transfer query 生成 MySQL 兼容语句
- 回移自上游 #58493:将 transfer query(数据转移查询)改写为 MySQL 兼容的查询形式,修复上游问题 #57253、#52654、#56729(对应 PR #56456,作者 flynn)。
该修复影响 ClickHouse 与 MySQL 之间的数据交换路径:在执行跨系统数据转移(例如通过 transfer 相关流程向 MySQL 导出)时,原本生成的 SQL 可能不符合 MySQL 语法约定,导致执行失败;修复后语句在 MySQL 侧可正常解析执行。
回移修复:获取 PostgreSQL 表结构时空数组导致 SIGABRT
- 回移自上游 #57659:处理通过 PostgreSQL 外部表获取表结构(table structure)时遇到空数组触发的
SIGABRT崩溃(对应 PR #57618,作者 Mike Kot)。
这是一次典型的"外部目录解析健壮性"修复:当外部 PostgreSQL 表中存在空数组字段时,元数据解析路径此前会因断言失败而中止进程。修复后该路径降级为正常处理,不再导致服务崩溃。
Bug 修复:Schema 与 ALTER 操作
仅当 flatten_nested=1 时才展平真正的 Nested 类型
- 修复:此前
flatten_nested设置会无差别地展平所有Array(Tuple(...))列;本版本修正为只展平真正的Nested类型列(PR #56132,作者 Kruglov Pavel)。
这是本版本中值得重点理解的一项修复。flatten_nested是会话/服务器级设置,在源码中定义于 src/Core/Settings.cpp(约 L5780 起),默认值为true:
- 取
1(默认):Nested列被展平为若干独立的数组列,例如n Nested(a UInt32, b UInt32)变为`n.a` Array(UInt32)、`n.b` Array(UInt32); - 取
0:Nested列保持单个数组元组的形态,且可以表示任意层级的嵌套结构。
设置文档(内嵌于 Settings 源码)给出了示例:
SET flatten_nested = 1; CREATE TABLE t_nest (`n` Nested(a UInt32, b UInt32)) ENGINE = MergeTree ORDER BY tuple(); SHOW CREATE TABLE t_nest; -- 结果:`n.a` Array(UInt32), `n.b` Array(UInt32)SET flatten_nested = 0; CREATE TABLE t_nest (`n` Nested(a UInt32, b UInt32)) ENGINE = MergeTree ORDER BY tuple(); SHOW CREATE TABLE t_nest; -- 结果:`n` Nested(a UInt32, b UInt32)展平的实现工具集中在 src/DataTypes/NestedUtils.cpp 与 src/DataTypes/NestedUtils.h,建表时的类型转换逻辑位于 src/Interpreters/InterpreterCreateQuery.cpp。修复前的行为意味着:一张包含普通Array(Tuple)列的表,在flatten_nested=1(默认值)下可能被误当成 Nested 结构展平,从而改变表结构与查询语义;修复后"是不是真正的 Nested 类型"成为展平的唯一判据,普通Array(Tuple)列不再受该设置影响。
修复 ALTER COLUMN ... ALIAS
- 修复带
ALIAS的ALTER COLUMN操作(PR #56493,作者 Nikolay Degterinsky)。
ALIAS列是 ClickHouse 的虚拟列机制(不落盘、查询时按表达式求值)。此前对已有列执行ALTER COLUMN ... ALIAS的路径存在缺陷,本版本修复了该 DDL 路径。相关 DDL 解释器逻辑位于 src/Interpreters/ 目录下的 Alter 解释器实现。
阻止对投影列的不兼容 ALTER
- 防止对投影(projection)列执行不兼容的
ALTER变更(PR #56948,作者 Amos Bird)。
投影是 MergeTree 的预聚合/预物化视图机制,投影列的存储布局与主表数据耦合。对投影列执行与既有物化结构不兼容的ALTER(例如改类型、改聚合函数形态)会导致投影数据与实际数据无法对应。本版本在变更入口增加校验,直接拦截这类不兼容操作,避免产生静默的元数据不一致。
Bug 修复:查询执行与优化
修复"部分物化普通投影"导致的错误 JOIN 计划
- 修复在存在"部分物化的普通投影"时生成的错误 JOIN 执行计划(PR #57196,作者 Amos Bird)。
"部分物化"指投影文件在后台物化过程中只覆盖了部分数据分区。规划器在评估能否使用投影回答 JOIN 时,若未正确区分"投影完整"与"投影仅部分可用",会生成错误的执行计划(例如错误地跳过主数据扫描)。本版本修正了该判断逻辑,确保部分物化场景下 JOIN 计划仍然正确。
LIMIT-only 查询禁用 MergeTreePrefetchedReadPool
- 对仅含
LIMIT的查询禁用MergeTreePrefetchedReadPool预取读池(PR #58505,作者 Maksim Kita)。
预取读池通过多线程批量预取数据块来优化大范围扫描,但对"扫描行数极少、只取前 N 行"的 LIMIT 类查询而言,多预取线程的启动开销反而大于收益,甚至可能放大尾延迟。本版本识别这类查询并绕过预取池,走低开销的读取路径。
Bug 修复:MergeTree 存储、物化变更与复制
含 Nullable MATERIALIZED 列的表 ALTER UPDATE 段错误
- 修复含
Nullable类型MATERIALIZED列的表执行ALTER UPDATE(mutation)后的段错误(PR #57147,作者 Nikolay Degterinsky)。
MATERIALIZED列在 mutation 重写数据块时需要按表达式重新求值并填充;Nullable包装增加了额外的空值指针层。此前该组合在 mutation 数据流中触发了内存越界访问。这是数据变更(mutation)路径上的崩溃类修复,涉及 src/Storages/MergeTree/ 下的 mutation 执行实现。
后台合并正确复用缓存中的临时数据存储
- 后台合并(background merge)现在正确地在缓存中使用临时数据存储(PR #57275,作者 vdimir)。
在"写盘路径挂缓存"(如cache_disk)的部署形态下,merge 过程中产生的中间数据块需要落在缓存管理的临时存储内,而不能直接落到缓存背后的慢速原始介质。本版本修复了后台 merge 任务在此场景下的落盘路径,保证临时数据的生命周期由缓存统一管理。
Mutation 复用源数据分区的索引粒度
- MergeTree 的 mutation 结果分区复用源分区的索引粒度(index granularity)设置(PR #57352,作者 Maksim Kita)。
索引粒度(index_granularity,默认 8192 行一个主键索引标记)决定了标记文件的密度与查询跳过能力。此前 mutation 重写出的分区可能使用默认粒度而非源分区粒度,造成同一表内不同分区索引密度不一致,影响查询跳过效率与空间占用。本版本使 mutation 结果继承源分区的粒度配置。
修复删除含"损坏 detached 分区"副本后 Blob 丢失
- 修复在删除带有 broken detached parts 的副本后出现 blob 丢失的问题(PR #58333,作者 Alexander Tokmakov)。
该项涉及共享存储(Shared MergeTree 一类)场景中的对象(blob)引用生命周期:删除副本时若其目录下存在无法读取的 detached 分区,清理逻辑此前可能误删仍被其他副本引用的远端对象。修复后清理流程对损坏 detached 分区做了隔离处理,不再级联丢失共享对象。
Bug 修复:函数与格式解析
修复 jsonMergePatch 对部分常量列的处理
- 修复
jsonMergePatch函数在输入包含部分常量列(partially const columns)时的错误行为(PR #57379,作者 Nikolay Degterinsky)。
jsonMergePatch实现于 src/Functions/jsonMergePatch.cpp(函数注册名JSONMergePatch,别名jsonMergePatch)。向量引擎中"常量列"是特殊的单值物化优化形态,当两路 JSON 列一路为常量、一路为普通列时,逐元素 patch 逻辑此前会取错指针或索引。该函数是 JSON Patch(RFC 7396 风格 merge patch)的数据库化入口,修复后在混合常量/非常量列上行为正确。
JSONCompactEachRow 并行解析:先移除、后修复的两次迭代
- 移除:先移除了
JSONCompactEachRow格式的并行解析(PR #58181,作者 Alexey Milovidov); - 修复:随后修复了该格式的并行解析实现并重新启用(PR #58250,作者 Kruglov Pavel)。
这一"先禁用、后修复"的组合值得注意:说明并行解析路径存在缺陷(可能与共享读缓冲区竞争有关,见下一条修复),团队选择以最小风险先回退为串行解析保证正确性,再提交修复版本。最终态是"修复后的并行解析"。
修复 StreamingFormatExecutor 中读缓冲区的使用
- 修复流式格式执行器(
StreamingFormatExecutor)中读缓冲区(read buffers)的工作方式(PR #57438,作者 Kruglov Pavel)。
流式格式执行器支撑了"客户端直读 MergeTree 数据文件"等旁路查询路径(绕过常规查询流水线)。该路径与常规读路径共享底层读缓冲区,缓冲区状态(位置、剩余量)在两条路径间切换时若未正确管理,会读到越界或错位的字节。本版本修复了该缓冲区管理问题。
Bug 修复:系统命令、访问控制与安全
正确解析 SYSTEM STOP LISTEN TCP SECURE
- 修复
SYSTEM STOP LISTEN TCP SECURE系统命令的解析错误(PR #57483,作者 joelynch)。
该命令用于停止监听安全的 TCP 端口(例如故障排查时临时关停加密接入)。此前由于子命令关键词组合的解析缺陷,命令无法被正确识别执行。系统命令的解析与执行逻辑位于 src/Interpreters/InterpreterSystemQuery.cpp 等文件。
管理副本化访问实体时忽略 GRANT/REVOKE 的 ON CLUSTER 子句
- 对用于管理"副本化访问实体"(replicated access entities)的
GRANT/REVOKE查询,忽略其ON CLUSTER子句(PR #57538,作者 MikhailBurdukov)。
ClickHouse 支持将用户、角色、权限定义本身放到 Keeper/ZooKeeper 上做多副本一致管理(replicated access management)。这类语句的一致性由副本机制保证,ON CLUSTER广播反而是冗余且可能引发歧义的;本版本在解析阶段对这类语句明确忽略该子句。
默认关闭 system.kafka_consumers(因潜在内存泄漏)
- 出于潜在的常驻内存泄漏(live memory leak)考虑,默认禁用
system.kafka_consumers表(PR #57822,作者 Azat Khuzhin)。
system.kafka_consumers是监控 Kafka 引擎消费者进度的系统表,读取时需要实时查询各 Kafka 消费任务状态。此前该表存在内存持续增长的风险,因此本版本将其默认关闭(需要显式开启才可见),属于"先止血"的保守处理。受 Kafka 引擎消费监控依赖该表的告警/巡检逻辑需要相应调整。
修复 BLAKE3(Rust 实现)的非法内存访问
- 修复 BLAKE3 哈希函数 Rust 实现中的非法内存访问(PR #57876,作者 Raúl Marín)。
ClickHouse 的 BLAKE3 计算路径由 Rust 组件实现(见 rust/ 工作区及 contrib/ 中的 Rust 依赖管理),C++ 侧通过边界层调用。非法内存访问类修复属于内存安全加固,消除潜在的越界读写风险。
CREATE INDEX 中函数名规范化
- 在
CREATE INDEX(表内二级索引)中规范化函数名(PR #57906,作者 Alexander Tokmakov)。
索引表达式中的函数此前可能存在大小写/别名不一致导致的存储形态问题;本版本统一规范化函数名,保证同一索引函数在不同写法下得到一致的存储与查询展开形态。
修复 Keeper 上的非法预处理(preprocessing)
- 修复在 Keeper 上执行时的非法查询预处理问题(PR #58069,作者 Antonio Andelic)。
当 ClickHouse 以 Keeper(Raft 一致性存储,见 programs/keeper/、src/Coordination/)作为依赖运行相关组件时,部分查询在预处理阶段走了错误的展开路径。本版本修正了 Keeper 场景下的预处理行为。
修复 Poco::UTF32Encoding 中的整型溢出
- 修复第三方库 Poco 的
Poco::UTF32Encoding中的整型溢出(PR #58073,作者 Andrey Fedotov)。
Poco 是仓库内置的 C++ 基础库(源码位于 base/poco/,含 Foundation、Net、XML 等模块)。UTF32 编码转换中的整型溢出属于输入边界未校验问题,在极端编码输入下可导致越界计算。该修复直接落在仓库内置的 Poco 副本上,随 ClickHouse 整体发布。
可观测性修复:ReadonlyReplica 指标
- 修复所有场景下
ReadonlyReplica指标的统计正确性(PR #57267,作者 Antonio Andelic)。
ReadonlyReplica是衡量"当前有多少复制表副本处于只读状态"的关键监控指标,基于CurrentMetrics实现。从源码结构看,指标的加/减操作分布在 src/Storages/StorageReplicatedMergeTree.cpp(如 L5950 的CurrentMetrics::add)、src/Storages/MergeTree/ReplicatedMergeTreeAttachThread.cpp(L94/L104 的加/减)与 src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp(L118/L428/L436)等多条线程路径上。只读副本的进入/退出涉及 attach 线程、restart 线程、存储主逻辑等多个入口,任一入口漏加或漏减都会使指标漂移。本版本统一修复了各路径的配对关系,使system.metrics中的该值在所有状态下与实际只读副本数一致——这对基于该指标触发告警的高可用部署尤为重要。
构建 / 测试 / 打包与内部变更
修复 Docker 官方镜像构建问题
- 回移自上游 #57586:修复在 Docker 官方镜像(official-images)审查中被发现的构建问题(PR #57571,作者 Mikhail f. Shiryaev)。
该项保证v23.10.6.60标签的官方 Docker 镜像能顺利通过构建与推送流程,仓库中的构建与镜像相关脚本参见 docker/ 目录。
内部/对最终用户无影响的变更(NOT FOR CHANGELOG / NO CL CATEGORY)
以下变更属于 CI、工具链与测试基础设施,不改变产品行为,此处按原日志完整保留:
- 回移自上游 #57916:无分类变更(PR #57909,作者 Alexey Milovidov);
- 固定(pin)集成测试辅助容器的 alpine 版本(PR #57669,作者 Mikhail f. Shiryaev);
- 移除较重的 rust stable 工具链(PR #57905,作者 Mikhail f. Shiryaev);
- 修复集成测试使用的 Docker 镜像(修复 CI)(PR #57952,作者 Azat Khuzhin);
- 修复
test_user_valid_until测试(PR #58409,作者 Nikolay Degterinsky)。
升级评估建议
- 常规跟进:本版本是 v23.10 稳定分支上的补丁,变更以修复为主,无默认行为破坏性变更,运行 v23.10.5.x 的集群可以按常规流程滚动升级。
- 重点核对项(如果你的工作负载涉及以下场景,建议逐项确认):
- 使用
Nested建表、且表中含Array(Tuple)列 → 对照本文flatten_nested一节,修复后建表结果更符合设置语义; - 依赖
system.metrics中ReadonlyReplica做告警 → 修复后指标更准,注意升级前后基线可能变化; - 使用
system.kafka_consumers监控 Kafka 消费 → 本版本默认禁用,需评估告警链路; - 依赖
JSONCompactEachRow高并发导入 → 最终态为修复后的并行解析,性能应恢复到预期水平; - 使用投影(projection)+ JOIN 的工作负载 → 升级前建议用生产查询抽样回归验证计划。
- 使用
- 验证方式:升级后可通过
SELECT version()确认版本为23.10.6.60,并对照 docs/changelogs/ 目录中相邻版本日志核对变更集。
附:变更条目与源码位置对照
| 变更主题 | 上游 PR | 本仓库可对照的源码位置 |
|---|---|---|
| flatten_nested 展平逻辑 | #56132 | src/Core/Settings.cpp、src/DataTypes/NestedUtils.cpp、src/Interpreters/InterpreterCreateQuery.cpp |
| ALTER COLUMN ALIAS / 投影列 ALTER | #56493、#56948 | src/Interpreters/、src/Storages/MergeTree/ |
| Nullable MATERIALIZED mutation 段错误 | #57147 | src/Storages/MergeTree/ |
| ReadonlyReplica 指标 | #57267 | src/Storages/StorageReplicatedMergeTree.cpp、src/Storages/MergeTree/ReplicatedMergeTreeRestartingThread.cpp |
| 后台 merge 临时存储缓存 | #57275 | src/Storages/MergeTree/、src/Disks/ |
| mutation 索引粒度复用 | #57352 | src/Storages/MergeTree/ |
| jsonMergePatch 常量列修复 | #57379 | src/Functions/jsonMergePatch.cpp |
| JSONCompactEachRow 并行解析 | #58181、#58250 | src/Formats/ |
| StreamingFormatExecutor 读缓冲区 | #57438 | src/Formats/、src/IO/ |
| SYSTEM STOP LISTEN TCP SECURE | #57483 | src/Interpreters/InterpreterSystemQuery.cpp |
| GRANT/REVOKE ON CLUSTER 忽略 | #57538 | src/Access/、src/Interpreters/ |
| system.kafka_consumers 默认关闭 | #57822 | src/Storages/System/ |
| BLAKE3(Rust)非法内存访问 | #57876 | rust/ 工作区 |
| Poco::UTF32Encoding 整型溢出 | #58073 | base/poco/ |
| Keeper 非法预处理 | #58069 | src/Coordination/ |
完整变更日志原文见 v23.10.6.60-stable.md,相邻版本的日志可在 docs/changelogs/ 与 docs/changelogs/archive/ 目录中按版本号查阅。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考