区域设置数据更改

来自 PostgreSQL Wiki
跳转到导航跳转到搜索

以下信息重点关注使用 GNU C 库 (glibc) 的操作系统,其中包括大多数流行的 Linux 发行版。所有版本的 PostgreSQL 都受到影响。原则上其他操作系统可能存在相同的问题,但我们尚未收集到任何相关信息。

PostgreSQL 使用操作系统 C 库提供的区域设置数据来排序文本。排序发生在各种情况下,包括用户输出、合并连接、B 树索引和范围分区。在后两种情况下,排序后的数据会持久化到磁盘。如果 C 库中的区域设置数据在数据库生命周期内发生更改,持久化数据可能与预期排序顺序不一致,这会导致查询结果错误和其他错误行为。例如,如果索引未按索引扫描预期的方式排序,查询可能无法找到实际存在的数据,并且更新可能会插入应该禁止的重复数据。同样,在分区表中,查询可能会查看错误的分区,并且更新可能会写入错误的分区。因此,**数据库的正确操作至关重要,即区域设置定义在数据库生命周期内不会发生不兼容的更改**。

操作系统供应商,尤其是 GNU C 库的作者,会不时以细微的方式更改区域设置数据,以纠正错误或添加对更多语言的支持。虽然这在理论上违反了上述规则,但历史上影响的用户很少,而且没有引起广泛关注。但是,**在 2018 年 8 月 1 日发布的 glibc 版本 2.28 中,包含了对区域设置数据的重大更新,这可能会影响许多用户的数据**。需要注意的是,更新本身是合法的,因为它使区域设置数据符合当前的国际标准。但是,如果将这些更新应用于现有的 PostgreSQL 系统,则一定会出现问题。

将 glibc 更新集成到 Linux 发行版是操作系统供应商的领域。我们预计长期支持 Linux 发行版的供应商**不会**在给定发行版内将不兼容的区域设置更新应用于其发行版,但这只是一个预期,因为我们无法预测或影响未来的行动。此外,PostgreSQL 目前无法检测到不兼容的 glibc 更新。因此,在计划任何更新或升级时需要一些人工操作。

受影响的内容

潜在的受影响情况包括将更改的区域设置数据应用于现有实例或二进制等效实例,特别是

  • 更改运行实例上的区域设置数据(即使重新启动)。
    • 这尤其包括在保留 PostgreSQL 数据目录的情况下将 Linux 发行版升级到新的主要版本。
    • 使用 pg_upgrade(例如,在同时升级操作系统和 PostgreSQL 主版本时)无法避免此问题。
  • 使用流式复制到具有不同区域设置数据的备用实例。(备用实例可能会被损坏,但主实例没问题。)
  • 在具有不同区域设置数据的系统上还原二进制备份(例如,pg_basebackup)。

不受影响的情况是数据以逻辑(而不是二进制)方式传输的情况,包括

  • 使用 pg_dump 进行备份/升级
  • 逻辑复制

测试校对

使用 OS "sort" 实用程序是一种简单的方法,可以查看校对是否已更改

( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort

这两个字符串在不同的区域设置版本上排序不同。比较旧版和新版 OS 的输出。

**注意:**如果这两个排序结果相同,仍然可能存在其他差异。

受影响的数据类型

受影响

  • 对 text、varchar、char(包括其中一列为文本的多列索引)的 btree 索引

不受影响

  • bytea
  • tsvector gin 索引
  • pg_trgm 索引
  • 数值数据类型:int、bigint、numeric、float 等。
  • 自定义数据类型,如几何图形 (PostGIS)

该怎么办

当需要将实例升级到新的 glibc 版本时(例如,升级操作系统),则在升级后

  • 在将实例投入生产之前,应重新索引所有涉及类型为 text、varchar、char 和 citext 的列的索引。
  • 应检查使用这些类型作为分区键的范围分区表,以验证所有行是否仍在正确的分区中。(这极不可能成为问题,只有在特别模糊的分区边界情况下才会出现。)
  • 为了避免由于重新索引或重新分区造成的停机,请考虑使用逻辑复制进行升级。
  • 使用“C”或“POSIX”区域设置的数据库或表列不受影响。所有其他区域设置都可能受到影响。
  • 使用 ICU 提供程序的校对的表列不受影响。

受影响的索引

在每个数据库中使用此 SQL 查询来找出哪些索引受到影响

SELECT DISTINCT indrelid::regclass::text, indexrelid::regclass::text, collname, pg_get_indexdef(indexrelid) 
FROM (SELECT indexrelid, indrelid, indcollation[i] coll FROM pg_index, generate_subscripts(indcollation, 1) g(i)) s 
  JOIN pg_collation c ON coll=c.oid
WHERE collprovider IN ('d', 'c') AND collname NOT IN ('C', 'POSIX');

受影响的 Linux 发行版

为了帮助用户评估其当前操作系统的状况,我们收集了以下信息。再次注意,这只是当前状况的报告,我们无法影响这些供应商将来会做什么或可能做什么。

Debian

版本 8 (jessie) 和 9 (stretch) 使用旧的区域设置数据。我们预计这些版本内部不会有任何不兼容的更改。从版本 8 升级到 9 是安全的。

**版本 10 (buster) 使用新的区域设置数据**。因此,在升级时需要谨慎。

另请参阅

Ubuntu

Ubuntu 最高版本 18.04 (bionic) 使用旧的区域设置数据。

新的**glibc 2.28 区域设置数据在版本 18.10 (cosmic) 中引入**(非 LTS)。从 bionic 或更低版本升级到 cosmic 或更高版本需要上面概述的缓解措施。

RHEL/CentOS

版本 6 和 7 使用旧的区域设置数据。从版本 6 升级到 7 是安全的,**除非使用 de_DE.UTF-8 区域设置**,因为这些版本之间发生了类似的更改。(所有其他区域设置,包括其他 de_*.UTF-8 区域设置(如 de_AT),都是安全的。)

**版本 8 使用新的区域设置数据**。因此,在升级时需要谨慎。

SuSE Linux Enterprise

SLE12 使用旧的区域设置数据。

SLE15 直到 Service Pack 2 (SLESP2) 附带 glibc-2.26 并使用旧的区域设置数据。**SLE15 Service Pack 3 更新了 glibc 版本到 2.31,因此使用新的区域设置数据**。因此,在升级时需要谨慎。

macOS

虽然 macOS 没有使用 glibc,但它显示了一个类似的问题,因为 macOS 10.15 Catalina 和 macOS 11 Big Sur 之间许多校对都发生了重大更改。旧版本将其所有 UTF8 LC_COLLATE 文件的符号链接指向一个本质上具有字节顺序校对的虚拟文件,如 'C'。从 macOS 11 开始,Apple 将大约一半的符号链接指向其 ISO8859-1 (Latin 1) 对应文件。

ls -l /usr/share/locale/*.UTF-8/LC_COLLATE
( echo "5£"; echo "£5" ) | LC_COLLATE=en_US.UTF-8 sort

在此处添加您的内容

参考资料