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。
当指定的字符集为 utf8 或 utf8mb4 时,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_bin 和 utf8_general_bin 的 PADDING 行为,会将字符串补齐空格后比较;同时支持了 utf8mb4_general_ci 和 utf8_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)