ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

TiDB 中文拼音排序方案设计解读:utf8mb4_zh_pinyin_tidb_as_cs 校对规则的原理与落地

TiDB 中文拼音排序方案设计解读:utf8mb4_zh_pinyin_tidb_as_cs 校对规则的原理与落地 TiDB 中文拼音排序方案设计解读utf8mb4_zh_pinyin_tidb_as_cs 校对规则的原理与落地【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb本篇围绕 TiDB 仓库中的设计文档 2020-09-12-utf8mb4-pinyin-order.md 展开系统讲解 TiDB 为utf8mb4字符集引入中文拼音排序所设计的全新校对规则collationutf8mb4_zh_pinyin_tidb_as_cs。文章将带你理解该规则的命名语义、底层排序权重的编码规则、Collation ID 2048 的选取理由、与既有排序规则的兼容矩阵并对照当前仓库源码parser 注册表、collator 映射、测试用例梳理该特性从设计到代码的真实落地状态。读完你可以掌握中文按拼音 ORDER BY 的问题根源、TiDB 自定义排序规则的完整设计套路以及在当前版本中该 collation 已注册到哪一层、实现到什么程度。背景为什么 TiDB 需要中文拼音排序在关系型数据库中字符串ORDER BY的结果完全由列上声明的 collation 决定。对于中文场景用户常见的诉求之一是按拼音排序——例如姓名、城市名、商品名等希望以拼音字母a–z为序。设计文档指出彼时的 TiDB 无法基于拼音对一列汉字做排序。文档给出了一个具体示例create table t( a varchar(100) ) charset utf8mb4 collate utf8mb4_zh_0900_as_cs; # insert some data: insert into t values (中文), (啊中文); # a query requires to order by column a in its pinyin order: select * from t order by a; ----------- | a | ----------- | 啊中文 | | 中文 | ----------- 2 rows in set (0.00 sec)utf8mb4_zh_0900_as_cs是 MySQL 提供的 UCA 9.0.0 中文排序规则zh即 Chinese、as_cs即 accent-sensitive / case-sensitive。文档引用该示例的用意在于说明当中文排序的语义无法被正确、可预期地实现时仅靠直接ORDER BY得到的结果并不能稳定满足业务对拼音序的预期。要真正解决这类问题需要数据库内核提供语义正确且可复现的拼音排序能力。补充本提案讨论的背景演进可参见设计文档末尾列出的 issue #19747 与 #10192。方案总览utf8mb4_zh_pinyin_tidb_as_cs是什么本提案的核心产出是新增一个名为utf8mb4_zh_pinyin_tidb_as_cs的校对规则。命名本身就是一份完整的规格说明拆解如下命名片段含义utf8mb4适用的字符集为utf8mb4zh面向中文Chinese语言pinyin提供基于拼音pinyin的排序次序tidb表示这是 TiDB 的特殊custom版本as_csaccent-sensitive 且 case-sensitive区分重音与大小写能力边界该规则支持全部 Unicode 字符参与排序且能根据 CLDR24 中zh.xml文件定义的拼音 collation 次序对中文字符进行正确排序目前只支持zh.xml中拥有拼音条目的汉字对于字形与汉字相同、但 Unicode 归类为 Symbol符号的 CJK 字符以及拼音字符本身均不提供拼音排序支持。为什么不自研utf8mb4_zh_0900_as_csAdvantages文档明确给出了选择自研而非实现 MySQL 同款规则的理由实现utf8mb4_zh_0900_as_cs工作量大MySQL 的实现方式涉及权重重排weight reorders、魔法数字magic numbers与大量技巧复杂且难维护。相比之下utf8mb4_zh_pinyin_tidb_as_cs实现路径简单直接它覆盖全部汉字、按拼音次序排序对本提案的目标场景足够好。代价Disadvantages它不兼容 MySQL——MySQL 中并不存在名为utf8mb4_zh_pinyin_tidb_as_cs的校对规则。这一不兼容性是后续所有迁移与同步方案设计的出发点。核心设计排序权重Compare / Key如何编码排序的本质是比较排序键sort key / weight。设计文档给出了三条权值计算规则它们决定了每个字符在utf8mb4_zh_pinyin_tidb_as_cs下的相对次序中文字符凡在zh.xml中按 gb18030 编码查到非零seq No.的汉字其最终权重为0xFFA00000 seq No.。非中文的 gb18030 双字节字符 C最终权重取C本身。非中文的 gb18030 四字节字符 C最终权重为0xFF000000 diff(C)其中diff通过算法求得。从这套编码可以读出几个设计意图结合规则推演属合理推断而非文档明示以gb18030 编码作为汉字与zh.xml条目之间的桥梁是因为 gb18030 覆盖整个 Unicode 码域gb18030_chinese_ci.go 中即注释 Unicode code points up to U10FFFF can be encoded as GB18030任何 Unicode 字符都能先落到一个确定的 gb18030 字节序列再映射为拼音序号拼音序号被平移到0xFFA00000这个高基地址上与非中文双字节字符权重即其自身量级明显更小天然拉开区间从而任意中文字符的拼音权重落在同一高位段、且严格按 seq 递增四字节非中文字符落在0xFF000000基线之上需要额外保证其diff值不会与汉字拼音区间0xFFA00000起产生重叠。按文档表述这与双字节规则共同构成一个非中文在前、中文按拼音在后的整体次序模型。整体看这套方案的巧妙之处在于不需要复刻 MySQL 那套繁复的 UCA 中文权重表而是用gb18030 编码 zh.xml 拼音序号 区间化权值三要素直接生成可比较的排序键。Parser 侧落地为 collation 挑选 ID 2048一个可被 SQL 层识别的 collation首先要在 parser 的字符集/排序规则注册表中拥有唯一 ID。提案选择 ID2048并写入 parser。文档援引了 MySQL 官方的 ID 规划MySQL 支持双字节 collation ID其中1024–2047 区间预留给用户自定义排序规则user-defined collations。因此选择2048恰好落在该保留区间之外可避免与 MySQL 用户自定义规则的 ID 空间冲突。对照当前仓库源码这条注册记录确实已经落地pkg/parser/charset/charset.go 中存在{2048, utf8mb4, utf8mb4_zh_pinyin_tidb_as_cs, false, 1, PadNone}即字符集为utf8mb4、ID 为2048、padding 方式为PadNone。与现有 collation 的兼容性矩阵设计文档规定utf8mb4_zh_pinyin_tidb_as_cs与utf8mb4_unicode_ci、utf8mb4_general_ci拥有相同优先级三者彼此不兼容——即两个 collation 一旦混用例如 JOIN 两表、比较不同 collation 的列TiDB 不会自动将其视为可兼容并做隐式转换。这个兼容/不兼容的判定在引擎侧有专门实现可参考 collate.go 的CompatibleCollate其中对general_ci家族、bin家族、unicode_ci家族分别做了同族互认的处理其余情况严格按名字相等判定。中文拼音规则作为新成员不在任何既有家族内自然只能与自身相等与unicode_ci、general_ci均判定为不兼容与文档描述一致。与 MySQL 的兼容性及迁移建议由于 MySQL 没有utf8mb4_zh_pinyin_tidb_as_cs这一 collation文档给出的迁移指引很直接当用户需要把数据从 TiDB 复制replicate到 MySQL 时应当对使用该 collation 的列做处理如注释/改写 collation避免下游 MySQL 无法解析。换句话说该规则是TiDB 内可用、出 TiDB 需转换的方言特性适合在纯 TiDB 生态内部使用排序、索引、主从均为 TiDB 的场景一旦涉及 MySQL 下游同步就必须在 schema 层显式改写。从设计到代码该特性在当前仓库的落地现状设计文档是 2020 年提出的方案那么它在当前仓库中落地到哪一步了结合源码可以给出精确答案。1. 注册已就位名字与 ID 双双进入映射表除了 parser 侧的 ID 注册外运行期的 collator 映射表也已登记collate.go 同时将utf8mb4_zh_pinyin_tidb_as_cs写入newCollatorMap与newCollatorIDMap指向zhPinyinTiDBASCSCollator由于utf8mb4家族默认 collation 之外的名字统一经GetCollator/GetCollatorByID分发见 collate.go只要命中映射表即可取到对应 collator 实例。2. 运行时实现仍是占位桩stub打开 collator 本体文件 pinyin_tidb_as_cs.go会发现结构体zhPinyinTiDBASCSCollator虽然实现了Collator接口的全部方法Compare、Key、ImmutableKey、KeyWithoutTrimRightSpace、MaxKeyLen、Pattern、Clone但所有方法体目前都是panic(implement me)占位。这意味着从当前仓库快照看utf8mb4_zh_pinyin_tidb_as_cs的运行时排序逻辑尚未真正实现仍处于开发中的状态。这一点与 collate.go 的注释相互印证// utf8mb4_zh_pinyin_tidb_as_cs is under developing, should not be shown to user. if name utf8mb4_zh_pinyin_tidb_as_cs { continue }即GetSupportedCollations()对应SHOW COLLATION会显式过滤掉该 collation不向用户展示。3. 新排序规则开关与回退行为TiDB 的新排序规则new collations是否启用对应NewCollationEnabled()判定会显著影响该 collation 的表现new collations开启时GetCollator(utf8mb4_zh_pinyin_tidb_as_cs)与GetCollatorByID(2048)能命中上述 stub 实例new collations关闭时GetCollatorWithCollate 与 GetCollatorByID 会直接回退到二进制binarycollator另外new collations 开启时引擎还会把 collation ID 编码为负数下发 TiKVRewriteNewCollationIDIfNeeded让存储侧感知自定义排序语义而无需改动协议。上述两种开关下的行为都有测试覆盖collate_test.go 分别在新排序规则启用/关闭两组用例中用require.IsType断言GetCollator(utf8mb4_zh_pinyin_tidb_as_cs)与GetCollatorByID(2048)返回的分别是zhPinyinTiDBASCSCollator启用时与derivedBinCollator回退时。4. 可参照的同思路已完成范本gb18030 中文排序提案中汉字 → gb18030 编码 → 权值数据文件的技术路线在仓库中已有完成度很高的同族实现可供参照即gb18030字符集的中文排序规则gb18030_chinese_ci.go 通过//go:embed gb18030_weight.data内嵌权重数据文件运行期逐字符把 gb18030 序列换算为排序键后比较parser 侧对应注册了 ID 248/249/250 的gb18030_chinese_ci、gb18030_bin、gb18030_unicode_520_ci见 charset.go。可以推断未来若完成utf8mb4_zh_pinyin_tidb_as_cs的运行时实现最自然的路径就是参照gb18030_*系列预生成/内嵌一份基于 gb18030 码点与拼音 seq 的权值数据用数据驱动替代手写算法与设计文档中0xFFA00000 seq No.的公式完全吻合。延伸讨论替代路线与后续工作设计文档提到的替代路线是 MySQL 官方utf8mb4_zh_0900_as_cs——它是 MySQL 用于拼音序的语言专属 collation 之一。TiDB 之所以没有直接复刻核心障碍已在前文说明其实现依赖大量权重重排与魔法数值维护成本与出错风险高。而本提案的取舍是用一个命名上明确标注tidb方言、实现上依赖 CLDR zh.xml 拼音序号 gb18030 编码桥接的自研规则换取实现简单与语义正确代价则是与 MySQL 的不兼容并在跨库同步时需要显式改写。当前仓库的状态表明该 collation 的规格与注册层已经定型名字、ID 2048、collator 类型映射、兼容性定位、对外隐藏策略而运行时比较逻辑仍待实现。后续工作可沿着两个方向推进其一为zhPinyinTiDBASCSCollator填充真实实现并配套中文拼音排序的单元/集成测试其二在实现完成后放开 GetSupportedCollations 中的过滤逻辑使其对用户可见可用。设计文档末尾亦将 issue #19747、#10192 列为开放问题供持续跟踪。参考与延伸阅读设计文档原文docs/design/2020-09-12-utf8mb4-pinyin-order.mdParser 侧 collation 注册表含 ID 2048pkg/parser/charset/charset.goCollator 实例注册与展示过滤 pkg/util/collate/collate.go、collate.go运行时占位实现 pkg/util/collate/pinyin_tidb_as_cs.go排序规则兼容性判定与 collator 分发 pkg/util/collate/collate.go行为测试启用/关闭两种状态 pkg/util/collate/collate_test.go同思路的 gb18030 中文排序实现可作实现范本 pkg/util/collate/gb18030_chinese_ci.go、charset.go【免费下载链接】tidbTiDB is built for agentic workloads that grow unpredictably, with ACID guarantees and native support for transactions, analytics, and vector search. No data silos. No noisy neighbors. No infrastructure ceiling.项目地址: https://gitcode.com/GitHub_Trending/ti/tidb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表