13.1.8 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 CHECK (expr)
  | ALGORITHM [=] {DEFAULT | INPLACE | COPY}
  | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
  | 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 {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
  | UPGRADE PARTITIONING
}

key_part:
    col_name [(length)] [ASC | DESC]

index_type:
    USING {BTREE | HASH}

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

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

table_option: {
    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
  | 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}
  | 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更改 table 的结构。例如,您可以添加或删除列,创建或销毁索引,更改现有列的类型或重命名列或 table 本身。您还可以更改 Feature,例如用于 table 或 tableComments 的存储引擎。

  • 要使用ALTER TABLE,您需要对该 table 具有ALTERCREATEINSERT特权。重命名 table 需要在旧 table 上使用ALTERDROP,在新 table 上需要ALTERCREATEINSERT

  • 在 table 名之后,指定要进行的更改。如果没有给出,则ALTER TABLE不执行任何操作。

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

  • COLUMN是可选的,可以省略。

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

ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;

ALTER TABLE语句还有其他方面,在本节以下主题下进行介绍:

Table Options

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

有关所有 table 选项的说明,请参见第 13.1.18 节“ CREATE TABLE 语句”。但是,ALTER TABLE在作为 table 选项给出时会忽略DATA DIRECTORYINDEX DIRECTORYALTER TABLE仅允许它们作为分区选项,并且从 MySQL 5.7.17 开始,要求您具有FILE特权。

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

  • 如果t1当前不是InnoDBtable,则此语句将其存储引擎更改为InnoDB
ALTER TABLE t1 ENGINE = InnoDB;
ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
  • 要为每个 table 文件 table 空间中的InnoDBtable 启用或禁用加密:
ALTER TABLE t1 ENCRYPTION='Y';
ALTER TABLE t1 ENCRYPTION='N';

必须安装并配置钥匙圈插件以使用ENCRYPTION选项。有关更多信息,请参见第 14.14 节“ InnoDB 静态数据加密”

  • 要重置当前的自动增量值:
ALTER TABLE t1 AUTO_INCREMENT = 13;

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

  • 更改默认 table 字符集:
ALTER TABLE t1 CHARACTER SET = utf8;

另请参见更改字符集

  • 要添加(或更改)tableComments:
ALTER TABLE t1 COMMENT = 'New table comment';
  • ALTER TABLETABLESPACE选项一起使用可在现有general tablespacesfile-per-tabletable 空间和system tablespace之间移动InnoDBtable。参见使用 ALTER TABLE 在 table 空间之间移动 table

  • ALTER TABLE ... TABLESPACE操作始终会导致整个 table 的重建,即使TABLESPACE属性与其之前的值相比也没有变化。

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

    • 创建 table...table 空间支持的DATA DIRECTORY子句不受ALTER TABLE ... TABLESPACE的支持,如果指定,将被忽略。

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

  • MySQL NDB Cluster 7.5.2 和更高版本支持设置NDB_TABLE选项,以控制 table 的分区平衡(碎片计数类型),从任何副本读取功能,完全复制或这些的任意组合,作为 tableComments 的一部分。 ALTER TABLE语句的方式与CREATE TABLE相同,如以下示例所示:

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

请记住,ALTER TABLE ... COMMENT ...会丢弃该 table 的所有现有 Comments。有关其他信息和示例,请参见设置 NDB_TABLE 选项

要验证是否按预期更改了 table 选项,请使用显示创建 table或查询INFORMATION_SCHEMA.TABLEStable。

性能和空间要求

ALTER TABLE操作是使用以下算法之一处理的:

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

  • INPLACE:操作避免复制 table 数据,但可以在适当位置重建 table。在操作的准备和执行阶段可以简短地获取 table 上的独占元数据锁定。通常,支持并发 DML。

ALGORITHM子句是可选的。如果省略ALGORITHM子句,则 MySQL 使用ALGORITHM=INPLACEtable 示存储引擎和使用ALTER TABLE子句来支持它。否则,使用ALGORITHM=COPY

