From 5e60f38e9280491cffca49f923efd3066aab14f1 Mon Sep 17 00:00:00 2001 From: wjHuang Date: Fri, 17 Apr 2020 17:05:33 +0800 Subject: [PATCH 1/2] reference: add document for new collation (#2606) --- TOC.md | 2 +- .../tidb-server/configuration-file.md | 6 + reference/mysql-compatibility.md | 9 - ...r-set.md => characterset-and-collation.md} | 191 ++++++++++++------ reference/sql/statements/alter-database.md | 2 +- reference/sql/statements/create-database.md | 2 +- reference/sql/statements/set-names.md | 2 +- .../system-databases/information-schema.md | 2 +- reference/tools/syncer.md | 2 +- 9 files changed, 137 insertions(+), 81 deletions(-) rename reference/sql/{character-set.md => characterset-and-collation.md} (51%) diff --git a/TOC.md b/TOC.md index 506bab4fe09f..42060a3e3393 100644 --- a/TOC.md +++ b/TOC.md @@ -222,7 +222,7 @@ - [约束](/reference/sql/constraints.md) - [生成列](/reference/sql/generated-columns.md) - [分区表](/reference/sql/partitioning.md) - - [字符集](/reference/sql/character-set.md) + - [字符集](/reference/sql/characterset-and-collation.md) - [SQL 模式](/reference/sql/sql-mode.md) - [SQL 诊断](/reference/system-databases/sql-diagnosis.md) - [视图](/reference/sql/view.md) diff --git a/reference/configuration/tidb-server/configuration-file.md b/reference/configuration/tidb-server/configuration-file.md index de4cd0c1bba0..d39f9fe8ef5a 100644 --- a/reference/configuration/tidb-server/configuration-file.md +++ b/reference/configuration/tidb-server/configuration-file.md @@ -111,6 +111,12 @@ TiDB 配置文件比命令行参数支持更多的选项。你可以在 [config/ + 默认值:[] + 默认情况下,该 list 名单为空,表示没有所需修复的坏表信息。 +### `new_collations_enabled_on_first_bootstrap` + ++ 用于开启新的 collation 支持 ++ 默认值:false ++ 注意:该配置项只有在初次初始化集群时生效,初始化集群后,无法通过更改该配置项打开或关闭新的 collation 框架;4.0 版本之前的 TiDB 集群升级到 4.0 时,由于集群已经初始化过,该参数无论如何配置,都作为 false 处理。 + ### `max-server-connections` + TiDB 中同时允许的最大客户端连接数,用于资源控制。 diff --git a/reference/mysql-compatibility.md b/reference/mysql-compatibility.md index 8c32c90171c9..161320bac096 100644 --- a/reference/mysql-compatibility.md +++ b/reference/mysql-compatibility.md @@ -24,7 +24,6 @@ TiDB 支持 MySQL 传输协议及其绝大多数的语法。这意味着您现 * 外键约束 * 全文/空间函数与索引 * 非 `ascii`/`latin1`/`binary`/`utf8`/`utf8mb4` 的字符集 -* `BINARY` 之外的排序规则 * SYS schema * MySQL 追踪优化器 * XML 函数 @@ -118,8 +117,6 @@ TiDB 支持常用的 MySQL 内建函数,但是不是所有的函数都已经 - 不支持修改 `DECIMAL` 类型的精度 - 不支持更改 `UNSIGNED` 属性 - 只支持将 `CHARACTER SET` 属性从 `utf8` 更改为 `utf8mb4` -+ Alter Database - - 只支持将 `CHARACTER SET` 属性从 `utf8` 更改为 `utf8mb4` + `LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}`: TiDB 支持的语法,但是在 TiDB 中不会生效。所有支持的 DDL 变更都不会锁表。 + `ALGORITHM [=] {DEFAULT|INSTANT|INPLACE|COPY}`: TiDB 完全支持 `ALGORITHM=INSTANT` 和 `ALGORITHM=INPLACE` 语法,但运行过程与 MySQL 有所不同,因为 MySQL 中的一些 `INPLACE` 操作实际上是 TiDB 中的 `INSTANT` 操作。`ALGORITHM=COPY` 语法在 TiDB 中不会生效,会返回警告信息。 + 单个 `ALTER TABLE` 语句中无法完成多个操作。例如,不能用一个语句来添加多个列或多个索引。 @@ -233,12 +230,6 @@ TiDB 不需要导入时区表数据也能使用所有时区名称,采用系统 与 MySQL 一样,TiDB 默认启用了 `NO_ZERO_DATE` 和 `NO_ZERO_IN_DATE` 模式,不建议将这两个模式设为禁用。尽管将这些模式设为禁用时 TiDB 仍可正常使用,但 TiKV coprocessor 会受到影响,具体表现为,执行特定类型的语句,将日期和时间处理函数下推到 TiKV 时可能会导致语句错误。 -#### 字符串类型行末空格的处理 - -目前 TiDB 在进行数据插入时,对于 `VARCHAR` 类型会保留行末空格,对于 `CHAR` 类型会插入截断空格后的数据。在没有索引的情况下,TiDB 和 MySQL 行为保持一致。如果 `VARCHAR` 类型上有 `UNIQUE` 索引,MySQL 在判断是否重复的时候,和处理 `CHAR` 类型一样,先截断 `VARCHAR` 数据末行空格再作判断;TiDB 则是按照保留空格的情况处理。 - -在做比较时,MySQL 会先截去常量和 Column 的末尾空格再作比较,而 TiDB 则是保留常量和 Column 的末尾空格来做精确比较。 - ### 类型系统的区别 以下的列类型 MySQL 支持,但 TiDB 不支持: diff --git a/reference/sql/character-set.md b/reference/sql/characterset-and-collation.md similarity index 51% rename from reference/sql/character-set.md rename to reference/sql/characterset-and-collation.md index 0537b208a809..7cf88ef8ad10 100644 --- a/reference/sql/character-set.md +++ b/reference/sql/characterset-and-collation.md @@ -1,11 +1,12 @@ --- -title: 字符集支持 +title: 字符集和排序规则 category: reference +aliases: ['/docs-cn/dev/reference/sql/character-set/'] --- # 字符集支持 -名词解释,下面的阐述中会交错使用中文或者英文,请互相对照: +下面的阐述中会交错使用中文或者英文,请互相对照: * Character Set:字符集 * Collation:排序规则 @@ -33,71 +34,27 @@ SHOW CHARACTER SET; > **注意:** > -> - 在 `TiDB` 中 `utf8` 被当做成了 `utf8mb4` 来处理。 -> - 每种字符集都对应一个默认的 Collation,当前有且仅有一个。 +> - 每种字符集都对应一个默认的 Collation,并且仅有一个。 -对于字符集来说,至少会有一个 Collation(排序规则)与之对应。而大部分字符集实际上会有多个 Collation。利用以下的语句可以查看: +对于字符集来说,至少会有一个 Collation(排序规则)与之对应。利用以下的语句可以查看字符集对应的排序规则(以下是[新的 Collation 框架](#新框架下的-collation-支持))下的结果: {{< copyable "sql" >}} ```sql -SHOW COLLATION WHERE Charset = 'latin1'; +SHOW COLLATION WHERE Charset = 'utf8mb4'; ``` ``` -+-------------------|---------|------|---------|----------|---------+ -| Collation | Charset | Id | Default | Compiled | Sortlen | -+-------------------|---------|------|---------|----------|---------+ -| latin1_german1_ci | latin1 | 5 | | Yes | 1 | -| latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | -| latin1_danish_ci | latin1 | 15 | | Yes | 1 | -| latin1_german2_ci | latin1 | 31 | | Yes | 1 | -| latin1_bin | latin1 | 47 | | Yes | 1 | -| latin1_general_ci | latin1 | 48 | | Yes | 1 | -| latin1_general_cs | latin1 | 49 | | Yes | 1 | -| latin1_spanish_ci | latin1 | 94 | | Yes | 1 | -+-------------------|---------|------|---------|----------|---------+ -8 rows in set (0.00 sec) ++--------------------+---------+------+---------+----------+---------+ +| Collation | Charset | Id | Default | Compiled | Sortlen | ++--------------------+---------+------+---------+----------+---------+ +| utf8mb4_bin | utf8mb4 | 46 | Yes | Yes | 1 | +| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | ++--------------------+---------+------+---------+----------+---------+ +2 rows in set (0.00 sec) ``` -`latin1` Collation(排序规则)分别有以下含义: - -| Collation | 含义 | -|:------------------|:----------------------------------| -| latin1_bin | latin1 编码的二进制表示 | -| latin1_danish_ci | 丹麦语/挪威语,不区分大小写 | -| latin1_general_ci | 多种语言的 (西欧),不区分大小写 | -| latin1_general_cs | 多种语言的 (ISO 西欧),区分大小写 | -| latin1_german1_ci | 德国 DIN-1 (字典序),不区分大小写 | -| latin1_german2_ci | 德国 DIN-2,不区分大小写 | -| latin1_spanish_ci | 现代西班牙语,不区分大小写 | -| latin1_swedish_ci | 瑞典语/芬兰语,不区分大小写 | - -每一个字符集,都有一个默认的 Collation,例如 `utf8` 的默认 Collation 就为 `utf8_bin`。 - -> **注意:** -> -> `TiDB` 目前的 Collation 只支持区分大小写的比较排序规则。 - -## Collation 命名规则 - -`TiDB` 的 Collation 遵循着如下的命名规则: - -* Collation 的前缀是它相应的字符集,通常之后会跟着一个或者更多的后缀来表名其他的排序规则, 例如:utf8_general_ci 和 lation1_swedish_ci 是 utf8 - 和 latin1 字符集的 Collation。但是 binary 字符集只有一个 Collation,就是 binary。 -* 一个语言对应的 Collation 会包含语言的名字,例如 utf8_turkish_ci 和 utf8_hungarian_ci 是依据 Turkish(土耳其语) 和 Hungarian(匈牙利语) 的排序规则来排序。 -* Collation 的后缀表示了 Collation 是否区分大小写和是否区分口音。下面的表展示了这些特性: - -| 后缀 | 含义 | -|:-----|:---------------------------------| -| \_ai | 口音不敏感(Accent insensitive) | -| \_as | 口音敏感 (Accent sensitive) | -| \_ci | 大小写不敏感 | -| \_cs | 大小写敏感 | - -> **注意:** -> -> 目前为止 TiDB 只支持部分以上提到的 Collation。 +每一个字符集,都有一个默认的 Collation,例如 `utf8mb4` 的默认 Collation 为 `utf8mb4_bin`。 ## 集群 Character Set 和 Collation @@ -126,7 +83,7 @@ ALTER DATABASE db_name {{< copyable "sql" >}} ```sql -create schema test1 character set utf8 COLLATE uft8_general_ci; +create schema test1 character set utf8mb4 COLLATE uft8mb4_general_ci; ``` ``` @@ -153,7 +110,7 @@ SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ -| utf8 | uft8_general_ci | +| utf8mb4 | uft8mb4_general_ci | +--------------------------|----------------------+ 1 row in set (0.00 sec) ``` @@ -161,7 +118,7 @@ SELECT @@character_set_database, @@collation_database; {{< copyable "sql" >}} ```sql -create schema test2 character set latin1 COLLATE latin1_general_ci; +create schema test2 character set latin1 COLLATE latin1_bin; ``` ``` @@ -188,7 +145,7 @@ SELECT @@character_set_database, @@collation_database; +--------------------------|----------------------+ | @@character_set_database | @@collation_database | +--------------------------|----------------------+ -| latin1 | latin1_general_ci | +| latin1 | latin1_bin | +--------------------------|----------------------+ 1 row in set (0.00 sec) ``` @@ -221,7 +178,7 @@ ALTER TABLE tbl_name {{< copyable "sql" >}} ```sql -CREATE TABLE t1(a int) CHARACTER SET utf8 COLLATE utf8_general_ci; +CREATE TABLE t1(a int) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` ``` @@ -260,8 +217,8 @@ col_name {ENUM | SET} (val_list) ```sql SELECT 'string'; -SELECT _latin1'string'; -SELECT _latin1'string' COLLATE latin1_danish_ci; +SELECT _utf8mb4'string'; +SELECT _utf8mb4'string' COLLATE utf8mb4_general_ci; ``` 规则,如下: @@ -283,7 +240,7 @@ SELECT _latin1'string' COLLATE latin1_danish_ci; * `SET NAMES 'charset_name' [COLLATE 'collation_name']` -`SET NAMES` 用来设定客户端会在之后的请求中使用的字符集。`SET NAMES utf8` 表示客户端会在接下来的请求中,都使用 utf8 字符集。服务端也会在之后返回结果的时候使用 utf8 字符集。 +`SET NAMES` 用来设定客户端会在之后的请求中使用的字符集。`SET NAMES utf8mb4` 表示客户端会在接下来的请求中,都使用 utf8mb4 字符集。服务端也会在之后返回结果的时候使用 utf8mb4 字符集。 `SET NAMES 'charset_name'` 语句其实等于下面语句的组合: {{< copyable "sql" >}} @@ -310,7 +267,7 @@ SET collation_connection = @@collation_database; ## 集群,服务器,数据库,表,列,字符串 Character Sets 和 Collation 优化级 -字符串 => 列 => 表 => 数据库 => 服务器 => 集群 +字符串 > 列 > 表 > 数据库 > 服务器 > 集群 ## Character Sets 和 Collation 通用选择规则 @@ -324,4 +281,106 @@ SET collation_connection = @@collation_database; 如果不希望报错,可以通过 `set @@tidb_skip_utf8_check=1;` 跳过字符检查。 +## 排序规则支持 + +Collation 的语法支持和语义支持受到配置项 [`new_collation_enable`](/reference/configuration/tidb-server/configuration-file.md#new_collations_enabled_on_first_bootstrap) 的影响。这里语法支持和语义支持有所区别。语法支持是指 TiDB 能够解析和设置 Collation;而语义支持是指 TiDB 能够在比较字符串时正确地使用 Collation。 + +在 4.0 版本之前,TiDB 只提供了旧的 Collation 框架,能够在语法上支持的绝大部分 MySQL Collation,但语义上所有的 Collation 都当成 binary Collation。 + +4.0 版本中,TiDB 增加了新的 Collation 框架用于在语义上支持不同的 Collation,保证字符串比较时严格遵循对应的 Collation,详情请见下文。 + +### 旧框架下的 Collation 支持 + +在 4.0 版本之前,TiDB 中可以指定大部分 MySQl 中的 Collation,并把这些 Collation 按照默认 Collation 处理,即以编码字节序为字符定序。和 MySQL 不同的是,TiDB 在比较字符前按照 Collation 的 `PADDING` 属性将字符补齐空格,因此会造成以下的行为区别: + +{{< copyable "sql" >}} + +```sql +create table t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci primary key); +Query OK, 0 rows affected +insert into t values ('A'); +Query OK, 1 row affected +insert into t values ('a'); +Query OK, 1 row affected # MySQL 中,由于 utf8mb4_general_ci 大小写不敏感,报错 Duplicate entry 'a'。 +insert into t1 values ('a '); +Query OK, 1 row affected # MySQL 中,由于补齐空格比较,报错 Duplicate entry 'a '。 +``` + +### 新框架下的 Collation 支持 + +TiDB 4.0 新增了完整的 Collation 支持框架,从语义上支持了 Collation,并新增了配置开关 `new_collation_enabled_on_first_boostrap`,在集群初次初始化时决定是否启用新 Collation 框架。在该配置开关打开之后初始化集群,可以通过 `mysql`.`tidb` 表中的 `new_collation_enabled` 变量确认新 Collation 是否启用: + +{{< copyable "sql" >}} + +```sql +select VARIABLE_VALUE from mysql.tidb where VARIABLE_NAME='new_collation_enabled'; +``` + +``` ++----------------+ +| VARIABLE_VALUE | ++----------------+ +| True | ++----------------+ +1 row in set (0.00 sec) +``` + +在新的 Collation 框架下,TiDB 能够支持 `utf8_general_ci` 和 `utf8mb4_general_ci` 这两种 Collation, 其排序规则与 MySQL 兼容。 + +使用 `utf8_general_ci` 或者 `utf8mb4_general_ci` 时,字符串之间的比较是大小写不敏感 (case-insensitive) 和口音不敏感 (accent-insensitive) 的。同时,TiDB 还修正了 Collation 的 `PADDING` 行为: + +{{< copyable "sql" >}} + +```sql +create table t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci primary key); +Query OK, 0 rows affected (0.00 sec) +insert into t values ('A'); +Query OK, 1 row affected (0.00 sec) +insert into t values ('a'); +ERROR 1062 (23000): Duplicate entry 'a' for key 'PRIMARY' +insert into t values ('a '); +ERROR 1062 (23000): Duplicate entry 'a ' for key 'PRIMARY' +``` + +> **注意:** +> +> TiDB 中 padding 的实现方式与 MySQL 的不同。在 MySQL 中,padding 是通过补齐空格实现的。而在 TiDB 中 padding 是通过裁剪掉末尾的空格来实现的。两种做法在绝大多数情况下是一致的,唯一的例外是字符串尾部包含小于空格 (0x20) 的字符时,例如 `'a' < 'a\t'` 在 TiDB 中的结果为 `1`,而在 MySQL 中,其等价于 `'a ' < 'a\t'`,结果为 `0`。 + +## 表达式中 Collation 的 Coercibility 值 + +如果一个表达式涉及多个不同 Collation 的子表达式时,需要对计算时用的 Collation 进行推断,规则如下: + +1. 显式 `COLLATE` 子句的 coercibility 值为 `0`。 +2. 如果两个字符串的 Collation 不兼容,这两个字符串 `concat` 结果的 coercibility 值为 `1`。目前所实现的 Collation 都是互相兼容的。 +3. 列的 Collation 的 coercibility 值为 `2`。 +4. 系统常量(`USER()` 或者 `VERSION()` 返回的字符串)的 coercibility 值为 `3`。 +5. 常量的 coercibility 值为 `4`。 +6. 数字或者中间变量的 coercibility 值为 `5`。 +7. `NULL` 或者由 `NULL` 派生出的表达式的 coercibility 值为 `6`。 + +在推断 Collation 时,TiDB 优先使用 coercibility 值较低的表达式的 Collation(与 MySQL 一致)。如果 coercibility 值相同,则按以下优先级确定 Collation: + +binary > utf8mb4_bin > utf8mb4_general_ci > utf8_bin > utf8_general_ci > latin1_bin > ascii_bin + +如果两个子表达式的 Collation 不相同,而且表达式的 coercibility 值都为 `0` 时,TiDB无法推断 Collation 并报错。 + +## `COLLATE` 子句 + +TiDB 支持使用 `COLLATE` 子句来指定一个表达式的 Collation,该表达式的 coercibility 值为 `0`,具有最高的优先级。示例如下: + +{{< copyable "sql" >}} + +```sql +select 'a' = 'A' collate utf8mb4_general_ci; +``` + +``` ++--------------------------------------+ +| 'a' = 'A' collate utf8mb4_general_ci | ++--------------------------------------+ +| 1 | ++--------------------------------------+ +1 row in set (0.00 sec) +``` + 更多细节,参考 [Connection Character Sets and Collations](https://dev.mysql.com/doc/refman/5.7/en/charset-connection.html)。 diff --git a/reference/sql/statements/alter-database.md b/reference/sql/statements/alter-database.md index 8f1839f5aa66..6e36ac3c122d 100644 --- a/reference/sql/statements/alter-database.md +++ b/reference/sql/statements/alter-database.md @@ -20,7 +20,7 @@ alter_specification: | [DEFAULT] COLLATE [=] collation_name ``` -`alter_specification` 选项用于指定数据库具体的 `CHARACTER SET` 和 `COLLATE`。目前 TiDB 只支持部分的字符集和排序规则,请参照[字符集支持](/reference/sql/character-set.md)。 +`alter_specification` 选项用于指定数据库具体的 `CHARACTER SET` 和 `COLLATE`。目前 TiDB 只支持部分的字符集和排序规则,请参照[字符集支持](/reference/sql/characterset-and-collation.md)。 ## 另请参阅 diff --git a/reference/sql/statements/create-database.md b/reference/sql/statements/create-database.md index 406cf63bcd9d..bf2349a473e2 100644 --- a/reference/sql/statements/create-database.md +++ b/reference/sql/statements/create-database.md @@ -47,7 +47,7 @@ create_specification: 当创建已存在的数据库且不指定使用 `IF NOT EXISTS` 时会报错。 -`create_specification` 选项用于指定数据库具体的 `CHARACTER SET` 和 `COLLATE`。目前 TiDB 只支持部分的字符集和排序规则,请参照[字符集支持](/reference/sql/character-set.md)。 +`create_specification` 选项用于指定数据库具体的 `CHARACTER SET` 和 `COLLATE`。目前 TiDB 只支持部分的字符集和排序规则,请参照[字符集支持](/reference/sql/characterset-and-collation.md)。 ## 示例 diff --git a/reference/sql/statements/set-names.md b/reference/sql/statements/set-names.md index 227f25d22990..537eff757ebc 100644 --- a/reference/sql/statements/set-names.md +++ b/reference/sql/statements/set-names.md @@ -110,4 +110,4 @@ SHOW VARIABLES LIKE 'character_set%'; * [SHOW \[GLOBAL|SESSION\] VARIABLES](/reference/sql/statements/show-variables.md) * [SET ](/reference/sql/statements/set-variable.md) -* [Character Set Support](/reference/sql/character-set.md) +* [Character Set Support](/reference/sql/characterset-and-collation.md) diff --git a/reference/system-databases/information-schema.md b/reference/system-databases/information-schema.md index 930812bd6c74..1af2decf7fb5 100644 --- a/reference/system-databases/information-schema.md +++ b/reference/system-databases/information-schema.md @@ -33,7 +33,7 @@ select * from `ANALYZE_STATUS`; ## CHARACTER_SETS 表 -`CHARACTER_SETS` 表提供[字符集](/reference/sql/character-set.md)相关的信息。TiDB 目前仅支持部分字符集。 +`CHARACTER_SETS` 表提供[字符集](/reference/sql/characterset-and-collation.md)相关的信息。TiDB 目前仅支持部分字符集。 {{< copyable "sql" >}} diff --git a/reference/tools/syncer.md b/reference/tools/syncer.md index f15e71b12820..aab14a525f39 100644 --- a/reference/tools/syncer.md +++ b/reference/tools/syncer.md @@ -505,7 +505,7 @@ target-table = "order_2017" 6. 检查字符集。 - TiDB 和 MySQL 的字符集的兼容性不同,详见 [TiDB 支持的字符集](/reference/sql/character-set.md)。 + TiDB 和 MySQL 的字符集的兼容性不同,详见 [TiDB 支持的字符集](/reference/sql/characterset-and-collation.md)。 7. 检查同步的表是否都有主键或者唯一索引。 From 47ae6cca256cc48dc03e3685889d4bdfc73c19ca Mon Sep 17 00:00:00 2001 From: TomShawn <41534398+TomShawn@users.noreply.github.com> Date: Fri, 17 Apr 2020 17:09:28 +0800 Subject: [PATCH 2/2] Update reference/sql/characterset-and-collation.md --- reference/sql/characterset-and-collation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/sql/characterset-and-collation.md b/reference/sql/characterset-and-collation.md index 7cf88ef8ad10..e7aefb66d2dd 100644 --- a/reference/sql/characterset-and-collation.md +++ b/reference/sql/characterset-and-collation.md @@ -1,7 +1,7 @@ --- title: 字符集和排序规则 category: reference -aliases: ['/docs-cn/dev/reference/sql/character-set/'] +aliases: ['/docs-cn/v4.0/reference/sql/character-set/'] --- # 字符集支持