📣

TiDB Cloud Serverless 现已更名为
Starter
!此页面由 AI 自动翻译,英文原文请见
此处。

字符集与排序规则

本文介绍了 TiDB 支持的字符集和排序规则。

概念

字符集是符号和编码的集合。TiDB 中的默认字符集是 utf8mb4,与 MySQL 8.0 及之后版本的默认字符集一致。

排序规则是一组用于比较字符的规则,以及字符的排序顺序。例如,在二进制排序规则中,Aa 不被视为相等:

SET NAMES utf8mb4 COLLATE utf8mb4_bin; SELECT 'A' = 'a'; SET NAMES utf8mb4 COLLATE utf8mb4_general_ci; SELECT 'A' = 'a';
SELECT 'A' = 'a';
+-----------+ | 'A' = 'a' | +-----------+ | 0 | +-----------+ 1 行结果(0.00 秒)
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
查询成功,影响行数:00.00 秒)
SELECT 'A' = 'a';
+-----------+ | 'A' = 'a' | +-----------+ | 1 | +-----------+ 1 行结果(0.00 秒)

以下示例演示了不同 Unicode 排序规则如何比较德语字符 ßss。可以看到,只有更严格的 Unicode 排序规则会将它们视为相等,返回 1(表示 TRUE):

SELECT 'ss' COLLATE utf8mb4_general_ci = 'ß', 'ss' COLLATE utf8mb4_unicode_ci = 'ß', 'ss' COLLATE utf8mb4_0900_ai_ci = 'ß', 'ss' COLLATE utf8mb4_0900_bin = 'ß' \G
*************************** 1. 行 *************************** 'ss' COLLATE utf8mb4_general_ci = 'ß': 0 'ss' COLLATE utf8mb4_unicode_ci = 'ß': 1 'ss' COLLATE utf8mb4_0900_ai_ci = 'ß': 1 'ss' COLLATE utf8mb4_0900_bin = 'ß': 0 1 行结果(0.01 秒)

字符集和排序规则命名

一个字符集可以有多个排序规则,命名格式为 <character_set>_<collation_properties>。例如,utf8mb4 字符集有一个排序规则叫 utf8mb4_bin,这是 utf8mb4 的二进制排序规则。多个排序规则属性可以用下划线 _ 分隔。

下表列出了常见的排序规则属性及其含义。

排序规则属性含义
_bin二进制
_ci不区分大小写
_ai_ci不区分重音符号,大小写不敏感
_0900_binUnicode UCA 9.0.0,二进制
_unicode_ci(较旧)Unicode UCA 排序规则,大小写不敏感
_general_ci较宽松的 Unicode 排序规则,大小写不敏感

TiDB 支持的字符集和排序规则

目前,TiDB 支持以下字符集:

SHOW CHARACTER SET;
+---------+-------------------------------------+-------------------+--------+ | Charset | Description | Default collation | Maxlen | +---------+-------------------------------------+-------------------+--------+ | ascii | US ASCII | ascii_bin | 1 | | binary | 二进制 | binary | 1 | | gbk | 中文内码规范 | gbk_chinese_ci | 2 | | latin1 | Latin1 | latin1_bin | 1 | | utf8 | UTF-8 Unicode | utf8_bin | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_bin | 4 | +---------+-------------------------------------+-------------------+--------+

TiDB 支持以下排序规则:

SHOW COLLATION;
+--------------------+---------+-----+---------+----------+---------+---------------+ | Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute | +--------------------+---------+-----+---------+----------+---------+---------------+ | ascii_bin | ascii | 65 ||| 1 | PAD SPACE | | binary | binary | 63 ||| 1 | NO PAD | | gbk_bin | gbk | 87 | || 1 | PAD SPACE | | gbk_chinese_ci | gbk | 28 ||| 1 | PAD SPACE | | latin1_bin | latin1 | 47 ||| 1 | PAD SPACE | | utf8_bin | utf8 | 83 ||| 1 | PAD SPACE | | utf8_general_ci | utf8 | 33 | || 1 | PAD SPACE | | utf8_unicode_ci | utf8 | 192 | || 8 | PAD SPACE | | utf8mb4_0900_ai_ci | utf8mb4 | 255 | || 0 | NO PAD | | utf8mb4_0900_bin | utf8mb4 | 309 | || 1 | NO PAD | | utf8mb4_bin | utf8mb4 | 46 ||| 1 | PAD SPACE | | utf8mb4_general_ci | utf8mb4 | 45 | || 1 | PAD SPACE | | utf8mb4_unicode_ci | utf8mb4 | 224 | || 8 | PAD SPACE | +--------------------+---------+-----+---------+----------+---------+---------------+

