【TiDB 4.0 PCTA 学习笔记】- 2.4 Behavior Differences Between MySQL and TiDB(TiDB 与 MySQL 的差异)@3+邓喆

课程名称:2.4 Behavior Differences Between MySQL and TiDB(TiDB 与 MySQL 的差异)

学习时长:

15分钟

课程收获:

本课程简要介绍了分布式数据库 TiDB 和单机数据库 MySQL 之间的兼容性。

课程内容:

TiDB 作为开源 NewSQL 数据库的典型代表之一,同样支持 SQL,支持事务 ACID 特性。在通讯协议上,TiDB 选择与 MySQL 完全兼容,并尽可能兼容 MySQL 的语法。因此,基于 MySQL 数据库开发的系统,大多数可以平滑迁移至 TiDB,而几乎不用修改代码。对用户来说,迁移成本极低,过渡自然。

然而,仍有一些 MySQL 的特性和行为,TiDB 目前暂时不支持或表现与 MySQL 有差异。除此之外,TiDB 提供了一些扩展语法和功能,为用户提供更多的便利。

TiDB 仍处在快速发展的道路上,对 MySQL 功能和行为的支持方面,正按 路线图 的规划在前行。

兼容策略

先从总体上概括 TiDB 和 MySQL 兼容策略,如下表:

通讯协议 SQL语法 功能和行为
完全兼容 兼容绝大多数 兼容大多数

截至 4.0 版本,TiDB 与 MySQL 的区别总结如下表:

MySQL TiDB
隔离级别 支持读未提交、读已提交、可重复读、串行化,默认为可重复读 乐观事务支持快照隔离,悲观事务支持快照隔离和读已提交
锁机制 悲观锁 乐观锁、悲观锁
存储过程 支持 不支持
触发器 支持 不支持
事件 支持 不支持
自定义函数 支持 不支持
窗口函数 支持 部分支持
JSON 支持 不支持部分 MySQL 8.0 新增的函数
外键约束 支持 忽略外键约束
字符集 只支持 ascii、latin1、binary、utf8、utf8mb4
增加/删除主键 支持 通过 alter-primary-key 配置开关提供
CREATE TABLE tblName AS SELECT stmt 支持 不支持
CREATE TEMPORARY TABLE 支持 TiDB 忽略 TEMPORARY 关键字,按照普通表创建
DML affected rows 支持 不支持
AutoRandom 列属性 不支持 支持
Sequence 序列生成器 不支持 支持

区别点详述及应对方案

(1) 字符集支持

TiDB 目前支持以下字符集:

tidb> SHOW CHARACTER SET;
+---------|---------------|-------------------|--------+
| Charset | Description   | Default collation | Maxlen |
+---------|---------------|-------------------|--------+
| utf8    | UTF-8 Unicode | utf8_bin          |      3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_bin       |      4 |
| ascii   | US ASCII      | ascii_bin         |      1 |
| latin1  | Latin1        | latin1_bin        |      1 |
| binary  | binary        | binary            |      1 |
+---------|---------------|-------------------|--------+
5 rows in set (0.00 sec)

注意:TiDB 的默认字符集为 utf8mb4,MySQL 5.7 中为 latin1,MySQL 8.0 中修改为 utf8mb4。 当指定的字符集为 utf8utf8mb4 时,TiDB 仅支持合法的 UTF8 字符。对于不合法的字符,会报错:incorrect utf8 value,该字符合法性检查与 MySQL 8.0 一致。对于 MySQL 5.7 及以下版本,会存在允许插入非法 UTF8 字符,但同步到 TiDB 报错的情况。此时,可以通过 TiDB 配置 “tidb_skip_utf8_check” 跳过 UTF8 字符合法性检查强制写入 TiDB。

每一个字符集,都有一个默认的 Collation,例如 utf8 的默认 Collation 为 utf8_bin,TiDB 中字符集的默认 Collation 与 MySQL 不一致,具体如下:

字符集 TiDB 默认 Collation MySQL 5.7 默认 Collation MySQL 8.0 默认 Collation
utf8 utf8_bin utf8_general_ci utf8_general_ci
utf8mb4 utf8mb4_bin utf8mb4_general_ci utf8mb4_0900_ai_ci
ascii ascii_bin ascii_general_ci ascii_general_ci
latin1 latin1_bin latin1_swedish_ci latin1_swedish_ci
binary binary binary binary

在 4.0 版本之前,TiDB 中可以任意指定字符集对应的所有 Collation,并把它们按照默认 Collation 处理,即以编码字节序为字符定序。同时,并未像 MySQL 一样,在比较前按照 Collation 的 PADDING 属性将字符补齐空格。因此,会造成以下的行为区别:

tidb> create table t(a varchar(20) charset utf8mb4 collate utf8mb4_general_ci primary key);
Query OK, 0 rows affected
tidb> insert into t values ('A');
Query OK, 1 row affected
tidb> insert into t values ('a');
Query OK, 1 row affected // MySQL 中,由于 utf8mb4_general_ci 大小写不敏感,报错 Duplicate entry 'a'.
tidb> insert into t1 values ('a ');
Query OK, 1 row affected // MySQL 中,由于补齐空格比较,报错 Duplicate entry 'a '

TiDB 4.0 新增了完整的 Collation 支持框架,允许实现所有 MySQL 中的 Collation,并新增了配置开关 new_collation_enabled_on_first_boostrap,在集群初次初始化时决定是否启用新 Collation 框架。在该配置开关打开之后初始化集群,可以通过 mysql.tidb 表中的 new_collation_enabled 变量确认新 Collation 是否启用:

tidb> select VARIABLE_VALUE from mysql.tidb where VARIABLE_NAME='new_collation_enabled';
+----------------+
| VARIABLE_VALUE |
+----------------+
| True           |
+----------------+
1 row in set (0.00 sec)

在新 Collation 启用后,TiDB 修正了 utf8mb4_general_binutf8_general_binPADDING 行为,会将字符串补齐空格后比较;同时支持了 utf8mb4_general_ciutf8_general_ci,这两个 Collation 与 MySQL 保持兼容。

(2) 系统时区

在 MySQL 中,系统时区 system_time_zone 在 MySQL 服务启动时通过 环境变量 TZ 或命令行参数 --timezone 指定。

对于 TiDB 而言,作为一个分布式数据库,TiDB 需要保证整个集群的系统时区始终一致。因此 TiDB 的系统时区在集群初始化时,由负责初始化的 TiDB 节点环境变量 TZ 决定。集群初始化后,固定在集群状态表 mysql.tidb 中:

tidb> select VARIABLE_VALUE from mysql.tidb where VARIABLE_NAME='system_tz';
+----------------+
| VARIABLE_VALUE |
+----------------+
| Asia/Shanghai  |
+----------------+
1 row in set (0.00 sec)

通过查看 system_time_zone 变量,可以看到该值与状态表中的 system_tz 保持一致:

tidb> select @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| Asia/Shanghai      |
+--------------------+
1 row in set (0.00 sec)

请注意,这意味着 TiDB 的系统时区在初始化后不再更改。若需要改变集群的时区,可以显式指定 time_zone 系统变量,例如:

tidb> set @@global.time_zone='UTC';
Query OK, 0 rows affected (0.00 sec)

学习过程中参考的其他资料

同学你好,感谢参与 TiDB 4.0 课程的学习!

本篇笔记逻辑清晰、内容丰富,被评选为优质笔记,将额外获得 20 积分,并在 「TiDB 培训」分类下获得“置顶”权益,积分兑换规则将于近期开放,敬请关注!

期待您继续产出优质内容!

此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。