PingKai Logo下载

ALTER TABLE

ALTER TABLE 语句用于对已有表进行修改,以符合新表结构。ALTER TABLE 语句可用于:

语法图

AlterTableStmt
ALTER IgnoreOptional TABLE TableName AlterTableSpecListOpt AlterTablePartitionOpt ANALYZE PARTITION PartitionNameList INDEX IndexNameList AnalyzeOptionListOpt COMPACT PARTITION PartitionNameList TIFLASH REPLICA
TableName
Identifier . Identifier
AlterTableSpec
TableOptionList SET TIFLASH REPLICA LengthNum LocationLabelList CONVERT TO CharsetKw CharsetName DEFAULT OptCollate ADD ColumnKeywordOpt IfNotExists ColumnDef ColumnPosition ( TableElementList ) Constraint PARTITION IfNotExists NoWriteToBinLogAliasOpt PartitionDefinitionListOpt PARTITIONS NUM CHECK TRUNCATE PARTITION OPTIMIZE REPAIR REBUILD PARTITION NoWriteToBinLogAliasOpt AllOrPartitionNameList COALESCE PARTITION NoWriteToBinLogAliasOpt NUM DROP ColumnKeywordOpt IfExists ColumnName RestrictOrCascadeOpt PRIMARY KEY PARTITION IfExists PartitionNameList KeyOrIndex IfExists CHECK Identifier FOREIGN KEY Symbol EXCHANGE PARTITION Identifier WITH TABLE TableName WithValidationOpt IMPORT DISCARD PARTITION AllOrPartitionNameList TABLESPACE REORGANIZE PARTITION NoWriteToBinLogAliasOpt ReorganizePartitionRuleOpt ORDER BY AlterOrderItem , DISABLE ENABLE KEYS MODIFY ColumnKeywordOpt IfExists CHANGE ColumnKeywordOpt IfExists ColumnName ColumnDef ColumnPosition ALTER ColumnKeywordOpt ColumnName SET DEFAULT SignedLiteral ( Expression ) DROP DEFAULT CHECK Identifier EnforcedOrNot INDEX Identifier VISIBLE INVISIBLE RENAME COLUMN KeyOrIndex Identifier TO Identifier TO = AS TableName LockClause AlgorithmClause FORCE WITH WITHOUT VALIDATION SECONDARY_LOAD SECONDARY_UNLOAD AUTO_INCREMENT AUTO_ID_CACHE AUTO_RANDOM_BASE SHARD_ROW_ID_BITS EqOpt LengthNum CACHE NOCACHE TTL EqOpt TimeColumnName + INTERVAL Expression TimeUnit TTLEnable EqOpt ON OFF REMOVE TTL TTLEnable EqOpt ON OFF TTLJobInterval EqOpt stringLit PlacementPolicyOption
PlacementPolicyOption
PLACEMENT POLICY EqOpt PolicyName PLACEMENT POLICY EqOpt SET DEFAULT

示例

创建一张表,并插入初始数据:

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 的兼容性情况

另请参阅