ALTER TABLE
ALTER TABLE 语句用于对已有表进行修改,以符合新表结构。ALTER TABLE 语句可用于:
语法图
- AlterTableStmt
- TableName
- AlterTableSpec
- PlacementPolicyOption
示例
创建一张表,并插入初始数据:
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, c1 INT NOT NULL);
INSERT INTO t1 (c1) VALUES (1),(2),(3),(4),(5);Query OK, 0 rows affected (0.11 sec)
Query OK, 5 rows affected (0.03 sec)
Records: 5 Duplicates: 0 Warnings: 0执行以下查询需要扫描全表,因为 c1 列未被索引:
EXPLAIN SELECT * FROM t1 WHERE c1 = 3;+-------------------------+----------+-----------+---------------+--------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------+----------+-----------+---------------+--------------------------------+
| TableReader_7 | 10.00 | root | | data:Selection_6 |
| └─Selection_6 | 10.00 | cop[tikv] | | eq(test.t1.c1, 3) |
| └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t1 | keep order:false, stats:pseudo |
+-------------------------+----------+-----------+---------------+--------------------------------+
3 rows in set (0.00 sec)你可以使用 ALTER TABLE .. ADD INDEX 语句在 t1 表上添加索引。添加后,EXPLAIN 的分析结果显示 SELECT * FROM t1 WHERE c1 = 3; 查询已使用效率更高的索引范围扫描:
ALTER TABLE t1 ADD INDEX (c1);
EXPLAIN SELECT * FROM t1 WHERE c1 = 3;Query OK, 0 rows affected (0.30 sec)
+------------------------+---------+-----------+------------------------+---------------------------------------------+
| id | estRows | task | access object | operator info |
+------------------------+---------+-----------+------------------------+---------------------------------------------+
| IndexReader_6 | 10.00 | root | | index:IndexRangeScan_5 |
| └─IndexRangeScan_5 | 10.00 | cop[tikv] | table:t1, index:c1(c1) | range:[3,3], keep order:false, stats:pseudo |
+------------------------+---------+-----------+------------------------+---------------------------------------------+
2 rows in set (0.00 sec)TiDB 允许用户为 DDL 操作指定使用某一种 ALTER 算法。这仅为一种指定,并不改变实际的用于更改表的算法。如果你只想在群集的高峰时段允许即时 DDL 更改,则 ALTER 算法会很有用。示例如下:
ALTER TABLE t1 DROP INDEX c1, ALGORITHM=INSTANT;Query OK, 0 rows affected (0.24 sec)如果某一 DDL 操作要求使用 INPLACE 算法,而用户指定 ALGORITHM=INSTANT,会导致报错:
ALTER TABLE t1 ADD INDEX (c1), ALGORITHM=INSTANT;ERROR 1846 (0A000): ALGORITHM=INSTANT is not supported. Reason: Cannot alter table by INSTANT. Try ALGORITHM=INPLACE.但如果为 INPLACE 操作指定 ALGORITHM=COPY,会产生警告而非错误,这是因为 TiDB 将该指定解读为该算法或更好的算法。由于 TiDB 使用的算法可能不同于 MySQL,所以这一行为可用于 MySQL 兼容性。
ALTER TABLE t1 ADD INDEX (c1), ALGORITHM=COPY;
SHOW WARNINGS;Query OK, 0 rows affected, 1 warning (0.25 sec)
+-------+------+---------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------------------------------------------------+
| Error | 1846 | ALGORITHM=COPY is not supported. Reason: Cannot alter table by COPY. Try ALGORITHM=INPLACE. |
+-------+------+---------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)多操作 ALTER TABLE 的顺序语义
TiDB 支持在一条 ALTER TABLE 语句中修改一张表的多个模式对象(如列、索引和部分表属性)。当一条 ALTER TABLE 语句包含多个子操作时,TiDB 会按照 SQL 中从左到右的顺序进行语义检查和执行准备。后续子操作可以引用前序子操作刚刚创建、重命名或修改的列、索引及其他支持的模式对象。
例如,以下语句中第二个 ADD COLUMN 可以通过 AFTER c1 引用第一个 ADD COLUMN 新增的 c1 列:
CREATE TABLE t_multi (a INT);
ALTER TABLE t_multi ADD COLUMN c1 INT AFTER a, ADD COLUMN c2 INT AFTER c1;Query OK, 0 rows affected (0.15 sec)TiDB 也支持在同一条 ALTER TABLE 语句中替换非聚簇主键。例如:
CREATE TABLE t_pk (
old_part INT NOT NULL,
shared_id INT NOT NULL,
PRIMARY KEY (old_part, shared_id) NONCLUSTERED
);
ALTER TABLE t_pk DROP PRIMARY KEY, ADD PRIMARY KEY (shared_id) NONCLUSTERED;该操作会作为一个 multi-schema DDL 任务统一执行。若新增主键存在重复值或 DDL 执行失败,整条语句会失败并回滚,不会产生部分生效的中间表结构。
MySQL 兼容性
TiDB 中的 ALTER TABLE 语法主要存在以下限制:
- 使用
ALTER TABLE语句修改一个表的多个模式对象(如列、索引和部分表属性)时,TiDB 会按照 SQL 中从左到右的顺序处理,并基于前序子操作产生的临时表结构检查后续子操作。TiDB 不会自动重排用户书写的子操作顺序。如果书写顺序本身不满足依赖关系,语句会返回相应错误。 - TiDB 不保证支持所有 multi-action
ALTER TABLE子操作组合。涉及聚簇主键物理存储语义变更、不支持的列类型转换、复杂数据重组、分区表或全局索引等特殊对象的组合,仍可能返回不支持错误。 - 支持修改
NONCLUSTERED PRIMARY KEY成员列上 Reorg-Data 类型的变更。对于CLUSTERED PRIMARY KEY,如果列类型变更会影响 row handle、行键编码或数据物理组织,则仍不支持。 - 不支持分区表上的列类型变更。
- 不支持生成列上的列类型变更。
- 不支持部分数据类型(例如,部分时间类型、Bit、Set、Enum、JSON 等)的变更,因为 TiDB 中的
CAST函数与 MySQL 的行为存在兼容性问题。 - 不支持空间数据类型。
其它限制可参考:TiDB 中 DDL 语句与 MySQL 的兼容性情况。