暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

PostgreSQL 15可靠性之本地化规则改进

原创 多米爸比 2022-11-03
1672

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乐知乐享交流群,欢迎关注我文章的小伙伴加我微信进群吹牛唠嗑,交流技术。

456.png

最后修改时间:2022-11-21 10:18:05
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论