TiDB 6.0 新特性解讀 | Collation 規則

語言: CN / TW / HK

對資料庫而言,合適的字符集和規則能夠大大提升使用者運維和分析的效率。TiDB 從 v4.0 開始支援新 collation 規則,並於 TiDB 6.0 版本進行了更新。本文將深入解讀 Collation 規則在 TiDB 6.0 中的變更和應用。

這裡的“引”,有兩層含義,這第一層是“言”,從 TiDB v6.0 發版說明 中可以瞭解到,TiDB 6.0 引入了很多新特性,同時也引入了新的 發版模型,本文將對 TiDB 6.0 新特性一睹為快。

第二層含義是“拋磚玉”,開源社群的力量是無窮盡的,希望有更多人可以參與到開源中來,那麼如何參與開源,其實途徑遠不止提交程式碼一種,比如,在 AskTUG 社群提問、回答、互動,再如,發現 TiDB 官方文件 有 Bug 或資訊不完整,提出 Issue 和解決方案,又如,參與 TiDB 6.0 Book Rush! 活動,做版本評測、案例文章等等。

預設啟用新 Collation 規則

TiDB 從 v4.0 開始支援新 collation 規則,在大小寫不敏感、口音不敏感、padding 規則上與 MySQL 行為保持一致。

TiDB 6.0 引入了新的 Collation 規則,並將預設啟用新 Collation 框架。新 Collation 規則已在 TiDB 4.0 引入,但一直都是預設關閉項,只有叢集初始化時才能變更。可通過系統表看到該變數值的設定。

TiDB [(none)] 18:45:27> select * from mysql.tidb where variable_name = 'new_collation_enabled';
+-----------------------+----------------+----------------------------------------------------+
| VARIABLE_NAME         | VARIABLE_VALUE | COMMENT                                            |
+-----------------------+----------------+----------------------------------------------------+
| new_collation_enabled | True           | If the new collations are enabled. Do not edit it. |
+-----------------------+----------------+----------------------------------------------------+
1 row in set (0.003 sec)

檢視 I_S.collations 表,可以知道 TiDB 6.0 已支援 11 種規則,較之前未啟用新 collation 框架的版本新增了 5 種規則,分別是 gbk_bin, gbk_chinese_ci, utf8_general_ciutf8_unicode_ci, utf8mb4_unicode_ci

由於很多舊系統使用的是 GBK 字符集,所以在做系統重構的專案,尤其涉及到資料遷移的情況時,對於 GBK 字符集的支援就顯得尤為重要和實用。當然,對於新專案,建議使用 UTF8mb4。

TiDB [(none)] 18:45:51> select version()\G
*************************** 1. row ***************************
version(): 5.7.25-TiDB-v6.0.0
1 row in set (0.001 sec)

