文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  ALTER TABLE 语句

15.1.9 ALTER TABLE 语句

ALTER TABLE tbl_name
    [alter_option [, alter_option] ...]
    [partition_options]

alter_option: {
    table_options
  | ADD [COLUMN] col_name column_definition
        [FIRST | AFTER col_name]
  | ADD [COLUMN] (col_name column_definition,...)
  | ADD {INDEX | KEY} [index_name]
        [index_type] (key_part,...) [index_option] ...
  | ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name]
        (key_part,...) [index_option] ...
  | ADD [CONSTRAINT [symbol]] PRIMARY KEY
        [index_type] (key_part,...)
        [index_option] ...
  | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
        [index_name] [index_type] (key_part,...)
        [index_option] ...
  | ADD [CONSTRAINT [symbol]] FOREIGN KEY
        [index_name] (col_name,...)
        reference_definition
  | ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
  | DROP {CHECK | CONSTRAINT} symbol
  | ALTER {CHECK | CONSTRAINT} symbol [NOT] ENFORCED
  | ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY}
  | ALTER [COLUMN] col_name {
        SET DEFAULT {literal | (expr)}
      | SET {VISIBLE | INVISIBLE}
      | DROP DEFAULT
    }
  | ALTER INDEX index_name {VISIBLE | INVISIBLE}
  | CHANGE [COLUMN] old_col_name new_col_name column_definition
        [FIRST | AFTER col_name]
  | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
  | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
  | {DISABLE | ENABLE} KEYS
  | {DISCARD | IMPORT} TABLESPACE
  | DROP [COLUMN] col_name
  | DROP {INDEX | KEY} index_name
  | DROP PRIMARY KEY
  | DROP FOREIGN KEY fk_symbol
  | FORCE
  | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
  | MODIFY [COLUMN] col_name column_definition
        [FIRST | AFTER col_name]
  | ORDER BY col_name [, col_name] ...
  | RENAME COLUMN old_col_name TO new_col_name
  | RENAME {INDEX | KEY} old_index_name TO new_index_name
  | RENAME [TO | AS] new_tbl_name
  | {WITHOUT | WITH} VALIDATION
}

partition_options:
    partition_option [partition_option] ...

partition_option: {
    ADD PARTITION (partition_definition)
  | DROP PARTITION partition_names
  | DISCARD PARTITION {partition_names | ALL} TABLESPACE
  | IMPORT PARTITION {partition_names | ALL} TABLESPACE
  | TRUNCATE PARTITION {partition_names | ALL}
  | COALESCE PARTITION number
  | REORGANIZE PARTITION partition_names INTO (partition_definitions)
  | EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH | WITHOUT} VALIDATION]
  | ANALYZE PARTITION {partition_names | ALL}
  | CHECK PARTITION {partition_names | ALL}
  | OPTIMIZE PARTITION {partition_names | ALL}
  | REBUILD PARTITION {partition_names | ALL}
  | REPAIR PARTITION {partition_names | ALL}
  | REMOVE PARTITIONING
}

key_part: {col_name [(length)] | (expr)} [ASC | DESC]

index_type:
    USING {BTREE | HASH}

index_option: {
    KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'
  | {VISIBLE | INVISIBLE}
}

table_options:
    table_option [[,] table_option] ...

table_option: {
    AUTOEXTEND_SIZE [=] value
  | AUTO_INCREMENT [=] value
  | AVG_ROW_LENGTH [=] value
  | [DEFAULT] CHARACTER SET [=] charset_name
  | CHECKSUM [=] {0 | 1}
  | [DEFAULT] COLLATE [=] collation_name
  | COMMENT [=] 'string'
  | COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'}
  | CONNECTION [=] 'connect_string'
  | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory'
  | DELAY_KEY_WRITE [=] {0 | 1}
  | ENCRYPTION [=] {'Y' | 'N'}
  | ENGINE [=] engine_name
  | ENGINE_ATTRIBUTE [=] 'string'
  | INSERT_METHOD [=] { NO | FIRST | LAST }
  | KEY_BLOCK_SIZE [=] value
  | MAX_ROWS [=] value
  | MIN_ROWS [=] value
  | PACK_KEYS [=] {0 | 1 | DEFAULT}
  | PASSWORD [=] 'string'
  | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
  | SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
  | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
  | STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
  | STATS_SAMPLE_PAGES [=] value
  | TABLESPACE tablespace_name [STORAGE {DISK | MEMORY}]
  | UNION [=] (tbl_name[,tbl_name]...)
}

partition_options:
    (see CREATE TABLE options)