指定ALGORITHM子句要求操作将指定的算法用于支持该子句的子句和存储引擎,否则将因错误而失败。指定ALGORITHM=DEFAULT与省略ALGORITHM子句相同。

使用COPY算法的ALTER TABLE操作 await 其他正在修改 table 的操作完成。将更改应用于 table 副本后,将数据复制过来,删除原始 table,然后将 table 副本重命名为原始 table 的名称。在执行ALTER TABLE操作时,其他会话可以读取原始 table(不久后会注意到)。在ALTER TABLE操作开始之后开始的 table 的更新和写入将暂停,直到准备好新 table,然后自动将其重定向到新 table。该 table 的临时副本是在原始 table 的数据库目录中创建的,除非它是通过RENAME TO操作将 table 移动到位于其他目录中的数据库中。

前面提到的 exception 是ALTER TABLE块在准备安装 table.frm文件的新版本,丢弃旧文件以及从 table 和 table 定义高速缓存中清除过时的 table 结构的 Moment 读取(而不仅仅是写入) 。此时,它必须获得一个排他锁。为此,它 await 当前的读取器完成,并阻止新的读取和写入。

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

要强制将COPY算法用于原本不会使用的ALTER TABLE操作,请启用old_alter_table系统变量或指定ALGORITHM=COPY。如果old_alter_table设置和ALGORITHM子句的值不是DEFAULT发生冲突,则ALGORITHM子句优先。

对于InnoDBtable,对驻留在shared tablespace中的 table 使用COPY算法的ALTER TABLE操作可以增加 table 空间使用的空间量。此类操作需要与 table 中的数据以及索引一样多的额外空间。对于驻留在共享 table 空间中的 table,操作期间使用的额外空间不会释放回 os,就像驻留在file-per-tabletable 空间中的 table 一样。

有关联机 DDL 操作的空间要求的信息,请参阅第 14.13.3 节“在线 DDL 空间要求”

使用INPLACE算法的ALTER TABLE操作包括:

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

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

  • 仅修改 table 元数据的操作。这些操作是立即进行的,因为服务器仅更改 table.frm文件,而不更改 table 内容。仅元数据的操作包括:

  • 重命名列。

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

    • 只要数据类型的存储大小不变,就可以通过向有效成员值列 table 的* end *添加新的枚举或设置成员来修改ENUMSET列的定义。例如,将成员添加到具有 8 个成员的SET列会将每个值所需的存储从 1 字节更改为 2 字节;这需要一个 table 副本。在列 table 中间添加成员会导致对现有成员重新编号,这需要 table 副本。

  • 重命名索引。

  • InnoDBNDBtable 添加或删除辅助索引。参见第 14.13 节“ InnoDB 和在线 DDL”

  • 对于NDBtable,是在可变宽度列上添加和删除索引的操作。这些操作在线发生,无需复制 table,也不会在大部分时间内阻止并发 DML 操作。参见第 21.5.11 节“ NDB 集群中使用 ALTER TABLE 的在线操作”

ALTER TABLEADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEXFORCE操作的 MySQL 5.5 临时列升级为 5.6 格式。使用INPLACE算法无法完成此转换,因为必须重建 table,因此在这种情况下指定ALGORITHM=INPLACE会导致错误。如有必要,请指定ALGORITHM=COPY

如果对用于通过KEY分区 table 的多列索引执行ALTER TABLE操作更改了列的 Sequences,则只能使用ALGORITHM=COPY执行该操作。

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

NDB Cluster 以前使用ONLINEOFFLINE关键字支持联机ALTER TABLE操作。不再支持这些关键字。它们的使用会导致语法错误。 MySQL NDB Cluster 7.5(及更高版本)使用与标准 MySQL Server 相同的ALGORITHM=INPLACE语法支持在线操作。 NDB不支持在线更改 table 空间。有关更多信息,请参见第 21.5.11 节“ NDB 集群中使用 ALTER TABLE 的在线操作”

ALTER TABLEDISCARD ... PARTITION ... TABLESPACEIMPORT ... PARTITION ... TABLESPACE不会创建任何临时 table 或临时分区文件。

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

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

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

