Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 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 DIRECTORY作为表选项,但允许它们作为分区选项,并且需要您拥有FILE特权。

使用表选项与ALTER TABLE提供了改变单个表特性的便捷方式。例如:

  • 如果t1当前不是InnoDB表,这个语句将其存储引擎更改为InnoDB:

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

    ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
  • ENCRYPTION子句启用或禁用InnoDB表的页面级别数据加密。需要安装和配置密钥ring插件以启用加密。

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

    ENCRYPTION也支持在公共表空间中的表。

    在公共表空间中,表和表空间加密必须一致。

    通过移动表或更改存储引擎来更改表加密不允许,不得不指定ENCRYPTION子句。

    如果表使用不支持加密的存储引擎,指定ENCRYPTION子句的值不是'N'''是不可允许的。尝试在不支持加密的存储引擎中创建一个没有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 TABLE语句的TABLESPACE选项来将通用表空间文件表空间系统表空间中的InnoDB表之间移动。详见.

    • ALTER TABLE ... TABLESPACE操作总是导致全表重建,即使TABLESPACE属性没有从前一个值改变。

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

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

    • 关于CREATE TABLETABLESPACE选项能力和限制,详见.

  • MySQL NDB集群 8.4 支持在ALTER TABLE语句中,通过表注释来控制表的分区平衡(碎片计数类型)、从任意副本读取能力、全量复制或这三个选项的组合,方式与CREATE TABLE相同,如下所示:

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

    也可以在ALTER TABLE语句中,设置NDB表的列注释,例如:

    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,或者查询信息架构TABLES表。

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

  • COPY:对原始表进行copy,逐行将数据从原始表复制到新表。并发DML不允许。

  • INPLACE:操作避免了表数据的copy,但可能在执行过程中重建表。在准备和执行阶段,可能会短暂地获取表独占锁。通常情况下,支持并发DML。

  • INSTANT:只修改数据字典中的元数据。在执行阶段,可能会短暂地获取表独占锁。表数据不受影响,使操作实时完成。支持并发DML。

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

  • COPYNDB创建了表的副本,然后将数据从原始表复制到新表。最后,NDB删除原始表并重命名新表。

    这也称为复制离线ALTER TABLE

  • INPLACE: 数据节点执行所需的更改,NDB集群处理不复制数据或参与其他操作。

    这也称为非复制在线ALTER TABLE

  • INSTANT: 不支持NDB

请参阅第25.6.12节,“NDB集群中的ALTER TABLE在线操作”,了解更多信息。

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

Note

使用ALGORITHM=INSTANT添加列到分区表后,不能再对该表执行ALTER TABLE ... EXCHANGE PARTITION

指定ALGORITHM子句需要操作使用指定的算法,否则报错。指定ALGORITHM=DEFAULT与省略ALGORITHM子句相同。

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

前面提到的例外是ALTER TABLE在清理过时表结构和表定义缓存时,会阻塞读取(不仅写入),因此它需要获取独占锁。为此,它等待当前读者完成,然后阻塞新读取和写入。

ALTER TABLE 操作使用COPY算法将阻止并发DML操作。仍然允许查询操作。即使是表复制操作,也至少包括LOCK=SHARED(允许查询,但不允许DML)的并发限制。你可以通过指定LOCK=EXCLUSIVE,来进一步限制并发操作,阻止DML和查询。更多信息,请参见Concurrency Control.

强制使用COPY算法的ALTER TABLE操作,可以指定ALGORITHM=COPY或启用old_alter_table系统变量。如果old_alter_table设置和ALGORITHM子句的值不是DEFAULT,那么ALGORITHM子句优先级更高。

InnoDB 表中,使用ALTER TABLE操作在共享表空间中执行时,可以增加表空间的大小。这种操作需要额外的空间与表中的数据和索引之和。对共享表空间中的表,操作过程中使用的额外空间不会像文件-per-table 表空间那样被释放回操作系统。

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