ALTER TABLE 用于更改表的结构。例如,您可以添加或删除列、创建或删除索引、更改现有列的类型或重命名列或表本身。您还可以更改表的特征,例如用于表的存储引擎或表注释。

  • 要使用 ALTER TABLE,您需要对该表拥有 ALTERCREATEINSERT 权限。重命名表需要对旧表拥有 ALTERDROP 权限,对新表拥有 ALTERCREATEINSERT 权限。

  • 在表名之后,指定要进行的更改。如果未指定任何更改,则 ALTER TABLE 不执行任何操作。

  • 许多允许修改的语法类似于 CREATE TABLE 语句的子句。column_definition 子句对 ADDCHANGE 使用与 CREATE TABLE 相同的语法。有关更多信息,请参阅 第 15.1.20 节 “CREATE TABLE 语句”

  • 单词 COLUMN 是可选的,可以省略,但 RENAME COLUMN 除外(用于区分列重命名操作和 RENAME 表重命名操作)。

  • 单个 ALTER TABLE 语句中允许使用多个 ADDALTERDROPCHANGE 子句,用逗号分隔。这是对标准 SQL 的 MySQL 扩展,标准 SQL 每个 ALTER TABLE 语句只允许使用其中一个子句。例如,要在一个语句中删除多个列,请执行以下操作

    ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
  • 如果存储引擎不支持尝试的 ALTER TABLE 操作,则可能会导致警告。可以使用 SHOW WARNINGS 显示此类警告。请参阅 第 15.7.7.41 节 “SHOW WARNINGS 语句”。有关 ALTER TABLE 故障排除的信息,请参阅 第 B.3.6.1 节 “ALTER TABLE 问题”

  • 有关生成列的信息,请参阅 第 15.1.9.2 节 “ALTER TABLE 和生成列”

  • 有关使用示例,请参阅 第 15.1.9.3 节 “ALTER TABLE 示例”

  • InnoDB 支持使用 key_part 规范在 JSON 列上添加多值索引,该规范可以采用 (CAST json_path AS type ARRAY) 形式。有关多值索引创建和使用以及多值索引的限制的详细信息,请参阅 多值索引

  • 使用 mysql_info() C API 函数,您可以找出 ALTER TABLE 复制了多少行。请参阅 mysql_info()

ALTER TABLE 语句还有其他几个方面,将在本节的以下主题中进行介绍

表选项

table_options 表示可以在 CREATE TABLE 语句中使用的表选项,例如 ENGINEAUTO_INCREMENTAVG_ROW_LENGTHMAX_ROWSROW_FORMATTABLESPACE

有关所有表选项的说明,请参阅 第 15.1.20 节 “CREATE TABLE 语句”。但是,当 DATA DIRECTORYINDEX DIRECTORY 作为表选项给出时,ALTER TABLE 会忽略它们。ALTER TABLE 仅允许将它们作为分区选项,并且要求您具有 FILE 权限。

将表选项与 ALTER TABLE 一起使用提供了一种更改单个表特征的便捷方法。例如

  • 如果 t1 当前不是 InnoDB 表,则此语句会将其存储引擎更改为 InnoDB

    ALTER TABLE t1 ENGINE = InnoDB;
  • 要更改 InnoDB 表以使用压缩行存储格式

    ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
  • ENCRYPTION 子句启用或禁用 InnoDB 表的页面级数据加密。必须安装和配置密钥环插件才能启用加密。

    如果启用了 table_encryption_privilege_check 变量,则需要 TABLE_ENCRYPTION_ADMIN 权限才能使用设置与默认架构加密设置不同的 ENCRYPTION 子句。

    还支持对驻留在通用表空间中的表进行 ENCRYPTION

    对于驻留在通用表空间中的表,表和表空间加密必须匹配。

    不允许通过将表移动到不同的表空间或更改存储引擎来更改表加密,而无需显式指定 ENCRYPTION 子句。

    如果表使用不支持加密的存储引擎,则不允许指定值为 'N''' 以外的 ENCRYPTION 子句。也不允许尝试在启用了加密的架构中使用不支持加密的存储引擎创建没有 ENCRYPTION 子句的表。

    有关更多信息,请参阅 第 17.13 节 “InnoDB 静态数据加密”

  • 要重置当前的自动增量值

    ALTER TABLE t1 AUTO_INCREMENT = 13;

    您不能将计数器重置为小于或等于当前使用的值的值。对于 InnoDBMyISAM,如果该值小于或等于 AUTO_INCREMENT 列中的当前最大值,则该值将重置为当前最大 AUTO_INCREMENT 列值加一。

  • 要更改默认表字符集

    ALTER TABLE t1 CHARACTER SET = utf8mb4;

    另请参阅 更改字符集

  • 要添加(或更改)表注释

    ALTER TABLE t1 COMMENT = 'New table comment';
  • ALTER TABLETABLESPACE 选项一起使用,以在现有的 通用表空间每个表一个文件 表空间和 系统表空间 之间移动 InnoDB 表。请参阅 使用 ALTER TABLE 在表空间之间移动表

    • ALTER TABLE ... TABLESPACE 操作始终会导致完全重建表,即使 TABLESPACE 属性与其先前值没有改变也是如此。

    • ALTER TABLE ... TABLESPACE 语法不支持将表从临时表空间移动到持久表空间。

    • CREATE TABLE ... TABLESPACE 支持的 DATA DIRECTORY 子句在 ALTER TABLE ... TABLESPACE 中不受支持,如果指定,将被忽略。

    • 有关 TABLESPACE 选项的功能和限制的更多信息,请参阅 CREATE TABLE

  • MySQL NDB Cluster 9.0 支持设置 NDB_TABLE 选项,用于控制表的 partitions balance(碎片计数类型)、read-from-any-replica 功能、完全复制或这些的任意组合,作为 ALTER TABLE 语句的表注释的一部分,方式与 CREATE TABLE 相同,如本例所示

    ALTER TABLE t1 COMMENT = "NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";

    还可以像下面这样,将 NDB_COMMENT 选项设置为 NDB 表的列的一部分,作为 ALTER TABLE 语句的一部分

    ALTER TABLE t1 
      CHANGE COLUMN c1 c1 BLOB 
        COMMENT = 'NDB_COLUMN=BLOB_INLINE_SIZE=4096,MAX_BLOB_PART_SIZE';

    请记住,ALTER TABLE ... COMMENT ... 会丢弃该表的任何现有注释。有关其他信息和示例,请参阅 设置 NDB_TABLE 选项

  • ENGINE_ATTRIBUTESECONDARY_ENGINE_ATTRIBUTE 选项用于为主存储引擎和辅助存储引擎指定表、列和索引属性。这些选项保留供将来使用。索引属性无法更改。必须删除索引并使用所需的更改重新添加,这可以在单个 ALTER TABLE 语句中执行。