TiDB [(none)] 18:46:00> SELECT * FROM information_schema.collations;
+--------------------+--------------------+------+------------+-------------+---------+
| COLLATION_NAME     | CHARACTER_SET_NAME | ID   | IS_DEFAULT | IS_COMPILED | SORTLEN |
+--------------------+--------------------+------+------------+-------------+---------+
| ascii_bin          | ascii              |   65 | Yes        | Yes         |       1 |
| binary             | binary             |   63 | Yes        | Yes         |       1 |
| gbk_bin            | gbk                |   87 |            | Yes         |       1 | (#28645)
| gbk_chinese_ci     | gbk                |   28 | Yes        | Yes         |       1 | (#28645)
| latin1_bin         | latin1             |   47 | Yes        | Yes         |       1 |
| utf8_bin           | utf8               |   83 | Yes        | Yes         |       1 |
| utf8_general_ci    | utf8               |   33 |            | Yes         |       1 |
| utf8_unicode_ci    | utf8               |  192 |            | Yes         |       1 | (#18678)
| utf8mb4_bin        | utf8mb4            |   46 | Yes        | Yes         |       1 |
| utf8mb4_general_ci | utf8mb4            |   45 |            | Yes         |       1 |
| utf8mb4_unicode_ci | utf8mb4            |  224 |            | Yes         |       1 | (#18678)
+--------------------+--------------------+------+------------+-------------+---------+
11 rows in set (0.001 sec)

TiDB [test] 19:05:14> SHOW CHARACTER SET;
+---------+-------------------------------------+-------------------+--------+
| Charset | Description                         | Default collation | Maxlen |
+---------+-------------------------------------+-------------------+--------+
| ascii   | US ASCII                            | ascii_bin         |      1 |
| binary  | binary                              | binary            |      1 |
| gbk     | Chinese Internal Code Specification | gbk_chinese_ci    |      2 |
| latin1  | Latin1                              | latin1_bin        |      1 |
| utf8    | UTF-8 Unicode                       | utf8_bin          |      3 |
| utf8mb4 | UTF-8 Unicode                       | utf8mb4_bin       |      4 |
+---------+-------------------------------------+-------------------+--------+
6 rows in set (0.001 sec)

而在 TiDB v5.4 未啟用新 Collation 的結果為:

TiDB-v5.4 [test] 10:17:22> select version()\G
*************************** 1. row ***************************
version(): 5.7.25-TiDB-v5.4.0
1 row in set (0.001 sec)

TiDB-v5.4 [test] 10:19:39> SELECT * FROM information_schema.collations;
+----------------+--------------------+------+------------+-------------+---------+
| COLLATION_NAME | CHARACTER_SET_NAME | ID   | IS_DEFAULT | IS_COMPILED | SORTLEN |
+----------------+--------------------+------+------------+-------------+---------+
| utf8mb4_bin    | utf8mb4            |   46 | Yes        | Yes         |       1 |
| latin1_bin     | latin1             |   47 | Yes        | Yes         |       1 |
| binary         | binary             |   63 | Yes        | Yes         |       1 |
| ascii_bin      | ascii              |   65 | Yes        | Yes         |       1 |
| utf8_bin       | utf8               |   83 | Yes        | Yes         |       1 |
| gbk_bin        | gbk                |   87 | Yes        | Yes         |       1 |
+----------------+--------------------+------+------------+-------------+---------+
6 rows in set (0.001 sec)

 

新 Collation 注意事項

對於 TiDB 6.0 之前的版本,該配置項的預設值一直為 false ,但可以在叢集初始化之前就改變其設定,如此就可以在叢集初始化之後使用新的 collation 框架。

service_configs:
  tidb:
    new_collations_enabled_on_first_bootstrap: true

不過,這裡要強調注意的是,當 TiDB 叢集跨大版本升級時,需要檢查配置項。以免出現上下游叢集字元校驗規則不一致而導致資料不同步或查詢結果不一致的情況。另外,當使用 BR 進行資料備份、恢復時,也需要注意 Collation 的設定,保證備份前、恢復後的叢集設定相同,防止出現因配置項new_collations_enabled_on_first_bootstrap 設定不同而報錯。

Collation Bug 修復

TiDB 6.0 中修復了2個關於 Collation 的 Bug,分別與比較函式和 JSON 相關,下面舉兩個小案例對其進行測試。

  1. 修復帶有 collation 的 greatest 或 least 函式結果出錯的問題 #31789

測試用例:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
c1 char(20) CHARACTER SET utf8 COLLATE utf8_bin,
c2 char(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
INSERT INTO t1 VALUES ('UUtJeaV','snRXXCZHBPW');

SET names utf8mb4 collate utf8mb4_bin;
SELECT greatest( c1, c2 ) as expr1 FROM t1;
SELECT least( c1, c2 ) as expr1 FROM t1;

SET names utf8mb4 collate utf8mb4_general_ci;
SELECT greatest( c1, c2 ) as expr1 FROM t1;
SELECT least( c1, c2 ) as expr1 FROM t1;

測試結果:

1.png

  1. 修復了 json 型別在 builtin-func 中推導 collation 錯誤的問題 #31320

修復這個問題的主要程式碼如下,期望表現是與 MySQL 一致,在使用 JSON 型別的內部方法時,應當始終使用 utf8mb4_bin 規則。

// The collation of JSON is always utf8mb4_bin in builtin-func which is same as MySQL
// see details https://github.com/pingcap/tidb/issues/31320#issuecomment-1010599311
if isJSON {
   dstCharset, dstCollation = charset.CharsetUTF8MB4, charset.CollationUTF8MB4
}

測試用例:

DROP TABLE IF EXISTS t2;
CREATE TABLE t2 (c1 json);
INSERT INTO t2 VALUES ('{\"測試\": \"你好\"}');

SELECT collation(c1), collation(upper(c1)), collation(elt(1, c1, 0x12)) FROM t2;

測試結果:

2.png

在 TiDB v5.4 中的測試結果為:

tc.jpg

新增內建函式 CHARSET()

TiDB 6.0 新增了一個新內建函式,用來判定入參的字符集,這與 Collation 是相關聯的,所以一併舉例演示。注:從 Issue #3931 記錄來看,這個需求早在 2017 年就提出來了,但是到 6.0 才合併到主幹程式碼。

TiDB [test] 23:54:42> select version()\G
*************************** 1. row ***************************
version(): 5.7.25-TiDB-v6.0.0
1 row in set (0.001 sec)

TiDB [test] 00:03:51> set names utf8mb4;
Query OK, 0 rows affected (0.000 sec)

TiDB [test] 00:03:58> select charset(1);
+------------+
| charset(1) |
+------------+
| binary     |
+------------+
1 row in set (0.001 sec)

TiDB [test] 00:04:03> select charset('1');
+--------------+
| charset('1') |
+--------------+
| utf8mb4      |
+--------------+
1 row in set (0.001 sec)

文件拾遺

正如開篇所提到的,參與開源的途徑有很多種,我們從開源中收益,自然也要回饋社群。

舉一個實際例子,在寫本文查閱文件時,就發現了 Collations 這節在 v6.0 (DMR) 版本下的查詢結果集與實際不符,於是便進行了反饋。

3.png

在 GitHub 上提交了 Issue,處理速度也很快,第二天就已經完成初步修改,現處 Merge 到 master。

相關 Issue 連結為:https://github.com/pingcap/docs/pull/8364

原作者:@ShawnYan 原文連結:https://tidb.net/blog/82d7530c