排序规则

本节介绍排序规则的概念和配置方式。

基本概念

通常,每一种可排序的数据类型都拥有一个排序规则。本节介绍的排序规则(Collation)特指字符的排序规则。排序规则会影响:

  • ORDER BY 子句的排序。
  • 比较操作符(如 >、<、= 等)。

排序规则依赖于字符集,不同的字符集支持的排序规则不同。可以通过系统表 PG_COLLATION 查询 VexDB 支持的排序规则。

在初始化数据库时,LC_COLLATE 默认会根据操作系统的 locale 设置进行选择,也可以通过 --LC-COLLATE 参数指定。指定 LC_COLLATE 时,需要确保该设置与字符集能够匹配。

使用方式

VexDB 数据库允许在查询中通过 COLLATE 子句指定查询使用的排序规则。

SELECT expr COLLATE collation;
  • 不指定 COLLATE 时,使用对象的排序规则。
    SELECT col < 'expr' FROM tbl;
    
  • 在括号中指定 COLLATE 时,使用显式指定的排序规则。
    SELECT col < ('expr' COLLATE 'zh_CN.utf8') FROM tbl;
    
    说明

    通过 COLLATE 指定的排序规则必须为当前 server_encoding 字符集支持的排序规则。如上述语句在 server_encoding 为 zh_CN.gbk 时,则会报错:ERROR: collation "zh_CN.utf8" for encoding "GBK" does not exist

  • 若解析器无法确定使用哪种排序规则,则会报错。
    CREATE TABLE tbl(col1 text COLLATE 'zh_CN',col2 text COLLATE 'en_US');
    INSERT INTO tbl VALUES ('vexdb','vexdb');
    SELECT col1 < col2 from tbl;
    

    报错为:
    ERROR:  could not determine which collation to use for string comparison
    

    对于上述情况,可以通过显式指定 COLLATE 关键字规避。
    SELECT col1 < col2 COLLATE 'zh_CN' from tbl;
    
  • 对于不涉及排序的函数或操作符,即使表达式前后的排序规则不同,也不会产生影响。
    CREATE TABLE tbl(col1 text COLLATE 'zh_CN',col2 text COLLATE 'en_US');
    INSERT INTO tbl VALUES ('vexdb','vexdb');
    SELECT col1 || col2 from tbl;
    

配置方式

允许配置排序规则的对象

  • VexDB 允许为数据库、列级别设置排序规则。其中优先级为:
显式指定 > 列 > 数据库

初始化排序规则

在初始化数据库时,LC_COLLATE 默认会使用操作系统 locale.conf 中的 LC_COLLATE 配置,用户可以在初始化数据库时通过 --lc-collate 参数指定。指定 --lc-collate 时,需要确保该设置与字符集能够匹配。

方式一:

  1. 修改 locale.conf,将 LANG 设置为需要使用的语言设置。例如 "zh_CN.gbk"。
    LANG = zh_CN.GBK
    
  2. 重启操作系统,使配置生效。
    locale | grep 'LANG\|LC_COLLATE\|LC_CTYPE'
    

    上述命令返回结果如下,表示操作系统支持 zh_CN.gbk 排序规则:
    LANG=zh_CN.gbk
    LC_CTYPE="zh_CN.gbk"
    LC_COLLATE="zh_CN.gbk"
    
  3. 使用 vb_initdb 命令行工具初始化数据库。
    vb_initdb -D $GAUSSHOME --nodename=vb 
    

方式二:

使用 vb_initdb 命令行工具显式指定排序规则。

vb_initdb -D $GAUSSHOME \
         --nodename=vb \
         --encoding=GBK \
         --lc-collate=C \
         --lc-ctype=C

数据库级排序规则

VexDB 数据库支持 CREATE DATABASE 语句在创建数据库时使用 LC_COLLATE 指定排序规则。LC_COLLATE 在数据库创建后不允许修改。

CREATE DATABASE database_name
             ENCODING [=] encoding
             LC_COLLATE [=] lc_collate
             LC_CTYPE [=] lc_ctype;

当新建数据库 Encoding、LC_Collate 或 LC_Ctype 与模板数据库(SQL_ASCII)不匹配(为 GBK、UTF8 或 LATIN1 等)时,必须指定 template = template0。

参数说明

  • database_name
    要创建的数据库名称。
  • encoding
    指定数据库使用的字符编码,可以是字符串(如'SQL_ASCII')、整数编号。
    不指定时,默认使用模版数据库的编码。模板数据库 template0 和 template1 的编码默认与操作系统环境相关。template1 不允许修改字符编码,因此若要变更编码,请使用 template0 创建数据库。
    指定新的数据库字符集编码必须与所选择的本地环境中(LC_COLLATE 和 LC_CTYPE)的设置兼容。
  • lc_collate
    指定新数据库使用的字符集。例如,通过lc_collate = 'zh_CN.gbk'设定该参数。
    该参数的使用会影响到对字符串的排序顺序(如使用 ORDER BY 执行,以及在文本列上使用索引的顺序)。默认是使用模板数据库的排序顺序。
    取值范围:操作系统支持的字符集。
  • lc_ctype
    指定新数据库使用的字符分类。例如,通过 lc_ctype = 'zh_CN.gbk' 设定该参数。该参数的使用会影响到字符的分类,如大写、小写和数字。默认是使用模板数据库的字符分类。
    取值范围:操作系统支持的字符分类。
    说明

    对于 lc_collate 和 lc_ctype 参数的取值范围,取决于本地环境支持的字符集。 例如:在 Linux 操作系统上,可通过 locale -a 命令获取操作系统支持的字符集列表,在应用 lc_collate 和 lc_ctype 参数时可从中选择用户需要的字符集和字符分类。

