Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  ALTER TABLE Statement

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 语句”。但是,当作为表选项给出时,ALTER TABLE 会忽略 DATA DIRECTORYINDEX DIRECTORYALTER 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';
  • 使用带有 TABLESPACE 选项的 ALTER TABLEInnoDB 表在现有 一般表空间每表一个文件 表空间和 系统表空间 之间移动。请参见 使用 ALTER TABLE 在表空间之间移动表

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

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

    • CREATE TABLE ... TABLESPACE 支持的 DATA DIRECTORY 子句,ALTER TABLE ... TABLESPACE 不支持,如果指定则忽略。

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

  • MySQL NDB Cluster 8.3 支持设置 NDB_TABLE 选项,用于控制表的partition balance(碎片计数类型)、read-from-any-replica 功能、full replication 或这些的任意组合,作为表注释的一部分,用于 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

Note

使用 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 设置与值为非 DEFAULTALGORITHM 子句之间存在冲突,则 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 属性可以在不重建表的情况下就地完成。

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

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

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

  • 添加或删除虚拟列。

  • 添加或删除列默认值。

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

  • 更改索引类型。

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

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

ALTER TABLE 将 MySQL 5.5 时间列升级为 5.6 格式,用于 添加列更改列修改列添加索引FORCE 操作。无法使用 INPLACE 算法执行此转换,因为必须重建表,因此在这些情况下指定 ALGORITHM=INPLACE 会导致错误。如有必要,请指定 ALGORITHM=COPY

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

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

NDB Cluster 8.3 支持使用与标准 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 是标准 SQL 的 MySQL 扩展。 MODIFYRENAME COLUMN 是为了与 Oracle 兼容而进行的 MySQL 扩展。

要更改列以同时更改其名称和定义,请使用 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 会尝试尽可能将现有列值转换为新类型。

Warning

此转换可能会导致数据更改。例如,如果缩短字符串列,则值可能会被截断。为了防止在转换为新数据类型会导致数据丢失的情况下操作成功,请在使用 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 节,“不可见索引”

外键和其他约束

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 (....) ...
Important

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

Note

分区后的 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 系统变量命名的字符集。

Warning

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

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

之所以可行,是因为在您转换为或从 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 操作可能会损坏引用表中的数据,因为在这些操作期间会发生隐式转换(Bug #45290、Bug #74816)。

导入InnoDB表

使用自己的 文件-每-表 表空间创建的 InnoDB 表可以通过 DISCARD TABLEPACEIMPORT TABLESPACE 语句从备份或从其他 MySQL 服务器实例导入。参见 第 17.6.1.3 节,“导入 InnoDB 表”

MyISAM表的行顺序

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

Note

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

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 节,“使用表交换分区和子分区”