要验证表选项是否按预期更改,请使用 SHOW CREATE TABLE 或查询 Information Schema TABLES 表。

性能和空间要求

ALTER TABLE 操作使用以下算法之一进行处理

  • COPY:操作是在原始表的副本上执行的,表数据从原始表逐行复制到新表。不允许并发 DML。

  • INPLACE:操作避免复制表数据,但可能会就地重建表。在操作的准备和执行阶段,可能会短暂获取表的独占元数据锁。通常,支持并发 DML。

  • INSTANT:操作仅修改数据字典中的元数据。在操作的执行阶段,可能会短暂获取表的独占元数据锁。表数据不受影响,因此操作是即时的。允许并发 DML。

对于使用 NDB 存储引擎的表,这些算法的工作原理如下

  • COPYNDB 创建表的副本并对其进行更改;然后,NDB Cluster 处理程序在表的旧版本和新版本之间复制数据。随后,NDB 删除旧表并将新表重命名。

    这有时也称为 复制离线 ALTER TABLE

  • INPLACE:数据节点进行所需的更改;NDB Cluster 处理程序不复制数据或以其他方式参与。

    这有时也称为 非复制在线 ALTER TABLE

  • INSTANTNDB 不支持。

有关更多信息,请参见 第 25.6.12 节,“使用 NDB Cluster 中的 ALTER TABLE 进行在线操作”

ALGORITHM 子句是可选的。如果省略 ALGORITHM 子句,则 MySQL 会对支持它的存储引擎和 ALTER TABLE 子句使用 ALGORITHM=INSTANT。否则,将使用 ALGORITHM=INPLACE。如果不支持 ALGORITHM=INPLACE,则使用 ALGORITHM=COPY

注意

使用 ALGORITHM=INSTANT 向分区表添加列后,将无法再对该表执行 ALTER TABLE ... EXCHANGE PARTITION

指定 ALGORITHM 子句要求操作对支持它的子句和存储引擎使用指定的算法,否则将失败并返回错误。指定 ALGORITHM=DEFAULT 与省略 ALGORITHM 子句相同。

使用 COPY 算法的 ALTER TABLE 操作将等待修改表的其他操作完成后再进行。将更改应用于表副本后,将复制数据,删除原始表,并将表副本重命名为原始表的名称。在 ALTER TABLE 操作执行期间,其他会话可以读取原始表(稍后提到的例外情况除外)。在 ALTER TABLE 操作开始后启动的对表的更新和写入将暂停,直到新表准备就绪,然后自动重定向到新表。表的临时副本将在原始表的数据库目录中创建,除非它是将表移动到位于不同目录中的数据库的 RENAME TO 操作。

前面提到的例外情况是,ALTER TABLE 在准备从表和表定义缓存中清除过时的表结构时会阻止读取(而不仅仅是写入)。此时,它必须获取独占锁。为此,它会等待当前读取器完成,并阻止新的读取和写入。

使用 COPY 算法的 ALTER TABLE 操作会阻止并发 DML 操作。仍然允许并发查询。也就是说,复制表操作始终至少包含 LOCK=SHARED 的并发限制(允许查询但不允许 DML)。您可以通过指定 LOCK=EXCLUSIVE 来进一步限制支持 LOCK 子句的操作的并发性,这将阻止 DML 和查询。有关更多信息,请参见 并发控制

要强制对原本不使用 COPY 算法的 ALTER TABLE 操作使用该算法,请指定 ALGORITHM=COPY 或启用 old_alter_table 系统变量。如果 old_alter_table 设置与值为 DEFAULT 以外的值的 ALGORITHM 子句之间存在冲突,则 ALGORITHM 子句优先。

对于 InnoDB 表,对驻留在 共享表空间 中的表使用 COPY 算法的 ALTER TABLE 操作可能会增加表空间使用的空间量。此类操作需要与表中的数据加索引一样多的额外空间。对于驻留在共享表空间中的表,操作期间使用的额外空间不会像驻留在 每个表一个文件 表空间中的表那样释放回操作系统。

有关在线 DDL 操作的空间要求的信息,请参见 第 17.12.3 节,“在线 DDL 空间要求”