Concurrency Control

对于支持它的ALTER TABLE操作,可以使用LOCK子句来控制对 table 进行更改时并发读取和写入的级别。通过为该子句指定非默认值,可以使您在 alter 操作期间需要一定数量的并发访问或排他性,并且如果请求的锁定程度不可用,则中止操作。 LOCK子句的参数为:

锁定=默认


Maximum level of concurrency for the given  `ALGORITHM`  clause \(if any\) and  `ALTER TABLE`  operation: Permit concurrent reads and writes if supported\. If not, permit concurrent reads if supported\. If not, enforce exclusive access\.

 - ```
LOCK = NONE

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

锁定=共享


If supported, permit concurrent reads but block writes\. Writes are blocked even if concurrent writes are supported by the storage engine for the given  `ALGORITHM`  clause \(if any\) and  `ALTER TABLE`  operation\. If concurrent reads are not supported, an error occurs\.

 - ```
LOCK = EXCLUSIVE

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

添加和删除列

使用ADD将新列添加到 table 中,并使用DROP删除现有列。 DROP col_name是标准 SQL 的 MySQL 扩展。

要在 table 格行中的特定位置添加列,请使用FIRSTAFTER col_name。默认为最后添加该列。

如果 table 仅包含一列,则不能删除该列。如果要删除 table,请使用DROP TABLE语句。

如果从 table 中删除了列,则这些列也将从它们所属的任何索引中删除。如果组成索引的所有列都被删除,那么索引也将被删除。

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

CHANGEMODIFYALTER子句可更改现有列的名称和定义。它们具有以下比较 Feature:

  • CHANGE :

  • 可以重命名列并更改其定义,或同时更改两者。

    • 具有比MODIFY更大的功能,但以某些操作的便利性为代价。 CHANGE如果不重命名该列,则需要两次命名。

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

  • MODIFY :

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

    • CHANGE相比,更方便地更改列定义而不重命名。

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

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

CHANGE是标准 SQL 的 MySQL 扩展。 MODIFY是与 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;

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

ALTER TABLE t1 CHANGE b a INT NOT NULL;

对于使用CHANGEMODIFY进行的列定义更改,定义必须包括数据类型和应应用于新列的所有属性,而不是诸如PRIMARY KEYUNIQUE之类的索引属性。原始定义中存在但未为新定义指定的属性不会 continue。假设将列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 模式(请参阅第 5.1.10 节“服务器 SQL 模式”)。

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

对于以CHANGE重命名的列,MySQL 自动将这些引用重命名为重命名的列:

  • 引用旧列的索引,包括索引和禁用的MyISAM索引。

  • 引用旧列的外键。

对于以CHANGE重命名的列,MySQL 不会自动将这些引用重命名为重命名的列:

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

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

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

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

主键和索引

DROP PRIMARY KEY丢弃primary key。如果没有主键,则会发生错误。有关主键(尤其是InnoDBtable)的性能 Feature 的信息,请参见第 8.3.2 节“主键优化”

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

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

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

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

如果在MyISAMtable 上使用ALTER TABLE,则将在单独的批处理中创建所有非唯一索引(对于REPAIR TABLE)。当您有很多索引时,这应该使ALTER TABLE更快。

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

虽然禁用了非唯一索引,但对于诸如SELECTEXPLAIN之类的语句将忽略它们,否则将使用它们。

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

外键和其他约束

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

CHECK约束子句已解析,但被所有存储引擎忽略。参见第 13.1.18 节“ CREATE TABLE 语句”。接受但忽略语法子句的原因是为了兼容性,使从其他 SQL Server 移植代码更加容易,以及运行使用引用创建 table 的应用程序。参见第 1.8.2 节“ MySQL 与标准 SQL 的区别”

对于ALTER TABLE,与CREATE TABLE不同,ADD FOREIGN KEY忽略* index_name *(如果给定),并使用自动生成的外键名称。解决方法是,包含CONSTRAINT子句以指定外键名称:

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