你可以使用以下语句查看对应字符集的排序规则(在 新排序规则框架 下):

SHOW COLLATION WHERE Charset = 'utf8mb4';
+--------------------+---------+-----+---------+----------+---------+---------------+ | Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute | +--------------------+---------+-----+---------+----------+---------+---------------+ | utf8mb4_0900_ai_ci | utf8mb4 | 255 | || 0 | NO PAD | | utf8mb4_0900_bin | utf8mb4 | 309 | || 1 | NO PAD | | utf8mb4_bin | utf8mb4 | 46 ||| 1 | PAD SPACE | | utf8mb4_general_ci | utf8mb4 | 45 | || 1 | PAD SPACE | | utf8mb4_unicode_ci | utf8mb4 | 224 | || 8 | PAD SPACE | +--------------------+---------+-----+---------+----------+---------+---------------+

关于 TiDB 对 GBK 字符集的支持详情,请参见 GBK

TiDB 中的 utf8utf8mb4

在 MySQL 中,字符集 utf8 限制为最多三字节。这足以存储基本多语言平面(BMP)中的字符,但不足以存储如表情符号等字符。建议在新安装时使用 utf8mb4,并迁移 away from utf8

在 MySQL 和 TiDB 中,utf8utf8mb3 是同一字符集的别名。

默认情况下,TiDB 也将 utf8 限制为最多三字节,以确保在 TiDB 中创建的数据可以安全地在 MySQL 中还原。你可以通过修改系统变量 tidb_check_mb4_value_in_utf8OFF 来禁用此限制。但强烈建议使用 utf8mb4,以获得完整的 Unicode 支持和更好的兼容性。

以下示例演示在表中插入 4 字节表情字符的默认行为。对于 utf8 字符集,INSERT 语句会失败;而对于 utf8mb4,会成功:

CREATE TABLE utf8_test ( c char(1) NOT NULL ) CHARACTER SET utf8;
查询成功,影响行数:0(0.09 秒)
CREATE TABLE utf8m4_test ( c char(1) NOT NULL ) CHARACTER SET utf8mb4;
查询成功,影响行数:0(0.09 秒)
INSERT INTO utf8_test VALUES ('😉');
错误 1366 (HY000): incorrect utf8 value f09f9889(😉) for column c
INSERT INTO utf8m4_test VALUES ('😉');
查询成功,影响行数:1(0.02 秒)
SELECT char_length(c), length(c), c FROM utf8_test;
空集(0.01 秒)
SELECT char_length(c), length(c), c FROM utf8m4_test;
+----------------+-----------+------+ | char_length(c) | length(c) | c | +----------------+-----------+------+ | 1 | 4 | 😉 | +----------------+-----------+------+ 1 行结果(0.00 秒)

不同层级的字符集和排序规则

字符集和排序规则可以在不同层级设置。

数据库字符集和排序规则

每个数据库都有字符集和排序规则。可以使用以下语句指定数据库的字符集和排序规则:

CREATE DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name] ALTER DATABASE db_name [[DEFAULT] CHARACTER SET charset_name] [[DEFAULT] COLLATE collation_name]

此处 DATABASE 可替换为 SCHEMA

不同数据库可以使用不同的字符集和排序规则。使用 character_set_databasecollation_database 查看当前数据库的字符集和排序规则:

CREATE SCHEMA test1 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
查询成功,影响行数:00.09 秒)
USE test1;
数据库已切换
SELECT @@character_set_database, @@collation_database;
+--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | utf8mb4 | utf8mb4_general_ci | +--------------------------|----------------------+ 1 行结果(0.00 秒)
CREATE SCHEMA test2 CHARACTER SET latin1 COLLATE latin1_bin;
查询成功,影响行数:00.09 秒)
USE test2;
数据库已切换
SELECT @@character_set_database, @@collation_database;
+--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ | latin1 | latin1_bin | +--------------------------|----------------------+ 1 行结果(0.00 秒)

你也可以在 INFORMATION_SCHEMA 中看到这两个值:

SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'db_name';