支持 INPLACE 算法的 ALTER TABLE 操作包括

  • InnoDB 在线 DDL 功能支持的 ALTER TABLE 操作。请参见 第 17.12.1 节,“在线 DDL 操作”

  • 重命名表。MySQL 会重命名与表 tbl_name 对应的文件,而无需进行复制。(您也可以使用 RENAME TABLE 语句来重命名表。请参见 第 15.1.36 节,“RENAME TABLE 语句”。)专门为重命名的表授予的权限不会迁移到新名称。必须手动更改它们。

  • 仅修改表元数据的操作。这些操作是立即执行的,因为服务器不会触碰表内容。仅限元数据的操作包括

    • 重命名列。在 NDB Cluster 中,此操作也可以在线执行。

    • 更改列的默认值(NDB 表除外)。

    • 通过将新的枚举或集合成员添加到有效成员值列表的末尾来修改 ENUMSET 列的定义,只要数据类型的存储大小没有改变。例如,将成员添加到具有 8 个成员的 SET 列会将每个值所需的存储空间从 1 字节更改为 2 字节;这需要复制表。在列表中间添加成员会导致对现有成员重新编号,这需要复制表。

    • 更改空间列的定义以删除 SRID 属性。(添加或更改 SRID 属性需要重建,并且无法就地完成,因为服务器必须验证所有值是否都具有指定的 SRID 值。)

    • 在满足以下条件时更改列字符集

      • 列数据类型为 CHARVARCHARTEXT 类型或 ENUM

      • 字符集更改是从 utf8mb3utf8mb4,或从任何字符集到 binary

      • 该列上没有索引。

    • 在满足以下条件时更改生成的列

      • 对于 InnoDB 表,修改生成的存储列但不更改其类型、表达式或可为空性的语句。

      • 对于非 InnoDB 表,修改生成的存储列或虚拟列但不更改其类型、表达式或可为空性的语句。

      此类更改的一个示例是对列注释的更改。

  • 重命名索引。

  • 对于 InnoDBNDB 表,添加或删除辅助索引。请参见 第 17.12.1 节,“在线 DDL 操作”

  • 对于 NDB 表,在可变宽度列上添加和删除索引的操作。这些操作在线执行,无需复制表,并且在其大部分持续时间内不会阻塞并发 DML 操作。请参见 第 25.6.12 节,“使用 NDB Cluster 中的 ALTER TABLE 进行在线操作”

  • 使用 ALTER INDEX 操作修改索引可见性。

  • 如果修改后的列未包含在生成的列表达式中,则对包含依赖于具有 DEFAULT 值的列的生成的列的表进行列修改。例如,可以就地更改单独列的 NULL 属性,而无需重建表。

支持 INSTANT 算法的 ALTER TABLE 操作包括

  • 添加列。此功能称为 即时 ADD COLUMN。有限制条件。请参见 第 17.12.1 节,“在线 DDL 操作”

  • 删除列。此功能称为 即时 DROP COLUMN。有限制条件。请参见 第 17.12.1 节,“在线 DDL 操作”

  • 添加或删除虚拟列。

  • 添加或删除列默认值。

  • 修改 ENUMSET 列的定义。适用与上述 ALGORITHM=INSTANT 相同的限制。

  • 更改索引类型。

  • 重命名表。适用与上述 ALGORITHM=INSTANT 相同的限制。

有关支持 ALGORITHM=INSTANT 的操作的更多信息,请参见 第 17.12.1 节,“在线 DDL 操作”

对于 ADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEXFORCE 操作,ALTER TABLE 会将 MySQL 5.5 时间类型列升级为 5.6 格式。此转换无法使用 INPLACE 算法完成,因为必须重建表,因此在这些情况下指定 ALGORITHM=INPLACE 会导致错误。如有必要,请指定 ALGORITHM=COPY

如果对使用 KEY 对表进行分区的多分支索引的 ALTER TABLE 操作更改了列的顺序,则只能使用 ALGORITHM=COPY 执行。

WITHOUT VALIDATIONWITH VALIDATION 子句会影响 ALTER TABLE 是否对 虚拟生成列 修改执行就地操作。请参阅 第 15.1.9.2 节,“ALTER TABLE 和生成列”

NDB Cluster 9.0 支持使用与标准 MySQL Server 相同的 ALGORITHM=INPLACE 语法进行在线操作。NDB 不允许在线更改表空间。有关更多信息,请参阅 第 25.6.12 节,“在 NDB Cluster 中使用 ALTER TABLE 进行在线操作”

执行复制 ALTER TABLE 时,NDB 会检查以确保没有对受影响的表进行并发写入。如果发现有任何写入,NDB 将拒绝 ALTER TABLE 语句并引发 ER_TABLE_DEF_CHANGED

带有 DISCARD ... PARTITION ... TABLESPACEIMPORT ... PARTITION ... TABLESPACEALTER TABLE 不会创建任何临时表或临时分区文件。

带有 ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREBUILD PARTITIONREORGANIZE PARTITIONALTER TABLE 不会创建临时表(与 NDB 表一起使用时除外);但是,这些操作可以并且确实会创建临时分区文件。

RANGELIST 分区的 ADDDROP 操作是立即操作或几乎是立即操作。HASHKEY 分区的 ADDCOALESCE 操作会在所有分区之间复制数据,除非使用了 LINEAR HASHLINEAR KEY;这实际上与创建新表相同,尽管 ADDCOALESCE 操作是按分区执行的。REORGANIZE 操作仅复制已更改的分区,而不触及未更改的分区。

