PostgreSQL 15版本在可靠性方面有不少改进,本文首先介绍本地化规则的改进。
在PostgreSQL里,LOCALE默认使用C的本地化规则。操作系统和各种软件中也经常可以看到LOCALE相关配置。LOCALE是一种文化偏好的区域设置,包括字母表、排序、数字格式等。
一个LOCALE就是一组规则,包括:字符分类LC_CTYPE,消息语言LC_MESSAGES,货币格式LC_MONETARY,数字格式LC_NUMERIC,日期时间格式LC_TIME。LOCALE通常会用语言代码 + 国家代码的方式来命名,例如中国大陆使用的LOCALE为:zh_CN。它分为两个部分:zh是语言代码,CN是国家代码。
现实中,一种语言可能有多个国家在使用,一个国家内也可能存在多种语言。以中文和中国为例:中国(COUNTRY=CN)相关的语言LOCALE有:
- zh:汉语:zh_CN
- bo:藏语:bo_CN
- ug:维语:ug_CN
讲中文(LANG=zh)的国家或地区相关的LOCALE有:
- CN 中国:zh_CN
- HK 香港:zh_HK
- MO 澳门:zh_MO
- TW 台湾:zh_TW
LOCALE里有一个比较重要的规则LC_COLLATE,即排序方式(Collation),它会对数据库行为有显著影响。例如默认的libc库里zh_CN提供了iso14651_t1_pinyin排序规则,这是一个基于拼音的排序规则。
下面我们创建一张表包含7个汉字:
create table some_chinese(
name text primary key
);
insert into some_chinese values
('阿'),('波'),('磁'),('得'),('饿'),('佛'),('割');
当采用zh_CN所使用的拼音排序规则,按照拼音比大小而不是默认ASCII码排序对我们会更有意义。
postgres=# select * from some_chinese order by name collate "zh_CN";
name
------
阿
波
磁
得
饿
佛
割
(7 rows)
可以看到,按照zh_CN排序规则排序得到的结果,就是拼音顺序abcdefg。当然这个查询结果取决于zh_CN排序规则的具体定义,而不是数据库本身定义,数据库本身提供的排序规则就是C(或者其别名POSIX)。
PostgreSQL中使用非C LOCALE的负面影响是:特定排序规则对涉及字符串大小比较的操作有巨大的性能影响,同时它还会导致无法在LIKE查询子句中使用普通索引。
C LOCALE是由数据库本身确保在任何操作系统与平台上使用的,它对Collation字符序的支持依赖于操作系统。
实际环境中操作系统的Collation可能发生版本变化,PostgreSQL 15里数据库会记录Collation版本,使用pg_database_collation_actual_version函数进行查询。(下面的数字5是当前postgres数据库的oid)
postgres=# select pg_database_collation_actual_version(5);
pg_database_collation_actual_version
--------------------------------------
2.17
(1 row)
如果操作系统Collation在数据库运行过程中发生版本改变,PostgreSQL 15支持refresh操作刷新Collation版本,从而避免数据损坏。
postgres=# alter database postgres refresh collation version ;
NOTICE: version has not changed
ALTER DATABASE
PostgreSQL中除了使用默认的C LOCALE,依赖于操作系统,还可以使用第三方的本地化库,如ICU(International Components for Unicode)库来提供排序规则。在PostgreSQL 15之前ICU不支持单独的Collate和Ctype设置,只能先创建一个Collation对象,Collation里再指定icu provider。
create collation chinese (provider = icu, locale = 'zh');
还可以设置高级选项colCaseFirst:
create collation upperfirst (provider = icu, locale = 'en@colCaseFirst=upper');
然后对指定表的列上使用,但并不能对整个数据库使用。
PostgreSQL 15实现了这个突破,可以在初始化数据库实例时设置默认的全局ICU。
initdb -D pgdata --locale-provider=icu --icu-locale=en
同样可以设置高级选项colCaseFirst:
initdb -D pgdata --locale-provider=icu --icu-locale='en@colCaseFirst=upper'
如果初始化时没有设置,新建database时也可以进行设置:
create database db_icu
icu_locale ='en@colCaseFirst=upper'
locale_provider ='icu'
template=template0;
ICU特性需要数据库编译时打开–with-icu选项,默认编译时并没有打开这个选项。
参考文章一:PG中的本地化排序规则
https://mp.weixin.qq.com/s/SEXcyRFmdXNI7rpPUB3Zew
参考文章二:ICU features in PostgreSQL 15
http://peter.eisentraut.org/blog/2022/09/26/icu-features-in-postgresql-15
保持联系
从2019年12月开始写第一篇文章,分享的初心一直在坚持,本人现在组建了一个PG乐知乐享交流群,欢迎关注我文章的小伙伴加我微信进群吹牛唠嗑,交流技术。