内容提要
PostgreSQL 默认使用外部库的语言环境排序规则,操作系统升级可能改变排序规则,导致字符串索引损坏,必须重建。建议用 C 排序规则建库:它按字节比较,只依赖字符编码,永不改变,且比较更快。若需自然语言排序,可仅在个别列或 ORDER BY 中指定其他排序规则,以减少可能损坏的索引。v17 起可用内置 C 排序规则,降低外部依赖。
延伸解读
C 排序规则的核心优势:稳定与高效
C 排序规则按字节比较字符串,仅依赖字符编码,因此排序顺序永不改变。这避免了操作系统升级导致排序规则变化,从而防止字符串索引损坏。同时,字节比较比自然语言排序更高效,能提升查询性能。对于不需要自然语言排序的场景,使用 C 排序规则可以显著降低维护成本。
自然语言排序的复杂性与风险
自然语言排序规则涉及特殊字符处理、大小写顺序等复杂逻辑,不同语言规则各异。实现中的错误修复可能导致排序规则变化,进而使索引损坏。操作系统升级可能更新外部库,改变排序行为,因此必须重建受影响索引。若必须使用自然语言排序,应尽量缩小其应用范围。
灵活使用排序规则:列级与查询级指定
即使数据库使用 C 排序规则,仍可在列定义或 ORDER BY 子句中指定自然语言排序规则。例如,为 name 列指定奥地利 ICU 排序规则,则按该列排序时自动使用,相关索引也按此排序。这样,只有少数索引可能受升级影响,减少重建需求。
PostgreSQL v17+ 的内置排序规则提供者
从 v17 开始,PostgreSQL 提供内置排序规则提供者,减少对外部库的依赖。初始版本支持 C 和 C.UTF-8,v18 增加 PG_UNICODE_FAST。这些排序规则简单且不支持自然语言,其中 C.UTF-8 和 PG_UNICODE_FAST 依赖 Unicode 版本,可能随更新变化。为完全稳定,建议使用 C 排序规则。
Q&A
为什么 PostgreSQL 默认排序规则会导致索引损坏?
PostgreSQL 默认使用外部库(C 库或 ICU 库)提供的语言环境排序规则。操作系统升级会升级这些库,有时会改变排序规则,导致字符串索引排序错误,即索引损坏。
C 排序规则有什么优点和缺点?
优点:按字节比较,只依赖字符编码,排序顺序永不改变,且比较速度更快。缺点:排序顺序不符合自然语言习惯,例如大写字母排在小写字母之前,非 ASCII 字符排在 ASCII 字符之后。
如何在使用 C 排序规则的同时实现自然语言排序?
可以在列定义时指定其他排序规则,或在 ORDER BY 子句中显式指定排序规则。这样只有这些列上的索引可能受操作系统升级影响,减少了需要重建的索引数量。
PostgreSQL v17 及以上版本提供了哪些内置排序规则?
v17 引入了内置排序规则提供者,初始提供 C 和 C.UTF-8;v18 增加了 PG_UNICODE_FAST。这些排序规则简单且不支持自然语言,其中 C.UTF-8 和 PG_UNICODE_FAST 依赖 Unicode 版本,可能随 PostgreSQL 更新而变化,因此推荐使用 C。
如何使用内置 C 排序规则创建数据库集群?
使用 initdb 并指定选项,例如:initdb --locale-provider=builtin --locale=C -D /path/to/data。也可以创建数据库时指定内置 C 排序规则,但若集群默认语言环境不同,需使用 template0 作为模板。
使用 C 排序规则能带来哪些性能优势?
C 排序规则的字符串比较比自然语言排序规则更廉价,因为只需简单的 memcmp() 调用,从而提升查询性能。