对于 MyISAM 表,您可以通过将 myisam_sort_buffer_size 系统变量设置为较高的值来加快索引重建速度(更改过程中最慢的部分)。

并发控制

对于支持它的 ALTER TABLE 操作,您可以使用 LOCK 子句来控制表在更改时并发读取和写入的级别。为该子句指定非默认值使您能够在更改操作期间要求一定程度的并发访问或独占访问,并在无法获得请求的锁定程度时停止操作。

对于使用 ALGORITHM=INSTANT 的操作,仅允许使用 LOCK = DEFAULT。其他 LOCK 子句参数不适用。

LOCK 子句的参数为:

  • LOCK = DEFAULT

    给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的最大并发级别:如果支持,则允许并发读取和写入。如果不支持,则允许并发读取(如果支持)。如果不支持,则强制执行独占访问。

  • LOCK = NONE

    如果支持,则允许并发读取和写入。否则,会发生错误。

  • LOCK = SHARED

    如果支持,则允许并发读取但阻止写入。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发写入,也会阻止写入。如果不支持并发读取,则会发生错误。

  • LOCK = EXCLUSIVE

    强制执行独占访问。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发读/写,也会执行此操作。

添加和删除列

使用 ADD 向表中添加新列,使用 DROP 删除现有列。DROP col_name 是 MySQL 对标准 SQL 的扩展。

要在表行的特定位置添加列,请使用 FIRSTAFTER col_name。默认情况下,列添加在最后。

如果表只包含一列,则不能删除该列。如果您打算删除表,请改用 DROP TABLE 语句。

如果从表中删除了列,则这些列也会从它们所属的任何索引中删除。如果删除了构成索引的所有列,则索引也会被删除。如果使用 CHANGEMODIFY 缩短存在索引的列,并且结果列长度小于索引长度,则 MySQL 会自动缩短索引。

对于 ALTER TABLE ... ADD,如果该列的表达式默认值使用非确定性函数,则该语句可能会产生警告或错误。有关更多信息,请参阅 第 13.6 节,“数据类型默认值”第 19.1.3.7 节,“使用 GTID 进行复制的限制”

重命名、重新定义和重新排序列

CHANGEMODIFYRENAME COLUMNALTER 子句允许更改现有列的名称和定义。它们具有以下比较特征:

  • CHANGE:

    • 可以重命名列并更改其定义,或同时执行这两项操作。

    • MODIFYRENAME COLUMN 相比,它具有更多功能,但以牺牲某些操作的便利性为代价。如果未重命名列,则 CHANGE 需要命名该列两次,如果仅重命名该列,则需要重新指定该列的定义。

    • 使用 FIRSTAFTER 可以对列重新排序。

  • MODIFY:

    • 可以更改列定义,但不能更改其名称。

    • CHANGE 相比,在不重命名的情况下更改列定义更方便。

    • 使用 FIRSTAFTER 可以对列重新排序。

  • RENAME COLUMN:

    • 可以更改列名称,但不能更改其定义。

    • CHANGE 相比,在不更改其定义的情况下重命名列更方便。

  • ALTER:仅用于更改列默认值。

CHANGE 是 MySQL 对标准 SQL 的扩展。MODIFYRENAME COLUMN 是 MySQL 为兼容 Oracle 而提供的扩展。

要更改列以更改其名称和定义,请使用 CHANGE,并指定旧名称和新名称以及新定义。例如,要将 INT NOT NULL 列从 a 重命名为 b 并将其定义更改为使用 BIGINT 数据类型,同时保留 NOT NULL 属性,请执行以下操作:

ALTER TABLE t1 CHANGE a b BIGINT NOT NULL;

要更改列定义但不更改其名称,请使用 CHANGEMODIFY。使用 CHANGE 时,语法需要两个列名,因此您必须指定两次相同的名称才能保持名称不变。例如,要更改列 b 的定义,请执行以下操作:

ALTER TABLE t1 CHANGE b b INT NOT NULL;

MODIFY 更方便在不更改名称的情况下更改定义,因为它只需要列名一次:

ALTER TABLE t1 MODIFY b INT NOT NULL;

要更改列名但不更改其定义,请使用 CHANGERENAME COLUMN。使用 CHANGE 时,语法需要列定义,因此要保持定义不变,您必须重新指定该列当前的定义。例如,要将 INT NOT NULL 列从 b 重命名为 a,请执行以下操作:

ALTER TABLE t1 CHANGE b a INT NOT NULL;

RENAME COLUMN 更方便在不更改定义的情况下更改名称,因为它只需要旧名称和新名称:

ALTER TABLE t1 RENAME COLUMN b TO a;

通常,您不能将列重命名为表中已存在的名称。但是,有时情况并非如此,例如,当您交换名称或通过循环移动它们时。如果表中有名为 abc 的列,则以下操作是有效的:

-- swap a and b
ALTER TABLE t1 RENAME COLUMN a TO b,
               RENAME COLUMN b TO a;
-- "rotate" a, b, c through a cycle
ALTER TABLE t1 RENAME COLUMN a TO b,
               RENAME COLUMN b TO c,
               RENAME COLUMN c TO a;

对于使用 CHANGEMODIFY 进行的列定义更改,定义必须包含数据类型和应应用于新列的所有属性,但索引属性(例如 PRIMARY KEYUNIQUE)除外。原始定义中存在但未为新定义指定的属性不会被保留。假设列 col1 定义为 INT UNSIGNED DEFAULT 1 COMMENT 'my column',并且您按如下方式修改该列,打算仅将 INT 更改为 BIGINT

