Skip to content

Commit

Permalink
mysql-compatibility: Improve MySQL Compatibility (#4024) (#4214)
Browse files Browse the repository at this point in the history
* cherry pick #4024 to release-4.0

Signed-off-by: ti-srebot <[email protected]>

* resolve conflict

Co-authored-by: TomShawn <[email protected]>
  • Loading branch information
ti-srebot and TomShawn authored Aug 7, 2020
1 parent 8886bdc commit 6973600
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 61 deletions.
98 changes: 37 additions & 61 deletions mysql-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ aliases: ['/docs-cn/stable/mysql-compatibility/','/docs-cn/v4.0/mysql-compatibil

- TiDB 100% 兼容 MySQL 5.7 协议、MySQL 5.7 常用的功能及语法。MySQL 5.7 生态中的系统工具(PHPMyAdmin、Navicat、MySQL Workbench、mysqldump、Mydumper/Myloader)、客户端等均用于 TiDB。

- 由于 TiDB 是一款分布式数据库,MySQL 5.7 中的部分特性因工程实现难度较大,投入产出比较低等多种原因在 TiDB 中未能实现或者仅兼容语法但功能并没有实现,因此使用过程中请特别注意。例如:`CREATE TABLE` 语句中 `ENGINE`,仅兼容语法,功能并没有实现,因此 TiDB 中没有 `ENGINE` 这类的概念。
- 但 TiDB 尚未支持一些 MySQL 功能,可能的原因如下:
- 有更好的解决方案,例如 JSON 取代 XML 函数。
- 目前对这些功能的需求度不高,例如存储流程和函数。
- 一些功能在分布式系统上的实现难度较大。

> **注意:**
>
Expand All @@ -20,8 +23,8 @@ aliases: ['/docs-cn/stable/mysql-compatibility/','/docs-cn/v4.0/mysql-compatibil
* 触发器
* 事件
* 自定义函数
* 外键约束
* 全文/空间函数与索引
* 外键约束 [#18209](https://github.com/pingcap/tidb/issues/18209)
* 全文/空间函数与索引 [#1793](https://github.com/pingcap/tidb/issues/1793)
*`ascii`/`latin1`/`binary`/`utf8`/`utf8mb4` 的字符集
* SYS schema
* MySQL 追踪优化器
Expand All @@ -34,6 +37,7 @@ aliases: ['/docs-cn/stable/mysql-compatibility/','/docs-cn/v4.0/mysql-compatibil
* `CREATE TEMPORARY TABLE` 语法
* `CHECK TABLE` 语法
* `CHECKSUM TABLE` 语法
* `GET_LOCK``RELEASE_LOCK` 函数 [#14994](https://github.com/pingcap/tidb/issues/14994)

## 与 MySQL 有差异的特性详细说明

Expand All @@ -48,7 +52,7 @@ aliases: ['/docs-cn/stable/mysql-compatibility/','/docs-cn/v4.0/mysql-compatibil
> **注意:**
>
> * `tidb_allow_remove_auto_inc` 要求版本号 >= v2.1.18 或者 >= v3.0.4。
> * 表的 `AUTO_ID_CACHE` 属性要求版本号 >= v3.0.14 或者 >= v3.1.2 或者 >= v4.0.rc-2。
> * 表的 `AUTO_ID_CACHE` 属性要求版本号 >= v3.0.14 或者 >= v3.1.2 或者 >= v4.0.0-rc.2。
> * 若创建表时没有指定主键时,TiDB 会使用 `_tidb_rowid` 来标识行,该数值的分配会和自增列(如果存在的话)共用一个分配器。如果指定了自增列为主键,则 TiDB 会用该列来标识行。因此会有以下的示例情况:
```sql
Expand All @@ -72,69 +76,43 @@ mysql> select _tidb_rowid, id from t;

### Performance schema

- TiDB 主要使用 Prometheus 和 Grafana 来存储及查询相关的性能监控指标,所以 Performance schema 部分表是空表。
TiDB 主要使用 Prometheus 和 Grafana 来存储及查询相关的性能监控指标,所以 Performance schema 部分表是空表。

### 查询计划

- `EXPLAIN`/`EXPLAIN FOR` 输出格式、内容、权限设置与 MySQL 有比较大的差别,参见[理解 TiDB 执行计划](/query-execution-plan.md)
`EXPLAIN`/`EXPLAIN FOR` 输出格式、内容、权限设置与 MySQL 有比较大的差别,参见[理解 TiDB 执行计划](/query-execution-plan.md)

### 内建函数

- 支持常用的 MySQL 内建函数,有部分函数并未支持参考 [SQL 语法文档](https://pingcap.github.io/sqlgram/#functioncallkeyword)
支持常用的 MySQL 内建函数,有部分函数并未支持。可通过执行 `SHOW BUILTINS` 语句查看可用的内建函数。参考 [SQL 语法文档](https://pingcap.github.io/sqlgram/#functioncallkeyword)

### DDL 的限制

- Add Index
+ 同一条 SQL 语句不支持创建多个索引。
+ 仅在语法在支持创建不同类型的索引 (HASH/BTREE/RTREE),功能未实现。

- Add Column
+ 不支持设置`PRIMARY KEY``UNIQUE KEY`,不支持设置 `AUTO_INCREMENT` 属性。可能输出的错误信息:`unsupported add column '%s' constraint PRIMARY/UNIQUE/AUTO_INCREMENT KEY`

- Drop Column
+ 不支持删除主键列及索引列,可能输出的错误信息:`Unsupported drop integer primary key/column a with index covered`

- Drop Primary Key
+ 仅支持删除建表时启用了 `alter-primary-key` 配置项的表的主键。可能输出的错误信息: `Unsupported drop primary key when alter-primary-key is false`

- Order By 忽略所有列排序相关的选项。

- Change/Modify Column
+ 不支持有损变更,比如从 `BIGINT` 变为 `INTEGER`,或者从 `VARCHAR(255)` 变为 `VARCHAR(10)`,可能输出的错误信息:`length %d is less than origin %d`
+ 不支持修改 `DECIMAL` 类型的精度,可能输出的错误信息:`can't change decimal column precision`
+ 不支持更改 `UNSIGNED` 属性,可能输出的错误信息:`can't change unsigned integer to signed or vice versa`
+ 只支持将 `CHARACTER SET` 属性从 `utf8` 更改为 `utf8mb4`

- `LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}`
+ 仅在语法上支持,功能未实现,故所有的 DDL 都不会锁表。

- `ALGORITHM [=] {DEFAULT|INSTANT|INPLACE|COPY}`
+ 支持 `ALGORITHM=INSTANT``ALGORITHM=INPLACE` 语法,但行为与 MySQL 有所不同,MySQL 中的一些 `INPLACE` 操作在 TiDB 中的 是`INSTANT` 操作。
+ 仅在语法上支持 `ALGORITHM=COPY`,功能未实现,会返回警告信息。

- 单条 `ALTER TABLE` 语句中无法完成多个操作。例如:不能用一条语句来添加多个列或多个索引。可能输出的错误信息:`Unsupported multi schema change`

- Table Option 仅支持`AUTO_INCREMENT``CHARACTER SET``COLLATE``COMMENT`,不支持以下语法:
+ `WITH/WITHOUT VALIDATION`
+ `SECONDARY_LOAD/SECONDARY_UNLOAD`
+ `CHECK/DROP CHECK`
+ `STATS_AUTO_RECALC/STATS_SAMPLE_PAGES`
+ `SECONDARY_ENGINE`
+ `ENCRYPTION`

- Table Partition 分区类型支持 Hash、Range;支持 Add/Drop/Truncate/Coalesce;忽略其他分区操作,可能错误信息:`Warning: Unsupported partition type, treat as normal table`,不支持以下语法:
TiDB 中,所有支持的 DDL 变更操作都是在线执行的。可能与 MySQL 不同的是,在 TiDB 中,`ALGORITHM=INSTANT``ALGORITHM=INPLACE` 这两种 MySQL DDL 算法可用于指定使用哪种算法来修改表。

与 MySQL 相比,TiDB 中的 DDL 存在以下限制:

* 不能在单条 `ALTER TABLE` 语句中完成多个操作。例如,不能在单个语句中添加多个列或索引,否则,可能会输出 `Unsupported multi schema change` 的错误。
* 不支持不同类型的索引 (`HASH|BTREE|RTREE|FULLTEXT`)。若指定了不同类型的索引,TiDB 会解析并忽略这些索引。
* 不支持添加/删除主键,除非开启了 [`alter-primary-key`](/tidb-configuration-file.md#alter-primary-key) 配置项。
* 更改/修改数据类型时,尚未支持“有损更改”,例如不支持从 BIGINT 更改为 INT。
* 更改/修改十进制列时,不支持更改预置。
* 更改/修改整数列时,不允许更改 `UNSIGNED` 属性。
* 分区表支持 Hash、Range 和 `Add`/`Drop`/`Truncate`/`Coalesce`。其他分区操作将被忽略,可能会报 `Warning: Unsupported partition type, treat as normal table` 错误。不支持以下分区表语法:
+ `PARTITION BY LIST`
+ `PARTITION BY KEY`
+ `SUBPARTITION`
+ `{CHECK|EXCHANGE|TRUNCATE|OPTIMIZE|REPAIR|IMPORT|DISCARD|REBUILD|REORGANIZE} PARTITION`

### `ANALYZE TABLE`

- [`ANALYZE TABLE`](/statistics.md#手动收集) 语句会完全重构表的统计数据,语句执行过程较长,但在 MySQL/InnoDB 中,它是一个轻量级语句,执行过程较短。
TiDB 中的[信息统计](/statistics.md#手动收集) 与 MySQL 中的有所不同:TiDB 中的信息统计会完全重构表的统计数据,语句执行过程较长,但在 MySQL/InnoDB 中,它是一个轻量级语句,执行过程较短。

更多信息统计的差异请参阅 [`ANALYZE TABLE`](/sql-statements/sql-statement-analyze-table.md)

### 视图

- 不支持 `UPDATE``INSERT``DELETE` 等写入操作。
TiDB 中的视图不可更新,不支持 `UPDATE``INSERT``DELETE` 等写入操作。

### 存储引擎

Expand All @@ -145,29 +123,27 @@ mysql> select _tidb_rowid, id from t;
TiDB 支持大部分 [SQL 模式](/sql-mode.md)。不支持的 SQL 模式如下:

- 不支持兼容模式,例如:`ORACLE``POSTGRESQL`(TiDB 解析但会忽略这两个兼容模式),MySQL 5.7 已弃用兼容模式,MySQL 8.0 已移除兼容模式。

- TiDB 的 `ONLY_FULL_GROUP_BY` 模式与 MySQL 5.7 相比有细微的[语义差别](/functions-and-operators/aggregate-group-by-functions.md#与-mysql-的区别)

- MySQL 中的 `NO_DIR_IN_CREATE``NO_ENGINE_SUBSTITUTION` 的 SQL 模式可用于解决兼容性问题,并不适用于 TiDB。
- `NO_DIR_IN_CREATE``NO_ENGINE_SUBSTITUTION` 仅用于解决与 MySQL 的兼容性问题,并不适用于 TiDB。

### 默认设置

- 字符集:
+ TiDB 默认:`utf8mb4`
+ MySQL 5.7 默认:`latin1`
+ MySQL 8.0 默认: `utf8mb4`
+ MySQL 8.0 默认:`utf8mb4`

- 排序规则:
+ TiDB 中 `utf8mb4` 字符集默认: `utf8mb4_bin`
+ MySQL 5.7 中 `utf8mb4` 字符集默认: `utf8mb4_general_ci`
+ MySQL 8.0 中 `utf8mb4` 字符集默认: `utf8mb4_0900_ai_ci`
+ TiDB 中 `utf8mb4` 字符集默认`utf8mb4_bin`
+ MySQL 5.7 中 `utf8mb4` 字符集默认`utf8mb4_general_ci`
+ MySQL 8.0 中 `utf8mb4` 字符集默认`utf8mb4_0900_ai_ci`

- `foreign_key_checks`
+ TiDB 默认: `OFF`,且仅支持设置该值为 `OFF`
+ MySQL 5.7 默认: `ON`
+ TiDB 默认`OFF`,且仅支持设置该值为 `OFF`
+ MySQL 5.7 默认:`ON`

- SQL mode:
+ TiDB 默认: `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`
+ TiDB 默认:`ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`
+ MySQL 5.7 默认 与 TiDB 相同。
+ MySQL 8.0 默认 `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION`

Expand All @@ -187,15 +163,15 @@ TiDB 支持大部分 [SQL 模式](/sql-mode.md)。不支持的 SQL 模式如下

#### 时区

- TiDB 采用系统当前安装的所有时区规则进行计算(一般为 `tzdata` 包), 不需要导入时区表数据就能使用所有时区名称,无法通过导入时区表数据的形式修改计算规则。
- TiDB 采用系统当前安装的所有时区规则进行计算(一般为 `tzdata` 包)不需要导入时区表数据就能使用所有时区名称,无法通过导入时区表数据的形式修改计算规则。

- MySQL 默认使用本地时区,依赖于系统内置的当前的时区规则(例如什么时候开始夏令时等)进行计算;且在未[导入时区表数据](https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html#time-zone-installation)的情况下不能通过时区名称来指定时区。

#### 零月和零日

- 与 MySQL 一样,TiDB 默认启用了 `NO_ZERO_DATE``NO_ZERO_IN_DATE` 模式,但是 TiDB 与 MySQL 在处理这两个 SQL 模式有以下不同:
- TiDB 在非严格模式下启用以上两个 SQL 模式,插入零月/零日/零日期不会给出警告,MySQL 则会给出对应的警告。
- TiDB 在严格模式下,启用了 `NO_ZERO_DATE` ,仍然能够插入零日期;如果启用了 `NO_ZERO_IN_DATE` 则无法插入零月/零日日期。MySQL 在严格模式下则都无法插入两种类型的日期。
- TiDB 在严格模式下,启用了 `NO_ZERO_DATE`,仍然能够插入零日期;如果启用了 `NO_ZERO_IN_DATE` 则无法插入零月/零日日期。MySQL 在严格模式下则都无法插入两种类型的日期。

### 类型系统

Expand All @@ -205,4 +181,4 @@ TiDB 支持大部分 [SQL 模式](/sql-mode.md)。不支持的 SQL 模式如下

+ 不支持 SERIAL (alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)。

+ 不支持 `SQL_TSI_*`(包括 SQL_TSI_YEARSQL_TSI_MONTHSQL_TSI_WEEKSQL_TSI_DAYSQL_TSI_HOURSQL_TSI_MINUTE 和 SQL_TSI_SECOND)。
+ 不支持 `SQL_TSI_*`(包括 `SQL_TSI_YEAR``SQL_TSI_MONTH``SQL_TSI_WEEK``SQL_TSI_DAY``SQL_TSI_HOUR``SQL_TSI_MINUTE``SQL_TSI_SECOND`)。
5 changes: 5 additions & 0 deletions sql-statements/sql-statement-analyze-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ EXPLAIN SELECT * FROM t1 WHERE c1 = 3;

* 在 MySQL 上不支持 `ANALYZE INCREMENTAL TABLE` 语句,它的使用可参考[增量收集文档](/statistics.md#增量收集)

TiDB 与 MySQL 在以下方面存在区别:所收集的统计信息,以及查询执行过程中统计信息是如何被使用的。虽然 TiDB 中的 `ANALYZE` 语句在语法上与 MySQL 类似,但存在以下差异:

+ 执行 `ANALYZE TABLE` 时,TiDB 可能不包含最近提交的更改。若对行进行了批量更改,在执行 `ANALYZE TABLE` 之前,你可能需要先执行 `sleep(1)`,这样统计信息更新才能反映这些更改。参见 [#16570](https://github.com/pingcap/tidb/issues/16570)
+ `ANALYZE TABLE` 在 TiDB 中的执行时间比在 MySQL 中的执行时间要长得多。但你可以通过执行 `SET GLOBAL tidb_enable_fast_analyze=1` 来启用快速分析,这样能部分抵消这种执行上的性能差异。快速分析利用了采样,会导致统计信息的准确性降低。因此快速分析仍是一项实验特性。

## 另请参阅

* [EXPLAIN](/sql-statements/sql-statement-explain.md)
Expand Down

0 comments on commit 6973600

Please sign in to comment.