表字符集和排序规则

可以使用以下语句为表指定字符集和排序规则:

CREATE TABLE tbl_name (column_list) [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]] ALTER TABLE tbl_name [[DEFAULT] CHARACTER SET charset_name] [COLLATE collation_name]

例如:

CREATE TABLE t1(a int) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
查询成功,影响行数:00.08 秒)

如果未指定表的字符集和排序规则,则使用数据库的默认值。如果只指定字符集为 utf8mb4,未指定排序规则,则排序规则由系统变量 default_collation_for_utf8mb4 决定。

字段字符集和排序规则

可以使用以下语句为字段指定字符集和排序规则:

col_name {CHAR | VARCHAR | TEXT} (col_length) [CHARACTER SET charset_name] [COLLATE collation_name] col_name {ENUM | SET} (val_list) [CHARACTER SET charset_name] [COLLATE collation_name]

如果未指定字段的字符集和排序规则,则使用表的默认值。如果只指定字符集为 utf8mb4,未指定排序规则,则由系统变量 default_collation_for_utf8mb4 决定。

字符串的字符集和排序规则

每个字符串对应一个字符集和排序规则。当你使用字符串时,可以使用以下语法:

[_charset_name]'string' [COLLATE collation_name]

示例:

SELECT 'string'; SELECT _utf8mb4'string'; SELECT _utf8mb4'string' COLLATE utf8mb4_general_ci;

规则说明:

  • 规则 1:如果你指定 CHARACTER SET charset_nameCOLLATE collation_name,则直接使用对应的字符集和排序规则。
  • 规则 2:如果你只指定 CHARACTER SET charset_name,未指定 COLLATE collation_name,则使用 charset_name 的字符集和其默认排序规则。
  • 规则 3:如果既未指定 CHARACTER SET 也未指定 COLLATE,则使用系统变量 character_set_connectioncollation_connection 所定义的字符集和排序规则。

客户端连接的字符集和排序规则

  • 服务器的字符集和排序规则为系统变量 character_set_servercollation_server 的值。

  • 默认数据库的字符集和排序规则为系统变量 character_set_databasecollation_database 的值。

你可以使用 character_set_connectioncollation_connection 来为每个连接设置字符集和排序规则。character_set_client 变量用于设置客户端字符集。

在返回结果之前,系统变量 character_set_results 指示服务器返回查询结果给客户端时所用的字符集,包括结果的元数据。

你可以使用以下语句设置与客户端相关的字符集和排序规则:

  • SET NAMES 'charset_name' [COLLATE 'collation_name']

    SET NAMES 表示客户端用来向服务器发送 SQL 语句的字符集。SET NAMES utf8mb4 表示所有来自客户端的请求以及服务器返回的结果都使用 utf8mb4。

    SET NAMES 'charset_name' 等价于以下组合语句:

    SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name;

    COLLATE 为可选项,若省略,则使用 charset_name 的默认排序规则设置 collation_connection

  • SET CHARACTER SET 'charset_name'

    类似于 SET NAMESSET CHARACTER SET 'charset_name' 等价于:

    SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection=@@character_set_database; SET collation_connection = @@collation_database;

字符集和排序规则的选择优先级

String > Column > Table > Database > Server

选择字符集和排序规则的通用规则

  • 规则 1:如果你指定 CHARACTER SET charset_nameCOLLATE collation_name,则直接使用对应的字符集和排序规则。
  • 规则 2:如果你只指定 CHARACTER SET charset_name,未指定 COLLATE collation_name,则使用 charset_name 的字符集和其默认排序规则。
  • 规则 3:如果既未指定 CHARACTER SET 也未指定 COLLATE,则使用排序规则优先级更高的字符集和排序规则。

字符有效性检查

如果指定的字符集为 utf8utf8mb4,TiDB 仅支持有效的 utf8 字符。对于无效字符,TiDB 会报错 incorrect utf8 value。TiDB 中的字符有效性检查与 MySQL 8.0 兼容,但与 MySQL 5.7 及早期版本不兼容。

若要禁用此错误检测,可使用 set @@tidb_skip_utf8_check=1; 跳过字符检查。

排序规则支持框架

在 v4.0 之前,TiDB 仅提供 旧排序规则框架。在此框架下,TiDB 支持大部分 MySQL 排序规则的语法解析,但语义上将所有排序规则视为二进制排序。