ALTER TABLE t1 MODIFY col1 BIGINT;

该语句会将数据类型从 INT 更改为 BIGINT,但也会删除 UNSIGNEDDEFAULTCOMMENT 属性。要保留它们,语句必须显式包含它们:

ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';

对于使用 CHANGEMODIFY 进行的数据类型更改,MySQL 会尝试尽可能将现有列值转换为新类型。

警告

此转换可能会导致数据更改。例如,如果缩短字符串列,则值可能会被截断。为防止在转换为新数据类型会导致数据丢失时操作成功,请在使用 ALTER TABLE 之前启用严格 SQL 模式(请参阅 第 7.1.11 节,“服务器 SQL 模式”)。

如果使用 CHANGEMODIFY 缩短存在索引的列,并且结果列长度小于索引长度,则 MySQL 会自动缩短索引。

对于由 CHANGERENAME COLUMN 重命名的列,MySQL 会自动将对重命名列的以下引用重命名:

  • 引用旧列的索引,包括不可见索引和已禁用的 MyISAM 索引。

  • 引用旧列的外键。

对于由 CHANGERENAME COLUMN 重命名的列,MySQL 不会自动将对重命名列的以下引用重命名:

  • 引用重命名列的生成列和分区表达式。您必须使用 CHANGE 在与重命名该列相同的 ALTER TABLE 语句中重新定义此类表达式。

  • 引用重命名列的视图和存储程序。您必须手动更改这些对象的定义以引用新的列名。

要对表中的列重新排序,请在 CHANGEMODIFY 操作中使用 FIRSTAFTER

ALTER ... SET DEFAULTALTER ... DROP DEFAULT 分别为列指定新的默认值或删除旧的默认值。如果删除了旧的默认值并且该列可以是 NULL,则新的默认值为 NULL。如果该列不能为空,则 MySQL 将按第 13.6 节“数据类型默认值” 中的描述分配默认值。

ALTER ... SET VISIBLEALTER ... SET INVISIBLE 启用列可见性的更改。请参阅第 15.1.20.10 节“不可见列”

主键和索引

DROP PRIMARY KEY 删除主键。如果没有主键,则会发生错误。有关主键性能特征的信息,特别是对于 InnoDB 表,请参阅第 10.3.2 节“主键优化”

如果启用了 sql_require_primary_key 系统变量,则尝试删除主键会产生错误。

如果将 UNIQUE INDEXPRIMARY KEY 添加到表中,MySQL 会将其存储在任何非唯一索引之前,以便尽早检测重复键。

DROP INDEX 删除索引。这是 MySQL 对标准 SQL 的扩展。请参阅第 15.1.27 节“DROP INDEX 语句”。要确定索引名称,请使用 SHOW INDEX FROM tbl_name

某些存储引擎允许您在创建索引时指定索引类型。 index_type 说明符的语法为 USING type_name。有关 USING 的详细信息,请参阅第 15.1.15 节“CREATE INDEX 语句”。首选位置是在列列表之后。预计在未来版本的 MySQL 中将删除对在列列表之前使用该选项的支持。

index_option 值指定索引的其他选项。 USING 就是这样的一个选项。有关允许的 index_option 值的详细信息,请参阅第 15.1.15 节“CREATE INDEX 语句”

RENAME INDEX old_index_name TO new_index_name 重命名索引。这是 MySQL 对标准 SQL 的扩展。表的内容保持不变。 old_index_name 必须是表中现有索引的名称,该索引不会被同一个 ALTER TABLE 语句删除。 new_index_name 是新的索引名称,它不能与应用更改后生成的表中的索引名称重复。两个索引名称都不能是 PRIMARY

如果在 MyISAM 表上使用 ALTER TABLE,则所有非唯一索引都会在一个单独的批处理中创建(就像 REPAIR TABLE 一样)。当您有很多索引时,这应该会使 ALTER TABLE 快得多。

对于 MyISAM 表,可以显式控制键更新。使用 ALTER TABLE ... DISABLE KEYS 告诉 MySQL 停止更新非唯一索引。然后使用 ALTER TABLE ... ENABLE KEYS 重新创建丢失的索引。 MyISAM 使用一种特殊的算法来实现这一点,该算法比逐个插入键快得多,因此在执行批量插入操作之前禁用键应该会显著提高速度。使用 ALTER TABLE ... DISABLE KEYS 需要 INDEX 权限以及前面提到的权限。

当非唯一索引被禁用时,诸如 SELECTEXPLAIN 之类的语句会忽略它们,否则将使用它们。

ALTER TABLE 语句之后,可能需要运行 ANALYZE TABLE 来更新索引基数信息。请参阅第 15.7.7.23 节“SHOW INDEX 语句”

ALTER INDEX 操作允许索引变为可见或不可见。优化器不使用不可见索引。索引可见性的修改适用于除主键(显式或隐式)以外的索引,并且不能使用 ALGORITHM=INSTANT 执行。此功能是存储引擎中立的(任何引擎都支持)。有关更多信息,请参阅第 10.3.12 节“不可见索引”

外键和其他约束