ALTER TABLE操作支持在线DDL特性,见第17.12.1节,“在线DDL操作”

  • ALTER TABLE operations supported by the InnoDB online DDL feature. See Section 17.12.1, “Online DDL Operations”.

  • 重命名一个表。MySQL不复制文件,直接将对应的tbl_name文件重命名。(也可以使用RENAME TABLE语句来重命名表。见第15.1.36节,“RENAME TABLE 语句”。对重命名后的表授予的特权不自动迁移到新名称,需要手动修改。

  • 只修改表元数据的操作这些操作是立即完成的,因为服务器不触摸表内容。只修改元数据的操作包括:

    • 重命名一个列。在 NDB 集群中,这个操作也可以在线执行。

    • 更改一个列的默认值(除了NDB表).

    • 修改一个ENUMSET列的定义,添加新的枚举值或集合成员到末尾有效值列表中,只要数据类型存储大小不变。例如,对于一个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操作修改索引可见性。

  • 修改包含生成列的表,生成列依赖于具有默认值的列,如果修改的列不参与生成列表达式。例如,单独修改一个列的NULL属性可以在不重建表的情况下完成。

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

  • 添加列。这个特性称为“Instant ADD COLUMN”。存在限制。见第17.12.1节,“在线DDL操作”.

  • 删除列。这一特性称为Instant DROP COLUMN。存在限制。请参见第17.12.1节,“在线DDL操作”

  • 添加或删除虚拟列。

  • 添加或删除列默认值。

  • 修改ENUMSET列的定义。同上述ALGORITHM=INSTANT所描述的限制。

  • 更改索引类型。

  • 重命名表格。同上述ALGORITHM=INSTANT所描述的限制。

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

ALTER TABLE将MySQL 5.5的时间戳列升级到5.6格式,对于ADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEXFORCE操作。由于表格需要重建,因此在这些情况下指定ALGORITHM=INPLACE将导致错误,需要指定ALGORITHM=COPY

如果对一个多列索引执行ALTER TABLE操作,用于将表按KEY分区,但改变了列的顺序,那么只能使用ALGORITHM=COPY

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

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

在执行复制ALTER TABLE时,NDB检查是否有其他线程对受影响的表进行了写入。如果发现有,则NDB拒绝ALTER TABLE语句并raise ER_TABLE_DEF_CHANGED

ALTER TABLE 使用DISCARD ... PARTITION ... TABLESPACEIMPORT ... PARTITION ... TABLESPACE不创建临时表或临时分区文件。

ALTER TABLE 使用ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREBUILD PARTITIONREORGANIZE PARTITION不创建临时表(except 使用NDB表),但是这些操作可以和会创建临时分区文件。

ADDDROP操作用于RANGELIST分区是即时操作或非常快的操作;ADDCOALESCE操作用于HASHKEY分区将数据从所有分区复制,除非使用了LINEAR HASHLINEAR KEY;这等同于创建一个新表,但是ADDCOALESCE操作是按分区进行的。REORGANIZE操作只复制变化的分区,不触摸未变更的分区。

对于MyISAM表,可以通过设置myisam_sort_buffer_size系统变量到高值来加速索引重建( alteration 过程中最慢的一部分)。

ALTER TABLE 操作支持时,您可以使用LOCK子句来控制表在被修改时的并发读写级别。指定非默认值的子句可以要求某种程度的并发访问或独占访问,直到请求的锁定级别不可用时终止操作。

使用ALGORITHM=INSTANT操作只能使用LOCK = DEFAULT。其他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更强大,但是在某些操作中需要付出更多代价。需要在不重命名列时指定列名称,且如果只重命名列则需要重新指定列定义。

    • 可以使用FIRSTAFTER来重新排列列。

  • MODIFY:

    • 只能改变列定义,不改变其名称。

    • CHANGE更方便地改变列定义而不重命名它。

    • 可以使用FIRSTAFTER来重新排列列。

  • RENAME COLUMN:

    • 只能重命名列,不改变其定义。

    • 比使用CHANGE更方便地重命名一个列而不改变其定义。

  • ALTER: 只用于修改列的默认值。

CHANGE是MySQL对标准SQL的扩展。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',你想将其修改为BIGINT,那么该语句会将数据类型从INT改为BIGINT,同时也会丢弃UNSIGNEDDEFAULTCOMMENT属性。为了保留它们,该语句必须包含它们的明确指定:

ALTER TABLE t1 MODIFY col1 BIGINT;

使用CHANGEMODIFY修改数据类型时,MySQL也会尽可能地将现有列值转换为新类型。

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

For data type changes using CHANGE or MODIFY, MySQL tries to convert existing column values to the new type as well as possible.

Warning

这次转换可能会改变数据。例如,如果您缩短字符串列,值可能被截断。在使用ALTER TABLE之前,启用严格SQL模式,以防止转换操作结果导致数据丢失(见第7.1.11节,“服务器 SQL 模式”)。

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

通过CHANGERENAME COLUMN重命名的列,MySQL自动重命名这些引用:

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

  • 对旧列的外键。

通过CHANGERENAME COLUMN重命名的列,MySQL不自动重命名这些引用:

  • 引用重命名列的生成列和分区表达式。您必须在同一个ALTER TABLE语句中重新定义这些表达式。

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

要在表中重新排列列,使用FIRSTAFTERCHANGEMODIFY操作中。

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

ALTER ... SET VISIBLEALTER ... SET INVISIBLE使列可见性可以被更改。请参阅第15.1.20.10节,“不可见列”

Primary Keys and 索引

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

如果你对ALTER TABLE一个MyISAM表,所有非唯一索引将在单独的批次中创建(类似REPAIR TABLE)。这应该使ALTER TABLE在你有许多索引时速度更快。

MyISAM 表中,可以控制键更新。使用 ALTER TABLE ... DISABLE KEYS 告诉 MySQL 停止更新非唯一索引,然后使用 ALTER TABLE ... ENABLE KEYS 重新创建缺失的索引。MyISAM 使用特殊算法,速度远快于逐一插入键,所以在执行 bulk 插入操作前禁用键可以获得明显加速。使用 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节,“外键约束”。其他存储引擎则将子句解析但忽略。

ALTER TABLE,不同于CREATE TABLEADD FOREIGN KEY如果给出index_name则忽略,并使用自动生成的外键名称。作为解决方案,请包含CONSTRAINT子句指定外键名称:

ADD CONSTRAINT name FOREIGN KEY (....) ...
Important

MySQL忽略inlineREFERENCES语句,定义在列规范中的引用关系。MySQL只接受独立的FOREIGN KEY语句中定义的REFERENCES子句。

Note

分区表不支持外键约束。这一限制不适用于第26.6.2节,“存储引擎与分区限制”中所述的NDB表,包括使用[LINEAR] KEY进行显式分区的表。

MySQL Server和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 约束”.

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

    ALTER TABLE tbl_name
        DROP CHECK symbol;
  • 修改现有CHECK约束名为symbol是否生效:

    ALTER TABLE tbl_name
        ALTER CHECK symbol [NOT] ENFORCED;

DROP CHECK 和 ALTER 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 中,每个约束类型都有自己的命名空间 per schema。因此,schema 内每种约束类型的名称必须是唯一的,但不同类型的约束可以拥有相同的名称。出现多个约束时,DROP CONSTRAINTADD CONSTRAINT 将产生错误。在这种情况下,必须使用 constraint-特定的语法来修改约束。例如,使用 DROP PRIMARY KEY 或 DROP FOREIGN KEY 删除主键或外键。

如果表的修改违反了生效的CHECK 约束,将产生错误且不修改表。以下是一些导致错误的操作示例:

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

  • 尝试添加强制CHECK约束或强制执行不强制的CHECK约束,但该约束已经存在的行违反约束条件。

  • 尝试修改、重命名或删除一个用作CHECK约束中的列,除非在同一语句中也删除该约束。异常:如果CHECK约束只引用单个列,那么删除该列自动删除约束。

ALTER TABLE tbl_name RENAME new_tbl_name 将内部生成的和用户定义的CHECK约束名称,前缀为“"tbl_name_chk_”,修改以反映新的表名。MySQL将前缀为“"tbl_name_chk_”CHECK约束名称解释为内部生成的名称。

更改表默认字符集和所有字符列(CHAR, VARCHAR, TEXT)到新字符集,使用以下语句:

ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

该语句还将所有字符列的排序规则更改。如果不指定COLLATE子句来指明使用哪种排序规则,语句将使用默认的排序规则。如果这个排序规则对于表的预期用途不合适(例如,如果要从敏感排序规则变为不敏感排序规则),请指定排序规则。

对于具有VARCHARTEXT类型的列,CONVERT TO CHARACTER SET会根据需要更改数据类型,以确保新的列足够存储原始列中的字符数。例如,一个TEXT列有两个长度字节,用于存储该列的值的字节长度,最大为65535个字节。对于一个latin1TEXT列,每个字符需要一个字节,所以该列最多可以存储65535个字符。如果该列被转换到utf8mb4,每个字符可能需要四个字节,最大可能长度为4×65535=262140字节。该长度不适合TEXT列的长度字节,所以MySQL将数据类型转换到MEDIUMTEXT,这是最小的字符串类型,可以记录262140个值。类似地,一个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 binaryCHARVARCHARTEXT列将被转换为相应的二进制字符串类型(BINARYVARBINARYBLOB)。这意味着这些列不再具有字符集,后续的CONVERT TO操作对它们无效。

如果charset_nameCONVERT TO CHARACTER SET操作中是DEFAULTcharacter_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后,可能会导致引用表中的数据损坏(Bug #45290,Bug #74816).

Importing InnoDB 表

可以使用文件-per-table表空间创建的InnoDB表,可以从备份或另一个MySQL服务器实例中导入,使用DISCARD TABLEPACEIMPORT TABLESPACE子句。详见第17.6.1.3节,“导入InnoDB表”.

Row Order for MyISAM 表

ORDER BY 允许您在创建新表时,按照特定的顺序排列行。这个选项主要有用处是在您知道大多数情况下查询的行顺序时。使用这个选项后对表进行了主要修改,您可能可以获得更高的性能。在某些情况下,如果表按要排序的列已经排序,MySQL也可能会更容易排序。

Note

删除和插入操作后,表不再保持指定的顺序。

ORDER BY 语法允许指定一个或多个列名来进行排序,每个列名可选地后跟ASCDESC,分别表示升序和降序排列顺序,默认是升序。只允许列名作为排序标准;不允许任意表达式。该子句应该在其他子句后面。

ORDER BY 对于InnoDB 表无意义,因为InnoDB 总是根据聚簇索引来排序表行。

在分区表上使用 ALTER TABLE ... ORDER BY 时,只对每个分区进行行排序。

分区 Options

partition_options 表示与分区表相关的选项,可以用于重分区、添加、删除、丢弃、导入、合并和拆分分区,执行分区维护操作。

ALTER TABLE 语句可以包含PARTITION BYREMOVE PARTITIONING子句,除了其他修改语法外,但必须在所有其他语法后面指定。不能将ADD PARTITIONDROP PARTITIONDISCARD PARTITIONIMPORT PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONEXCHANGE PARTITIONANALYZE PARTITIONCHECK PARTITIONREPAIR PARTITION选项与其他修改语法组合在一个ALTER TABLE语句中,因为这些选项都作用于单个分区。

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