Important

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

Note

分区的InnoDBtable 不支持外键。此限制不适用于NDBtable,包括由[LINEAR] KEY明确分区的 table。有关更多信息,请参见第 22.6.2 节“与存储引擎有关的分区限制”

MySQL Server 和 NDB Cluster 都支持使用ALTER TABLE删除外键:

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

ALTER TABLE ... ALGORITHM =插入支持在同一ALTER TABLE语句中添加和删除外键,但ALTER TABLE ... ALGORITHM =复制不支持。

服务器禁止对外键列进行更改,否则可能会导致丢失引用完整性。一种解决方法是在更改列定义之前使用ALTER TABLE ...删除外键,然后再使用ALTER TABLE ...添加外键。禁止更改的示例包括:

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

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

ALTER TABLE tbl_name RENAME new_tbl_name更改内部生成的外键约束名称和用户定义的外键约束名称,这些名称以字符串“ * tbl_name * ibfk”开头,以反映新的 table 名。 InnoDB将以字符串“ * tbl_name * ibfk”开头的外键约束名称解释为内部生成的名称。

更改字符集

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

ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

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

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

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

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

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

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

Warning

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

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

之所以起作用,是因为您在BLOB列之间进行转换时没有任何转换。

要仅更改 table 的* default *字符集,请使用以下语句:

ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;

DEFAULT是可选的。默认字符集是如果不为稍后添加到 table 中的列指定字符集(例如,使用ALTER TABLE ... ADD column),则使用该字符集。

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

丢弃和导入 InnoDBtable 空间

可以使用DISCARD TABLEPACEIMPORT TABLESPACE子句从备份或另一个 MySQL 服务器实例中导入在自己的file-per-tabletable 空间中创建的InnoDBtable。参见第 14.6.1.3 节“导入 InnoDBtable”

MyISAMtable 的行 Sequences

ORDER BY使您可以按特定 Sequences 创建包含行的新 table。该选项主要在您知道大多数情况下以某种 Sequences 查询行时才有用。通过在对该 table 进行重大更改之后使用此选项,可能会获得更高的性能。在某些情况下,如果 table 是按要稍后排序的列排序的,则对 MySQL 的排序可能会更容易。

Note

插入和删除后,table 未按指定 Sequences 保留。

ORDER BY语法允许指定一个或多个列名称进行排序,每个列名称可选地可以跟在ASCDESC之后,以分别指示升序或降序。默认为升序。只允许使用列名作为排序条件;不允许使用任意 table 达式。该条款应在其他任何条款之后给出。

ORDER BY对于InnoDBtable 没有意义,因为InnoDB始终根据clustered index对 table 行进行排序。

在分区 table 上使用时,ALTER TABLE ... ORDER BY仅对每个分区内的行进行排序。

Partitioning Options

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

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

有关分区选项的更多信息,请参见第 13.1.18 节“ CREATE TABLE 语句”第 13.1.8.1 节,“ ALTER TABLE 分区操作”。有关ALTER TABLE ... EXCHANGE PARTITION语句的信息和示例,请参见第 22.3.3 节“用 table 交换分区和子分区”

在 MySQL 5.7.6 之前,已分区的InnoDBtable 使用了MyISAM和其他不提供自己的分区处理程序的存储引擎使用的通用ha_partition分区处理程序;在 MySQL 5.7.6 和更高版本中,此类 table 是使用InnoDB存储引擎自己的(或“本机”)分区处理程序创建的。从 MySQL 5.7.9 开始,您可以使用ALTER TABLE ... UPGRADE PARTITIONING将在 MySQL 5.7.6 或更早版本中创建的InnoDBtable(即使用ha_partition创建)升级到InnoDB本机分区处理程序。 (缺陷号#76734,错误号#20727344)此ALTER TABLE语法不接受任何其他选项,并且一次只能在单个 table 上使用。您还可以在 MySQL 5.7.9 或更高版本中使用mysql_upgrade将较旧的分区 InnoDB table 升级到本机分区处理程序。