FOREIGN KEYREFERENCES 子句由 InnoDBNDB 存储引擎支持,它们实现 ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (...) REFERENCES ... (...)。请参阅第 15.1.20.5 节“FOREIGN KEY 约束”。对于其他存储引擎,将解析这些子句但会被忽略。

对于 ALTER TABLE,与 CREATE TABLE 不同,如果给定 index_nameADD FOREIGN KEY 会忽略它,并使用自动生成的外键名称。作为解决方法,请包含 CONSTRAINT 子句以指定外键名称

ADD CONSTRAINT name FOREIGN KEY (....) ...
重要

MySQL 会默默地忽略内联 REFERENCES 规范,其中引用被定义为列规范的一部分。MySQL 只接受定义为单独的 FOREIGN KEY 规范一部分的 REFERENCES 子句。

注意

分区 InnoDB 表不支持外键。此限制不适用于 NDB 表,包括由 [LINEAR] KEY 显式分区的表。有关更多信息,请参阅第 26.6.2 节“与存储引擎相关的分区限制”

MySQL 服务器和 NDB 集群都支持使用 ALTER TABLE 删除外键

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

在同一个 ALTER TABLE 语句中添加和删除外键对于 ALTER TABLE ... ALGORITHM=INPLACE 受支持,但对于 ALTER TABLE ... ALGORITHM=COPY 不受支持。

服务器禁止对外键列进行更改,因为这可能会导致引用完整性丢失。解决方法是在更改列定义之前使用 ALTER TABLE ... DROP FOREIGN KEY,并在更改之后使用 ALTER TABLE ... ADD FOREIGN KEY。禁止更改的示例包括

  • 对可能不安全的外键列的数据类型进行更改。例如,允许将 VARCHAR(20) 更改为 VARCHAR(30),但不允许将其更改为 VARCHAR(1024),因为这会改变存储单个值所需的长度字节数。

  • 禁止在非严格模式下将 NULL 列更改为 NOT NULL,以防止将 NULL 值转换为默认的非 NULL 值,因为在引用的表中没有对应的值。在严格模式下允许此操作,但如果需要进行任何此类转换,则会返回错误。

ALTER TABLE tbl_name RENAME new_tbl_name 会更改内部生成的外键约束名称和以字符串 tbl_name_ibfk_ 开头的用户定义的外键约束名称,以反映新的表名。 InnoDB 将以字符串 tbl_name_ibfk_ 开头的外键约束名称解释为内部生成的名称。

ALTER TABLE 允许添加、删除或更改现有表的 CHECK 约束

  • 添加新的 CHECK 约束

    ALTER TABLE tbl_name
        ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED];

    约束语法元素的含义与 CREATE TABLE 相同。请参阅第 15.1.20.6 节“CHECK 约束”

  • 删除名为 symbol 的现有 CHECK 约束

    ALTER TABLE tbl_name
        DROP CHECK symbol;
  • 更改是否强制执行名为 symbol 的现有 CHECK 约束

    ALTER TABLE tbl_name
        ALTER CHECK symbol [NOT] ENFORCED;

DROP CHECKALTER CHECK 子句是 MySQL 对标准 SQL 的扩展。

ALTER TABLE 允许使用更通用(和 SQL 标准)的语法来删除和更改任何类型的现有约束,其中约束类型由约束名称确定

  • 删除名为 symbol 的现有约束

    ALTER TABLE tbl_name
        DROP CONSTRAINT symbol;

    如果启用了 sql_require_primary_key 系统变量,则尝试删除主键会产生错误。

  • 更改是否强制执行名为 symbol 的现有约束

    ALTER TABLE tbl_name
        ALTER CONSTRAINT symbol [NOT] ENFORCED;

    只有 CHECK 约束可以更改为不强制执行。所有其他约束类型始终都会被强制执行。

SQL 标准规定所有类型的约束(主键、唯一索引、外键、检查)都属于同一个命名空间。在 MySQL 中,每种约束类型每个模式都有自己的命名空间。因此,每种类型的约束的名称在每个模式中必须是唯一的,但不同类型的约束可以具有相同的名称。当多个约束具有相同的名称时,DROP CONSTRAINTADD CONSTRAINT 是不明确的,并且会发生错误。在这种情况下,必须使用特定于约束的语法来修改约束。例如,使用 DROP PRIMARY KEY 或 DROP FOREIGN KEY 来删除主键或外键。

如果表更改导致违反强制执行的 CHECK 约束,则会发生错误,并且不会修改该表。发生错误的操作示例

  • 尝试将 AUTO_INCREMENT 属性添加到 CHECK 约束中使用的列。

  • 尝试添加强制执行的 CHECK 约束或强制执行现有行违反约束条件的非强制执行的 CHECK 约束。

  • 尝试修改、重命名或删除 CHECK 约束中使用的列,除非该约束也在同一语句中被删除。例外:如果 CHECK 约束仅引用单个列,则删除该列会自动删除该约束。

ALTER TABLE tbl_name RENAME new_tbl_name 会更改以字符串 tbl_name_chk_ 开头的内部生成和用户定义的 CHECK 约束名称,以反映新的表名。MySQL 将以字符串 tbl_name_chk_ 开头的 CHECK 约束名称解释为内部生成的名称。

更改字符集

