
ClickHouse v21.4.4.30-stable 版本解析层次字典新函数、simpleJSON 别名与复制 ATTACH 行为变更【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse本篇技术指南围绕 ClickHouse 官方 changelogdocs/changelogs/archive/v21.4.4.30-stable.md展开逐条解读 v21.4.4.30-stable 相对 v21.4.3.21-stable 的变更包括新增的层次字典函数dictGetChildren/dictGetDescendants、容错查询函数dictGetOrNull、simpleJSON*系列别名、background_fetches_pool_size默认值调整以及ATTACH PART[ITION]查找顺序的向后不兼容变更。读者阅读后可掌握这些新函数的语义、用法与源码级实现原理并了解升级该补丁版本时需要留意的行为差异。版本概览与定位v21.4.4.30-stable 是 ClickHouse 21.4 系列的一个补丁patch版本属于stable分支其变更全部为backport从主分支回移植到稳定分支而来。本版不含重大架构改动聚焦三类内容新功能New Feature围绕外部字典External Dictionary扩展了三个函数改进ImprovementJSON 解析函数别名、复制 fetch 线程池默认值、正则匹配阈值Bug FixAWS 请求超时、formatDateTime/toDateTime64、untuple子查询、Materialized View、Markdown 输出格式等修复。该文件位于仓库 docs/changelogs/archive/ 目录属于 2022 年归档的 2021 年发布记录标题归档为 2022 Changelog。以下按 changelog 原始分类逐节解读并给出对应源码位置佐证。向后不兼容变更ATTACH PART 优先在本地 detached/ 目录查找原文要点现在处理ALTER TABLE ATTACH PART[ITION]命令的副本会先在自身的detached/目录中查找然后再从其他副本拉取数据。作为实现细节复制日志replicated log中引入了一条新命令ATTACH_PART。数据 part 通过其**校验和checksums**进行搜索与比对PR #18978。行为变化旧行为下执行ALTER TABLE ATTACH PART时副本会直接向其他副本发起 fetch新行为下每个副本优先检查本地detached/目录中是否存在与目标 part 匹配分区 ID 相同、名称合法的候选 part若存在且校验和一致则直接本地挂载避免跨网络拷贝显著降低网络开销与 ZooKeeper 往返。源码佐证复制日志条目类型在 src/Storages/MergeTree/ReplicatedMergeTreeLogEntry.cpp 中定义ATTACH_PART被映射为字符串ATTACH_PART并在解析日志条目时赋给type见该文件 L44、L97、L265。本地查找逻辑位于 src/Storages/StorageReplicatedMergeTree.cpp 的attachPartHelperFoundValidPart方法L2467 起它会列出detached/目录下的所有 partgetDetachedParts()过滤掉名称非法、带前缀或带_tryN后缀的残留文件以及不属于目标分区的 part再按目标 part 名构建数据 part 并比对校验和只有匹配才返回。⚠️ 升级注意这是本版本唯一标记为Backward Incompatible的变更。从源码可推断若本地detached/中存在校验和不一致的残留 part新逻辑不会误用它校验和不一致会被拒绝因此主要影响是执行顺序而非数据安全性但运维脚本若依赖ATTACH 总是从其他副本拉取需要感知这一顺序变化。新功能一层次字典查询函数 dictGetChildren 与 dictGetDescendants原文要点改进了dictGetHierarchy、dictIsIn的性能新增函数dictGetChildren(dictionary, key)、dictGetDescendants(dictionary, key, level)。dictGetChildren返回所有子节点组成的索引数组是dictGetHierarchy的逆变换dictGetDescendants返回所有后代相当于对dictGetChildren递归应用level次level为 0 时等价于无穷大PR #22096。函数语义在层次字典hierarchical dictionary中dictGetHierarchy(dict, key)返回从 key 自身到根节点的祖先链含 key 自身dictIsIn(dict, child, parent)判断 child 是否为 parent 的后代。v21.4.4.30 补齐了下行方向的能力dictGetChildren(dictionary, key)返回指定 key 的直接子节点ID 数组Array即dictGetHierarchy的反向映射dictGetDescendants(dictionary, key, level)返回 key 的全部后代ID 数组level表示递归层数level 0表示不限深度无穷level 1等价于直接子节点。三者配合可实现完整的树形结构双向遍历向上查祖先用dictGetHierarchy向下查子孙用dictGetDescendants。源码实现实现位于 src/Functions/FunctionsExternalDictionaries.h核心是两个策略类L1444-L1458FunctionDictGetChildrenStrategyname dictGetChildrendefault_level 1固定 2 个参数非可变参数——因为子节点就是一层无需 level 参数FunctionDictGetDescendantsStrategyname dictGetDescendantsdefault_level 0即默认无限深度可变参数2 或 3 个。两者共用FunctionDictGetDescendantsOverloadResolverImplL1461这一重载解析器其buildImpl中若用户显式传入第三个参数则校验其为常量无符号整数负值会抛ILLEGAL_TYPE_OF_ARGUMENT并将其解析为level随后通过dictionary-getHierarchicalIndex()获取父→子索引DictionaryHierarchicalParentToChildIndexPtr最终在FunctionDictGetDescendantsExecutable::executeImplL1385中调用dictionary-getDescendants(...)完成递归查询。返回类型固定为Array(层次属性类型)会移除 Nullable 包装见getReturnTypeImplL1520。值得注意的前提约束FunctionDictHelper::checkDictionaryHierarchySupportL119要求字典必须声明了层次属性hierarchical_attribute_index且支持层次结构否则会抛UNSUPPORTED_METHOD异常。使用示例-- 假设字典 region 的层次属性指向父区域 ID -- 返回 key1 的所有直接子区域 SELECT dictGetChildren(region, 1); -- 返回 key1 的三层以内的所有后代 SELECT dictGetDescendants(region, 1, 3); -- 返回 key1 的所有后代不限制深度 SELECT dictGetDescendants(region, 1, 0);新功能二容错查询函数 dictGetOrNull原文要点新增dictGetOrNull用法与dictGet相同但在字典中找不到 key 时返回NullPR #22413。与 dictGet / dictGetOrDefault 的差异函数key 未命中时的行为dictGet返回字典属性声明的默认值或字典配置中指定的默认值dictGetOrDefault(dict, attr, key, default)返回用户显式指定的默认表达式dictGetOrNull(dict, attr, key)返回NULLNullable类型dictGetOrNull的价值在于无需预先知道默认值也无需在 SQL 中拼接if(dictHas(...), ...)三元判断直接利用 SQL 的NULL语义与isNull/ifNull/ 聚合函数组合简化查不到就跳过/标记缺失的查询逻辑。源码实现FunctionDictGetOrNull定义于 src/Functions/FunctionsExternalDictionaries.hL987其实现非常巧妙注释L1050-L1061阐明了三步法先调用dictHas内部复用FunctionDictHas判断每个 key 是否存在于字典得到 0/1 掩码并取反作为 null map 的候选再调用dictGet内部复用FunctionDictGetNoTypeget取值——按契约未命中的 key 返回默认值将取反后的掩码包装为ColumnNullable的 null map未命中的行显示为NULL。实现细节上还处理了两种特例当查询多个属性结果类型为Tuple时对每个元组元素分别包一层 NullableL1089-L1115当属性本身已是 Nullable 时通过addNullMap合并两张 null mapL1118-L1128。返回类型由getReturnTypeImplL1025决定单属性返回Nullable(属性类型)多属性返回元素均为 Nullable 的Tuple。使用示例-- 未命中的 key 返回 NULL 而非默认值 SELECT dictGetOrNull(region, region_name, toUInt64(id)) AS name FROM user_ids; -- 与 ifNull 组合自定义缺失回退 SELECT ifNull(dictGetOrNull(region, region_name, id), 未知区域) FROM user_ids;改进一simpleJSON* 函数别名统一 JSON 解析命名原文要点为visitParam / visitParamExtract{UInt, Int, Bool, Float, Raw, String}添加别名simpleJSONExtract / simpleJSONHasPR #21519。别名映射visitParam*系列是 ClickHouse 传统的简单 JSON解析函数基于字符串搜索而非完整 JSON 解析器要求 JSON 中字段以field:形式出现且每行一个 JSON。本版本为其注册了更贴近语义的新名字旧名保留为别名新名主函数名语义visitParamHassimpleJSONHas判断 JSON 中是否存在指定字段返回UInt81/0visitParamExtractUIntsimpleJSONExtractUInt从字段值解析UInt64失败返回 0visitParamExtractIntsimpleJSONExtractInt解析Int64visitParamExtractFloatsimpleJSONExtractFloat解析Float64visitParamExtractBoolsimpleJSONExtractBool解析布尔true/false返回UInt8visitParamExtractRawsimpleJSONExtractRaw返回字段值的原始子串visitParamExtractStringsimpleJSONExtractString返回字段值的字符串含反转义源码佐证注册逻辑分散在src/Functions/下的visitParam*.cpp文件中模式统一先registerFunctionFunctionSimpleJSONXxx(documentation)注册主函数名再registerAlias(visitParamXxx, simpleJSONXxx)注册旧名。例如src/Functions/visitParamExtractUInt.cppL58-L59factory.registerFunctionFunctionSimpleJSONExtractUInt(documentation); factory.registerAlias(visitParamExtractUInt, simpleJSONExtractUInt);src/Functions/visitParamHas.cppL59-L60factory.registerFunctionFunctionSimpleJSONHas(documentation); factory.registerAlias(visitParamHas, simpleJSONHas);两份文件的文档元数据均标注IntroducedIn {21, 4}21.4 引入与本 changelog 吻合函数分类为Category::JSON。函数本体为FunctionsStringSearchExtractParamImpl...模板见 src/Functions/visitParamExtractUInt.cpp 的FunctionSimpleJSONExtractUInt定义底层复用了字符串搜索与提取的通用实现。使用示例CREATE TABLE jsons (json String) ENGINE MergeTree ORDER BY tuple(); INSERT INTO jsons VALUES ({foo:4e3}), ({foo:3.4}), ({foo:5}), ({baz:2}); -- 解析 UInt字符串 4e3 从开头解析出 43.4 截断为 3not1number 解析失败返回 0 SELECT simpleJSONExtractUInt(json, foo) FROM jsons ORDER BY json; -- 0 / 3 / 4 / 5 -- 判断字段是否存在 SELECT simpleJSONHas(json, foo) FROM jsons; -- 存在返回 1 SELECT simpleJSONHas(json, bar) FROM jsons; -- 不存在返回 0说明simpleJSONExtractUInt(json, foo)从4e3这类字符串字段的开头尝试解析数字得到 4而3.4会按无符号整数截断为 3not1number与缺失字段均返回 0——此行为与官方文档示例src/Functions/visitParamExtractUInt.cpp 中REGISTER_FUNCTION内的示例一致。改进二background_fetches_pool_size 默认值调整为 8原文要点将background_fetches_pool_size设置为 8更适合生产环境中频繁小批量插入或ZooKeeper 集群较慢的场景PR #22945。背景与影响复制表ReplicatedMergeTree在副本间同步数据 part 时使用独立的后台拉取线程池。在 21.4 之前该池默认较小若副本需要大量并发 fetch例如频繁小批量插入导致产生大量小 part或 ZooKeeper 响应慢导致拉取任务积压容易出现 fetch 饥饿pool starving。调大到 8 后单副本可并行拉取的 part 数更多吞吐与恢复速度更优。在 src/Storages/MergeTree/registerStorageMergeTree.cppL4508 附近的引擎文档中明确说明ReplicatedMergeTree引擎为复制 fetch 使用独立线程池池大小由background_fetches_pool_size服务端设置限制可通过重启服务器调整。源码佐证在 src/Core/Settings.cppL9427中该设置被标记为MAKE_DEPRECATED_BY_SERVER_CONFIG(M, UInt64, background_fetches_pool_size, 8)即默认值为8且已迁移为服务端配置config.xml中background_fetches_pool_size在SETTINGS层面废弃DEPRECATED_BY_SERVER_CONFIG同类还包括background_pool_size、background_schedule_pool_size等见 src/Core/Settings.cpp。该设置的位置与命名还被复制相关任务的报错信息引用——当 fetch 池饥饿时会提示用户检查该参数例如 src/Storages/MergeTree/MergeFromLogEntryTask.cppL157。配置方式在服务器config.xml的merge_tree或顶层中显式覆盖background_fetches_pool_size8/background_fetches_pool_size修改后需要重启clickhouse-server生效。对慢 ZooKeeper 或高 part 数环境可进一步调大但需权衡内存与 ZooKeeper 会话负担。改进三extractAllGroupsHorizontal 匹配数量阈值提高原文要点提高了函数extractAllGroupsHorizontal结果中最大匹配数量的阈值PR #23036。extractAllGroupsHorizontal(s, regexp)使用正则表达式的捕获组将一行输入按组组织成二维字符串数组横向布局外层数组按组 id内层数组为该组的所有匹配其纵向版本extractAllGroupsVertical则按匹配出现顺序组织。实现见 src/Functions/extractAllGroups.h其中对每行匹配数有保护性上限由设置regexp_max_matches_per_rowsrc/Functions/extractAllGroups.h控制超限会抛TOO_LARGE_ARRAY_SIZE异常L198-L201。本版本提高的即此默认阈值降低了大文本多匹配场景下误报Too many matches per row的概率。-- 示例源码注释中原样给出 SELECT extractAllGroupsHorizontal(abc111, def222, ghi333, ([^]|\w)([^]|\w)); -- 返回 [[abc, def, ghi], [111, 222, 333]]Bug Fix 修复清单本版本包含 6 项 bug 修复均为 backport修复内容说明AWS 辅助请求无限等待修复 S3/对象存储相关辅助请求可能无限阻塞的问题PR #22594formatDateTime与toDateTime64修复formatDateTime()处理DateTime64、%C世纪格式符的问题修复toDateTime64()处理大数值与非零 scale 的问题PR #22937untuple子查询报错修复子查询使用untuple时可能出现Cannot find column in ActionsDAG result错误PR #22991clickhouse-client 建议信息移除客户端交互模式建议suggestions中非必要细节PR #23040Materialized View 报错修复物化视图从 Atomic 数据库 detach 后再 attach 时出现Table .inner_id... doesnt exist错误PR #23047Markdown 格式对齐修复Markdown输出格式中表格单元格值被居中对齐的问题现改为默认对齐PR #23096其中untuple相关修复对应 src/Functions 目录下的untuple函数族Markdown 格式修复对应 src/Formats 目录下的Markdown输出格式实现涉及 src/Formats/OutputFormats 中的格式写入逻辑。两类修复对依赖FORMAT Markdown导出表格的报表场景有实际影响。Build / Testing / Packaging 改进ppc64le 平台 openldap在 ppc64lePowerPC 64-bit Little Endian架构上启用捆绑bundled的 openldapPR #22487。这属于构建/打包层面的可移植性改进仅影响在 ppc64le 平台自行编译的用户LDAP 认证功能src/Access中基于 openldap 的 LDAP 身份认证此前在该架构上默认不可用本版本起随源码构建可用。升级建议与总结综合本 changelog升级到 v21.4.4.30-stable 时建议关注三点ATTACH 顺序变更执行ALTER TABLE ATTACH PART[ITION]前确认副本本地detached/目录中的残留 part 不会与预期冲突——新逻辑会优先基于校验和匹配本地 part相关实现见 src/Storages/StorageReplicatedMergeTree.cpp新函数可用性dictGetChildren、dictGetDescendants、dictGetOrNull仅对声明了层次属性hierarchy的字典有效使用前请确认字典配置simpleJSON*是visitParam*的新主名两者可互换使用服务端配置迁移background_fetches_pool_size等一批后台线程池设置已标记为DEPRECATED_BY_SERVER_CONFIG建议统一迁移到服务器配置文件中配置默认值已上调为 8。该版本整体属于低风险补丁升级仅一处向后不兼容ATTACH 查找顺序其余为新函数与默认参数优化适合在生产环境按正常发布节奏滚动升级。【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考