数据库的排序规则存储在 PG_DATABASE 系统表中。 可以使用 vsql 的 -l 选项或 \l  命令列出这些排序规则。

vsql -l

列级排序规则

VexDB 数据库支持在 CREATE TABLE 语句为列指定排序规则。支持通过 ALTER TABLE 修改列的排序规则。

CREATE TABLE table_name ( column_name data_type COLLATE collation 
                         [, ...] );

参数说明

  • table_name
    要创建的表名。
  • column_name
    要创建的表名。
  • data_type
    字段的数据类型。
  • collation
    指定列的排序规则。指定排序规则的列必须是可排序的数据类型。
    如果没有指定,则使用默认的排序规则。排序规则可以使用 select * from pg_collation; 命令从 pg_collation 系统表中查询,默认的排序规则为查询结果中以 default 开始的行。
    说明

    列的排序规则存储在PG_ATTRIBUTE系统表中。可以通过以下 SQL 查询 tbl 表上各列的排序规则。

    WITH foo AS (SELECT co.oid,co.collname FROM pg_collation co
               JOIN pg_namespace nco ON co.collnamespace = nco.oid  
               WHERE nco.nspname <> 'pg_catalog'::name 
                   OR co.collname <> 'default'::name) 
       SELECT tbl.relname AS table_name,
           col.attname AS column_name,
           foo.collname::varchar(100) AS "collation"
       FROM pg_attribute col 
       JOIN pg_class tbl ON col.attrelid = tbl.oid
       LEFT JOIN foo ON col.attcollation = foo.oid
       WHERE col.attnum > 0 
       AND col.attisdropped = false 
      AND relname = 'tbl';
    

示例

示例1:为索引指定排序规则

  1. 创建测试表,其中 c2 列排序规则指定为 C。
    CREATE TABLE coll_ind(c1 int,c2 text COLLATE 'C');
    
  2. 在测试表上创建索引,指定排序规则为 zh_CN。
    CREATE INDEX coll_idx ON coll_ind(c2 COLLATE 'zh_CN');
    
  3. 不显示指定排序规则,查看执行计划。
    EXPLAIN (costs off,verbose) SELECT * FROM coll_ind WHERE c2 = 'a';
    

    返回结果如下:
                QUERY PLAN
    -------------------------------------
    Seq Scan on public.coll_ind
    Output: c1, c2
    Filter: (coll_ind.c2 = 'a'::text)
    (3 rows)
    
  4. 显式指定排序规则,查看执行计划。
    EXPLAIN (costs off,verbose) SELECT * FROM coll_ind WHERE c2 = 'a' COLLATE 'zh_CN';
    

    返回结果如下,表示执行计划使用了索引:
                            QUERY PLAN
    ---------------------------------------------------------------
    Bitmap Heap Scan on public.coll_ind
    Output: c1, c2
    Recheck Cond: (coll_ind.c2 = 'a'::text COLLATE "zh_CN")
    ->  Bitmap Index Scan on coll_idx
            Index Cond: (coll_ind.c2 = 'a'::text COLLATE "zh_CN")
    (5 rows)
    
  5. 清理测试环境。
    DROP TABLE coll_ind;
    

示例2:指定数据库的排序规则

  1. 在默认字符集为 utf8 的数据库实例中,创建排序规则为 zh_CN.gbk 的数据库。
    CREATE DATABASE gbk LC_COLLATE 'zh_CN.gbk';
    

    返回结果如下,报错 utf8 字符集与 zh_CN.gbk 排序规则不匹配:
    ERROR:  encoding "UTF8" does not match locale "zh_CN.gbk"
    
  2. 在创建数据库命令中增加 ENCODING 选项。
    CREATE DATABASE gbk LC_COLLATE 'zh_CN.gbk' ENCODING 'gbk';
    

    返回结果如下,报错 GBK 字符集与区域 en_US.UTF8 不匹配:
    ERROR:  encoding "GBK" does not match locale "en_US.UTF-8"
    
  3. 在创建数据库命令中增加 LC_CTYPE 选项。
    CREATE DATABASE gbk LC_COLLATE 'zh_CN.gbk' ENCODING 'gbk' LC_CTYPE 'zh_CN.gbk'; 
    

    返回结果如下,创建数据库成功。
    CREATE DATABASE
    
  4. 清理测试环境。
    DROP DATABASE gbk;
    

示例3:指定列的排序规则

  1. 创建测试表,并插入数据。
    CREATE TABLE coll_tbl(c1 text COLLATE 'en_US',c2 text COLLATE 'C');
    INSERT INTO coll_tbl VALUES ('vexdb','vexdb');
    
  2. 查询 c1 < c2。
    SELECT c1 < c2 FROM coll_tbl;
    

    返回结果如下,由于执行器无法选择使用哪一种排序规则,返回报错。
    ERROR:  could not determine which collation to use for string comparison
    
  3. 在查询中显式指定排序规则。
    SELECT c1 < c2 collate 'en_US' from coll_tbl;
    

    返回结果如下:
    ?column?
    ----------
    f
    (1 row)
    
  4. 清理测试环境。
    DROP TABLE coll_tbl;
    

需要帮助?

扫码添加企业微信
获得专业技术支持

企业微信二维码
🎯 快速响应💡 专业解答