自 v4.0 起,TiDB 支持 新排序规则框架。在此框架下,TiDB 语义解析不同的排序规则,并在比较字符串时严格遵循排序规则。

旧排序规则框架

在 v4.0 之前,你可以在 TiDB 中指定大部分 MySQL 排序规则,这些排序规则按照默认排序规则处理,即字节顺序决定字符顺序。不同于 MySQL,TiDB 不处理字符末尾的空格,这导致以下行为差异:

CREATE TABLE t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci PRIMARY KEY);
查询成功,无影响行数
INSERT INTO t VALUES ('A');
查询成功,影响行数:1
INSERT INTO t VALUES ('a');
查询成功,影响行数:1

在 TiDB 中,上述语句执行成功。而在 MySQL 中,由于 utf8mb4_general_ci 是不区分大小写的,会报 Duplicate entry 'a' 错误。

INSERT INTO t1 VALUES ('a ');
查询成功,影响行数:1

在 TiDB 中,上述语句执行成功。而在 MySQL 中,由于比较是在填充空格后进行,会返回 Duplicate entry 'a ' 错误。

新排序规则框架

自 TiDB v4.0 起,引入完整的排序规则框架。

此新框架支持语义解析排序规则。TiDB 在集群首次初始化时默认启用新框架。

在新框架下,TiDB 支持 utf8_general_ciutf8mb4_general_ciutf8_unicode_ciutf8mb4_unicode_ciutf8mb4_0900_binutf8mb4_0900_ai_cigbk_chinese_cigbk_bin 排序规则,与 MySQL 兼容。

当使用 utf8_general_ciutf8mb4_general_ciutf8_unicode_ciutf8mb4_unicode_ciutf8mb4_0900_ai_cigbk_chinese_ci 时,字符串比较为不区分大小写和不区分重音符号。同时,TiDB 也修正了排序规则的 PADDING 行为:

CREATE TABLE t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci PRIMARY KEY);
查询成功,影响行数:00.00 秒)
INSERT INTO t VALUES ('A');
查询成功,影响行数:10.00 秒)
INSERT INTO t VALUES ('a');
ERROR 1062 (23000): Duplicate entry 'a' for key 't.PRIMARY' -- TiDB 兼容 MySQL 的不区分大小写排序规则。
INSERT INTO t VALUES ('a ');
ERROR 1062 (23000): Duplicate entry 'a ' for key 't.PRIMARY' -- TiDB 修改了 `PADDING` 行为以兼容 MySQL。

表达式中排序规则的 Coercibility 值

如果一个表达式涉及多个不同排序规则的子句,则需要推断所用的排序规则。规则如下:

  • 显式 COLLATE 子句的 coercibility 值为 0
  • 如果两个字符串的排序规则不兼容,则两个不同排序规则的字符串拼接的 coercibility 值为 1
  • 字段、CAST()CONVERT()BINARY() 的排序规则 coercibility 值为 2
  • 系统常量(由 USER()VERSION() 返回的字符串) coercibility 值为 3
  • 常量的 coercibility 值为 4
  • 数字或中间变量的 coercibility 值为 5
  • NULL 或由 NULL 派生的表达式的 coercibility 值为 6

在推断排序规则时,TiDB 优先使用 coercibility 值较低的表达式的排序规则。如果两个子句的 coercibility 值相同,则根据以下优先级确定排序规则:

binary > utf8mb4_bin > (utf8mb4_general_ci = utf8mb4_unicode_ci) > utf8_bin > (utf8_general_ci = utf8_unicode_ci) > latin1_bin > ascii_bin

TiDB 在以下情况下无法推断排序规则,并会报错:

  • 两个子句的排序规则不同,且 coercibility 值均为 0
  • 两个子句的排序规则不兼容,且表达式的返回类型为 String

COLLATE 子句

TiDB 支持使用 COLLATE 子句指定表达式的排序规则。此表达式的 coercibility 值为 0,优先级最高。示例:

SELECT 'a' = _utf8mb4 'A' collate utf8mb4_general_ci;
+-----------------------------------------------+ | 'a' = _utf8mb4 'A' collate utf8mb4_general_ci | +-----------------------------------------------+ | 1 | +-----------------------------------------------+ 1 行结果(0.00 秒)

更多详情请参见 Connection Character Sets and Collations

文档内容是否有帮助?