文档主页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9 MB
PDF (A4) - 40.0 MB
手册页 (TGZ) - 258.5 KB
手册页 (Zip) - 365.5 KB
信息 (Gzip) - 4.0 MB
信息 (Zip) - 4.0 MB


MySQL 8.4 参考手册  /  ...  /  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 语句还有其他几个方面,在本节的以下主题中进行了描述

表选项

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 8.4 支持设置 NDB_TABLE 选项,用于控制表的 partition 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 集群中使用 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 集群中,此操作也可以在线执行。

    • 更改列的默认值(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 集群中使用 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 8.4 支持使用与标准 MySQL 服务器相同的 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。如果该列不能为 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 节“不可见索引”

外键和其他约束

InnoDBNDB 存储引擎支持 FOREIGN KEYREFERENCES 子句,它们实现了 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 Server 和 NDB Cluster 都支持使用 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 节“将分区和子分区与表交换”