查看原文
其他

每天5分钟PG聊通透第8期,为什么order by不按中文拼音排序?

digoal PostgreSQL码农集散地
2024-09-30

文中参考文档可点击阅读原文打开, 推荐《最好的PostgreSQL学习镜像》。


每天5分钟PG聊通透第8期,为什么order by不按中文拼音排序?

背景

  • 问题说明(现象、环境)
  • 分析原因
  • 结论和解决办法

链接、驱动、SQL

8、为什么order by并没有按中文拼音排序? (LC collate)

https://www.bilibili.com/video/BV1KR4y1W7BU/

字符串排序受什么影响?

  • 字符集
  • LC_COLLATE (string sort order)

几处可以指定collate:

  • 初始化PostgreSQL 实例时指定template的collate
  • 创建数据库时指定数据库的默认collate
  • 指定表字段的collate
  • 排序时指定collate
  • 创建索引时指定collate
    • 用到这样的索引必须在order by排序时使用与索引一样的collate, 否则索引不会被使用

中文拼音排序推荐用法:

  • order by convert_to(字符串字段,'EUC_CN'); 简体
  • order by convert_to(info,'GB18030'); 简体+繁体+少数民族字体+各种中国的符号
postgres=# select * from (values ('刘德华'),('刘少奇'),('张学友'),('郭富城'),('郭德纲'),('黎明'),('李刚'),('中山'),('重庆'),('冲哥')) as t(info)    
order by info collate "C";   
  info     
--------   
 中山   
 冲哥   
 刘少奇   
 刘德华   
 张学友   
 李刚   
 郭富城   
 郭德纲   
 重庆   
 黎明   
(10 rows)   
   
postgres=# select * from (values ('刘德华'),('刘少奇'),('张学友'),('郭富城'),('郭德纲'),('黎明'),('李刚'),('中山'),('重庆'),('冲哥')) as t(info)    
order by info collate "zh_CN";   
  info     
--------   
 中山   
 冲哥   
 李刚   
 重庆   
 黎明   
 刘少奇   
 刘德华   
 张学友   
 郭富城   
 郭德纲   
(10 rows)   
   
   
postgres=# select * from (values ('刘德华'),('刘少奇'),('张学友'),('郭富城'),('郭德纲'),('黎明'),('李刚'),('中山'),('重庆'),('冲哥')) as t(info)    
order by convert_to(info,'GB18030');   
  info     
--------   
 冲哥   
 郭德纲   
 郭富城   
 黎明   
 李刚   
 刘德华   
 刘少奇   
 张学友   
 中山   
 重庆   
(10 rows)   
   
postgres=# select * from (values ('刘德华'),('刘少奇'),('张学友'),('郭富城'),('郭德纲'),('黎明'),('李刚'),('中山'),('重庆'),('冲哥')) as t(info)    
order by convert_to(info,'EUC_CN');   
  info     
--------   
 冲哥   
 郭德纲   
 郭富城   
 黎明   
 李刚   
 刘德华   
 刘少奇   
 张学友   
 中山   
 重庆   
(10 rows)   
   
postgres=# \df convert_to   
                            List of functions   
   Schema   |    Name    | Result data type | Argument data types | Type    
------------+------------+------------------+---------------------+------   
 pg_catalog | convert_to | bytea            | text, name          | func   
(1 row)   
索引必须是immutable的.

postgres=# create index idx_d_1 on d (convert_to(c1,'GBK'));
ERROR:  functions in index expression must be marked IMMUTABLE
postgres=# create or replace function immut_convert_to(text,text) returns bytea as $$
postgres$#   select convert_to($1,$2);
postgres$# $$ language sql strict immutable;
CREATE FUNCTION
postgres=# create index idx_d_1 on d (immut_convert_to(c1,'GBK'));                                                                                                                                        CREATE INDEX

postgres=# set enable_sort=off;
SET
postgres=# explain select * from d order by immut_convert_to(c1, 'GBK'::text);
                            QUERY PLAN                            
------------------------------------------------------------------
 Index Scan using idx_d_1 on d  (cost=0.12..2.59 rows=1 width=64)
(1 row)

参考:

  • PostgreSQL 支持的服务端与客户端字符集:
    • https://www.postgresql.org/docs/current/multibyte.html
  • 《PostgreSQL MySQL 兼容性之 - order by 拼音 or binary or 指定 collate》
  • 《如何按拼音排序 - 数据库本土化特性(collate, ctype, ...)》
  • 《PostgreSQL 按拼音排序 - convert to GBK/EUC_CN coding》
  • 中文相关字符集,注意有的只能作为客户端编码, 有的既能作为客户端编码也能作为服务端编码.
    • GB2312(简体),
    • GBK(简体+繁体),
    • GB18030(简体+繁体+少数民族字体+各种中国的符号)
    • EUC_CN Extended UNIX Code-CN Simplified Chinese
    • BIG5 Big Five Traditional Chinese
    • EUC_TW Extended UNIX Code-TW Traditional Chinese, Taiwanese


本期彩蛋 - 开源Clup: PostgreSQL&PolarDB高可用与日常管理软件

clup由《PostgreSQL从小工到专家》作者唐成乘数科技出品, 包含开源版本和企业版本, 是非常成熟的PostgreSQL&PolarDB集群管理软件. 

官网: https://www.csudata.com/clup

开源项目地址: https://gitee.com/csudata

使用CLup可以轻松管理几十套至上百套PostgreSQL、PolarDB高可用的数据库集群,发生故障自动切换,不影响生产系统的运行。故障切换后有详细的故障日志,方便定位故障原因,还可以手工一键切换。CLup还提供了数据库的一些基本监控和TOP SQL的监控,CLup后续版本还会增加更多的功能。

  • 管理基于PostgreSQL流复制的集群

  • 管理基于共享存储的PolarDB集群

  • 产品优势

最后推荐2本大佬的新书

文章中的参考文档请点击阅读原文获得. 


欢迎关注我的github (https://github.com/digoal/blog) , 及视频号:


个人观点,仅供参考
继续滑动看下一个
PostgreSQL码农集散地
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存