要将表默认字符集和所有字符列(CHARVARCHARTEXT)更改为新的字符集,请使用如下语句

ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

该语句还会更改所有字符列的排序规则。如果未指定 COLLATE 子句来指示要使用的排序规则,则该语句将使用字符集的默认排序规则。如果此排序规则不适合预期的表使用(例如,如果它将从区分大小写的排序规则更改为不区分大小写的排序规则),请显式指定排序规则。

对于数据类型为 VARCHARTEXT 类型之一的列,CONVERT TO CHARACTER SET 会根据需要更改数据类型,以确保新列的长度足以存储与原始列一样多的字符。例如,TEXT 列有两个长度字节,用于存储列中值的字节长度,最大可达 65,535。对于 latin1 TEXT 列,每个字符需要一个字节,因此该列最多可以存储 65,535 个字符。如果将该列转换为 utf8mb4,则每个字符可能需要多达 4 个字节,最大可能长度为 4 × 65,535 = 262,140 字节。该长度不适合 TEXT 列的长度字节,因此 MySQL 会将数据类型转换为 MEDIUMTEXT,这是长度字节可以记录 262,140 值的最小字符串类型。类似地,VARCHAR 列可能会转换为 MEDIUMTEXT

为避免上述类型的数据类型更改,请勿使用 CONVERT TO CHARACTER SET。而是使用 MODIFY 来更改单个列。例如

ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8mb4;
ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M) CHARACTER SET utf8mb4;

如果指定 CONVERT TO CHARACTER SET binary,则 CHARVARCHARTEXT 列将转换为其对应的二进制字符串类型(BINARYVARBINARYBLOB)。这意味着这些列不再具有字符集,并且后续的 CONVERT TO 操作不适用于它们。

如果在 CONVERT TO CHARACTER SET 操作中 charset_nameDEFAULT,则使用 character_set_database 系统变量命名的字符集。

警告

CONVERT TO 操作会在原始字符集和命名字符集之间转换列值。如果您有一个列使用一种字符集(如 latin1),但存储的值实际上使用其他不兼容的字符集(如 utf8mb4),则这不是您想要的。在这种情况下,您必须对每个此类列执行以下操作

ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8mb4;

之所以这样做可行,是因为在转换为 BLOB 列或从 BLOB 列转换时不会进行转换。

要仅更改表的默认字符集,请使用以下语句

ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;

单词 DEFAULT 是可选的。默认字符集是如果您没有为稍后添加到表中的列指定字符集(例如,使用 ALTER TABLE ... ADD column)时使用的字符集。

foreign_key_checks 系统变量启用时(默认设置),不允许对包含外键约束中使用的字符串列的表进行字符集转换。解决方法是在执行字符集转换之前禁用 foreign_key_checks。必须在重新启用 foreign_key_checks 之前对外键约束中涉及的两个表执行转换。如果仅转换其中一个表后重新启用 foreign_key_checks,则 ON DELETE CASCADEON UPDATE CASCADE 操作可能会损坏引用表中的数据,因为在这些操作期间会发生隐式转换(错误 #45290,错误 #74816)。

导入 InnoDB 表

可以使用 DISCARD TABLEPACEIMPORT TABLESPACE 子句从备份或从另一个 MySQL 服务器实例导入在其自己的 每个表一个文件 表空间中创建的 InnoDB 表。请参阅 第 17.6.1.3 节“导入 InnoDB 表”

MyISAM 表的行顺序

ORDER BY 使您能够创建按特定顺序排列行的表。当您知道大多数情况下都按特定顺序查询行时,此选项特别有用。在对表进行重大更改后使用此选项,您可能会获得更高的性能。在某些情况下,如果表按您稍后要对其进行排序的列排序,则可能会使 MySQL 更容易排序。

注意

在插入和删除后,表不会保持指定的顺序。

ORDER BY 语法允许指定一个或多个列名进行排序,每个列名后面可以选择跟随 ASCDESC 来指示升序或降序排序顺序。默认值为升序。仅允许使用列名作为排序条件;不允许使用任意表达式。此子句应在任何其他子句之后给出。

ORDER BYInnoDB 表没有意义,因为 InnoDB 始终根据 聚集索引 对表行进行排序。

当用于分区表时,ALTER TABLE ... ORDER BY 仅对每个分区内的行进行排序。

分区选项

partition_options 表示可与分区表一起使用的选项,用于重新分区、添加、删除、丢弃、导入、合并和拆分分区以及执行分区维护。

ALTER TABLE 语句可以在其他 alter 规范之外包含 PARTITION BYREMOVE PARTITIONING 子句,但 PARTITION BYREMOVE PARTITIONING 子句必须在任何其他规范之后指定。 ADD PARTITIONDROP PARTITIONDISCARD PARTITIONIMPORT PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONEXCHANGE PARTITIONANALYZE PARTITIONCHECK PARTITIONREPAIR PARTITION 选项不能与单个 ALTER TABLE 中的其他 alter 规范组合使用,因为刚刚列出的选项作用于单个分区。

有关分区选项的更多信息,请参阅 第 15.1.20 节“CREATE TABLE 语句”第 15.1.9.1 节“ALTER TABLE 分区操作”。有关 ALTER TABLE ... EXCHANGE PARTITION 语句的信息和示例,请参阅 第 26.3.3 节“与表交换分区和子分区”