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
,您需要对该表具有ALTER
、CREATE
和INSERT
权限。重命名表需要对旧表具有ALTER
和DROP
权限,对新表具有ALTER
、CREATE
和INSERT
权限。 -
在表名之后,指定要进行的更改。如果没有给出,
ALTER TABLE
不执行任何操作。 -
许多允许的更改的语法类似于
CREATE TABLE
语句的子句。column_definition
子句对ADD
和CHANGE
使用与CREATE TABLE
相同的语法。有关更多信息,请参阅 第 15.1.20 节,“CREATE TABLE 语句”。 -
单词
COLUMN
是可选的,可以省略,除了RENAME COLUMN
(用于将列重命名操作与RENAME
表重命名操作区分开来)。 -
单个
ALTER TABLE
语句中允许多个ADD
、ALTER
、DROP
和CHANGE
子句,并用逗号分隔。这是 MySQL 对标准 SQL 的扩展,标准 SQL 每个ALTER TABLE
语句只允许使用每个子句一次。例如,要在单个语句中删除多列,请执行以下操作:ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
-
如果存储引擎不支持尝试的
ALTER TABLE
操作,则可能会导致警告。可以使用SHOW WARNINGS
显示此类警告。请参阅 第 15.7.7.44 节,“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
AStype
ARRAY) -
使用
mysql_info()
C API 函数,您可以了解ALTER TABLE
复制了多少行。请参阅 mysql_info()。
ALTER TABLE
语句还有几个其他方面,在本节中的以下主题下进行了描述:
表选项
table_options
表示可在 CREATE TABLE
语句中使用的表选项,例如 ENGINE
、AUTO_INCREMENT
、AVG_ROW_LENGTH
、MAX_ROWS
、ROW_FORMAT
或 TABLESPACE
。
有关所有表选项的说明,请参阅 第 15.1.20 节,“CREATE TABLE 语句”。但是,当作为表选项给出时,ALTER TABLE
会忽略 DATA DIRECTORY
和 INDEX DIRECTORY
。 ALTER TABLE
仅允许将它们作为分区选项,并要求您具有 FILE
权限。
将表选项与 ALTER TABLE
一起使用提供了一种方便的方式来更改单个表特征。例如:
-
如果
t1
当前不是InnoDB
表,则此语句将其存储引擎更改为InnoDB
:ALTER TABLE t1 ENGINE = InnoDB;
-
有关将表切换到
InnoDB
存储引擎时的注意事项,请参阅 第 17.6.1.5 节,“将表从 MyISAM 转换为 InnoDB”。 -
当您指定
ENGINE
子句时,ALTER TABLE
会重建表。即使该表已经具有指定的存储引擎也是如此。 -
在现有的
InnoDB
表上运行ALTER TABLE
会执行一个 “空”tbl_name
ENGINE=INNODBALTER TABLE
操作,这可以用来对InnoDB
表进行碎片整理,如 章节 17.11.4, “碎片整理表” 中所述。在InnoDB
表上运行ALTER TABLE
执行相同的功能。tbl_name
FORCE -
ALTER TABLE
和tbl_name
ENGINE=INNODBALTER TABLE
使用 在线 DDL。有关更多信息,请参阅 章节 17.12, “InnoDB 和在线 DDL”。tbl_name
FORCE -
尝试更改表存储引擎的结果受所需存储引擎是否可用以及
NO_ENGINE_SUBSTITUTION
SQL 模式的设置的影响,如 章节 7.1.11, “服务器 SQL 模式” 中所述。 -
为了防止意外丢失数据,
ALTER TABLE
不能用于将表的存储引擎更改为MERGE
或BLACKHOLE
。
-
-
要将
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;
您不能将计数器重置为小于或等于当前正在使用的值。对于
InnoDB
和MyISAM
,如果值小于或等于AUTO_INCREMENT
列中的当前最大值,则该值将重置为当前最大AUTO_INCREMENT
列值加一。 -
要更改默认表字符集:
ALTER TABLE t1 CHARACTER SET = utf8mb4;
另请参见 更改字符集。
-
要添加(或更改)表注释:
ALTER TABLE t1 COMMENT = 'New table comment';
-
使用带有
TABLESPACE
选项的ALTER TABLE
将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.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_ATTRIBUTE
和SECONDARY_ENGINE_ATTRIBUTE
选项用于为主要和次要存储引擎指定表、列和索引属性。这些选项保留供将来使用。索引属性无法更改。必须删除索引并使用所需更改将其重新添加,这可以在单个ALTER TABLE
语句中执行。
要验证表选项是否按预期更改,请使用 SHOW CREATE TABLE
,或查询 Information Schema TABLES
表。
性能和空间要求
ALTER TABLE
操作使用以下算法之一进行处理:
-
COPY
:对原始表的副本执行操作,并将表数据逐行从原始表复制到新表。不允许并发 DML。 -
INPLACE
:操作避免复制表数据,但可能会就地重建表。在操作的准备和执行阶段,可能会短暂地获取表的独占元数据锁。通常,支持并发 DML。 -
INSTANT
:操作仅修改数据字典中的元数据。在操作的执行阶段,可能会短暂地获取表的独占元数据锁。表数据不受影响,从而使操作即时完成。允许并发 DML。
对于使用 NDB
存储引擎的表,这些算法的工作方式如下:
-
COPY
:NDB
创建表的副本并对其进行更改;然后,NDB Cluster 处理程序将数据在表的旧版本和新版本之间复制。随后,NDB
删除旧表并重命名新表。这有时也称为 “复制” 或 “离线”
ALTER TABLE
。 -
INPLACE
:数据节点进行所需的更改;NDB Cluster 处理程序不复制数据或以其他方式参与。这有时也称为 “非复制” 或 “在线”
ALTER TABLE
。 -
INSTANT
:NDB
不支持。
更多信息,请参见章节 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
表除外)。 -
修改
ENUM
或SET
列的定义,通过在有效成员值的列表 末尾 添加新的枚举或集合成员,只要数据类型的存储大小不变。例如,向具有8个成员的SET
列添加一个成员会将每个值所需的存储空间从1个字节更改为2个字节;这需要进行表复制。在列表中间添加成员会导致现有成员重新编号,这也需要进行表复制。 -
更改空间列的定义以删除
SRID
属性。(添加或更改SRID
属性需要重建,并且不能就地进行,因为服务器必须验证所有值都具有指定的SRID
值。) -
更改列字符集,当满足以下条件时:
-
更改生成的列,当满足以下条件时:
-
对于
InnoDB
表,修改生成的存储列但不更改其类型、表达式或可空性的语句。 -
对于非
InnoDB
表,修改生成的存储列或虚拟列但不更改其类型、表达式或可空性的语句。
此类更改的一个示例是对列注释的更改。
-
-
-
重命名索引。
-
对于
InnoDB
和NDB
表,添加或删除二级索引。请参见 第 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 操作”。 -
添加或删除虚拟列。
-
添加或删除列默认值。
-
更改索引类型。
-
重命名表。与上面针对
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 VALIDATION
和 WITH 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 ... TABLESPACE
或 IMPORT ... PARTITION ... TABLESPACE
的 ALTER TABLE
不会创建任何临时表或临时分区文件。
使用 ADD PARTITION
、DROP PARTITION
、COALESCE PARTITION
、REBUILD PARTITION
或 REORGANIZE PARTITION
的 ALTER TABLE
不会创建临时表(除非与 NDB
表一起使用);但是,这些操作可以并且确实会创建临时分区文件。
RANGE
或 LIST
分区的 ADD
或 DROP
操作是立即操作或几乎立即操作。 HASH
或 KEY
分区的 ADD
或 COALESCE
操作会在所有分区之间复制数据,除非使用了 LINEAR HASH
或 LINEAR KEY
;这实际上与创建新表相同,尽管 ADD
或 COALESCE
操作是按分区执行的。 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
是 MySQL 对标准 SQL 的扩展。col_name
要在表行中的特定位置添加列,请使用 FIRST
或 AFTER
。默认是在最后添加列。col_name
如果一个表只包含一列,则不能删除该列。如果你的目的是删除表,请使用 DROP TABLE
语句。
如果从表中删除列,则这些列也会从它们所属的任何索引中删除。如果组成索引的所有列都被删除,则索引也会被删除。如果你使用 CHANGE
或 MODIFY
来缩短存在索引的列,并且生成的列长度小于索引长度,MySQL 会自动缩短索引。
对于 ALTER TABLE ... ADD
,如果列具有使用非确定性函数的表达式默认值,则该语句可能会产生警告或错误。有关更多信息,请参阅 第 13.6 节,“数据类型默认值”,以及 第 19.1.3.7 节,“使用 GTID 进行复制的限制”。
重命名、重新定义和重新排序列
CHANGE
、MODIFY
、RENAME COLUMN
和 ALTER
子句允许更改现有列的名称和定义。它们具有以下比较特征:
-
CHANGE
:-
可以重命名列并更改其定义,或两者兼而有之。
-
比
MODIFY
或RENAME COLUMN
具有更多功能,但代价是某些操作不太方便。CHANGE
要求在不重命名列的情况下命名两次,并且如果只重命名列,则需要重新指定列定义。 -
使用
FIRST
或AFTER
可以对列重新排序。
-
-
MODIFY
:-
可以更改列定义,但不能更改其名称。
-
比
CHANGE
更方便,可以在不重命名的情况下更改列定义。 -
使用
FIRST
或AFTER
可以对列进行重新排序。
-
-
RENAME COLUMN
:-
可以更改列名称,但不能更改其定义。
-
比
CHANGE
更方便,可以在不更改定义的情况下重命名列。
-
-
ALTER
: 仅用于更改列的默认值。
CHANGE
是标准 SQL 的 MySQL 扩展。 MODIFY
和 RENAME COLUMN
是为了与 Oracle 兼容而进行的 MySQL 扩展。
要更改列以同时更改其名称和定义,请使用 CHANGE
,并指定新旧名称和新定义。 例如,要将 INT NOT NULL
列的名称从 a
更改为 b
,并将其定义更改为使用 BIGINT
数据类型,同时保留 NOT NULL
属性,请执行以下操作:
ALTER TABLE t1 CHANGE a b BIGINT NOT NULL;
要更改列定义而不是其名称,请使用 CHANGE
或 MODIFY
。 使用 CHANGE
时,语法需要两个列名,因此必须指定两次相同的名称才能保持名称不变。 例如,要更改列 b
的定义,请执行以下操作:
ALTER TABLE t1 CHANGE b b INT NOT NULL;
MODIFY
更方便在不更改名称的情况下更改定义,因为它只需要一次列名:
ALTER TABLE t1 MODIFY b INT NOT NULL;
要更改列名而不是其定义,请使用 CHANGE
或 RENAME 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;
通常,您不能将列重命名为表中已存在的名称。 但是,有时情况并非如此,例如,当您交换名称或通过循环移动名称时。 如果一个表有 a
、b
和 c
列,那么这些操作是有效的:
-- 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;
对于使用 CHANGE
或 MODIFY
进行的列定义更改,定义必须包含数据类型和应应用于新列的所有属性,但索引属性(如 PRIMARY KEY
或 UNIQUE
)除外。 原始定义中存在但未为新定义指定的属性不会被继承。 假设列 col1
定义为 INT UNSIGNED DEFAULT 1 COMMENT 'my column'
,您按如下方式修改该列,意图仅将 INT
更改为 BIGINT
:
ALTER TABLE t1 MODIFY col1 BIGINT;
该语句将数据类型从 INT
更改为 BIGINT
,但它也删除了 UNSIGNED
、DEFAULT
和 COMMENT
属性。若要保留它们,语句必须明确包含它们:
ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';
对于使用 CHANGE
或 MODIFY
进行的数据类型更改,MySQL 会尝试尽可能将现有列值转换为新类型。
此转换可能会导致数据更改。例如,如果缩短字符串列,则值可能会被截断。为了防止在转换为新数据类型会导致数据丢失的情况下操作成功,请在使用 ALTER TABLE
之前启用严格 SQL 模式(参见 第 7.1.11 节“服务器 SQL 模式”)。
如果使用 CHANGE
或 MODIFY
缩短存在索引的列,并且生成的列长度小于索引长度,则 MySQL 会自动缩短索引。
对于由 CHANGE
或 RENAME COLUMN
重命名的列,MySQL 会自动将以下引用重命名为重命名的列:
-
引用旧列的索引,包括不可见索引和已禁用的
MyISAM
索引。 -
引用旧列的外键。
对于由 CHANGE
或 RENAME COLUMN
重命名的列,MySQL 不会自动将以下引用重命名为重命名的列:
-
引用重命名列的生成列和分区表达式。必须使用
CHANGE
在与重命名列相同的ALTER TABLE
语句中重新定义此类表达式。 -
引用重命名列的视图和存储程序。必须手动更改这些对象的定义以引用新列名。
要在表中对列重新排序,请在 CHANGE
或 MODIFY
操作中使用 FIRST
和 AFTER
。
ALTER ... SET DEFAULT
或 ALTER ... DROP DEFAULT
分别为列指定新的默认值或删除旧的默认值。如果删除了旧的默认值并且该列可以为 NULL
,则新的默认值为 NULL
。如果该列不能为 NULL
,则 MySQL 会分配一个默认值,如 第 13.6 节“数据类型默认值” 中所述。
ALTER ... SET VISIBLE
和 ALTER ... SET INVISIBLE
允许更改列可见性。参见 第 15.1.20.10 节“不可见列”。
主键 和 索引
DROP PRIMARY KEY
删除主键。如果没有主键,则会发生错误。有关主键性能特征的信息,尤其是对于InnoDB
表,请参阅第 10.3.2 节“主键优化”。
如果启用了sql_require_primary_key
系统变量,则尝试删除主键会产生错误。
如果向表中添加UNIQUE INDEX
或PRIMARY 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
重命名索引。这是 MySQL 对标准 SQL 的扩展。表的内容保持不变。old_index_name
TO new_index_name
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
权限。
当非唯一索引被禁用时,它们会被诸如 SELECT
和 EXPLAIN
之类的语句忽略,否则会使用它们。
在 ALTER TABLE
语句之后,可能需要运行 ANALYZE TABLE
来更新索引基数信息。参见 第 15.7.7.23 节,“SHOW INDEX 语句”。
ALTER INDEX
操作允许索引变为可见或不可见。优化器不会使用不可见索引。索引可见性的修改适用于除主键(显式或隐式)之外的索引,并且不能使用 ALGORITHM=INSTANT
执行。此功能是存储引擎中立的(支持任何引擎)。有关更多信息,请参见 第 10.3.12 节,“不可见索引”。
外键和其他约束
FOREIGN KEY
和 REFERENCES
子句受 InnoDB
和 NDB
存储引擎支持,它们实现了 ADD [CONSTRAINT [
。参见 第 15.1.20.5 节,“FOREIGN KEY 约束”。对于其他存储引擎,这些子句会被解析但会被忽略。symbol
]] FOREIGN KEY [index_name
] (...) REFERENCES ... (...)
对于 ALTER TABLE
,与 CREATE TABLE
不同,如果给出 index_name
,ADD 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 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 中,每个约束类型在每个模式中都有自己的命名空间。因此,每种约束类型的名称在每个模式中必须是唯一的,但不同类型的约束可以具有相同的名称。当多个约束具有相同的名称时,DROP CONSTRAINT
和ADD 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
约束名称解释为内部生成的名称。
修改字符集
要将表默认字符集和所有字符列(CHAR
、VARCHAR
、TEXT
)更改为新的字符集,请使用如下语句:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
该语句还会更改所有字符列的排序规则。如果您没有指定 COLLATE
子句来指示要使用的排序规则,则该语句将使用字符集的默认排序规则。如果此排序规则不适合预期的表使用(例如,如果它将从区分大小写的排序规则更改为不区分大小写的排序规则),请明确指定排序规则。
对于数据类型为 VARCHAR
或 TEXT
类型之一的列,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
,则 CHAR
、VARCHAR
和 TEXT
列将转换为其相应的二进制字符串类型(BINARY
、VARBINARY
、BLOB
)。这意味着这些列不再具有字符集,并且后续的 CONVERT TO
操作不再适用于它们。
如果 CONVERT TO CHARACTER SET
操作中的 charset_name
是 DEFAULT
,则将使用由 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
列转换时没有进行转换。
要仅更改表的 默认 字符集,请使用以下语句:
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 CASCADE
或 ON UPDATE CASCADE
操作可能会损坏引用表中的数据,因为在这些操作期间会发生隐式转换(Bug #45290、Bug #74816)。
导入InnoDB表
使用自己的 文件-每-表 表空间创建的 InnoDB
表可以通过 DISCARD TABLEPACE
和 IMPORT TABLESPACE
语句从备份或从其他 MySQL 服务器实例导入。参见 第 17.6.1.3 节,“导入 InnoDB 表”。
MyISAM表的行顺序
ORDER BY
使您能够创建按特定顺序排列的新表。当您知道大多数时候会以特定顺序查询行时,此选项特别有用。在对表进行重大更改后使用此选项,您也许可以获得更高的性能。在某些情况下,如果表按您希望稍后对其进行排序的列排序,则可能会使 MySQL 更容易进行排序。
在插入和删除之后,该表不会保持指定的顺序。
ORDER BY
语法允许指定一个或多个列名进行排序,每个列名后面可以选择跟 ASC
或 DESC
以分别指示升序或降序排序。默认为升序。仅允许列名称作为排序条件;不允许使用任意表达式。此子句应在任何其他子句之后最后给出。
ORDER BY
对 InnoDB
表没有意义,因为 InnoDB
始终根据 聚簇索引 对表行进行排序。
当用于分区表时,ALTER TABLE ... ORDER BY
仅对每个分区内的行进行排序。
分区选项
partition_options
表示可用于分区表的选项,用于重新分区,添加、删除、丢弃、导入、合并和拆分分区,以及执行分区维护。
ALTER TABLE
语句除了其他 alter 规范之外,还可以包含 PARTITION BY
或 REMOVE PARTITIONING
子句,但 PARTITION BY
或 REMOVE PARTITIONING
子句必须在任何其他规范之后最后指定。 ADD PARTITION
、DROP PARTITION
、DISCARD PARTITION
、IMPORT PARTITION
、COALESCE PARTITION
、REORGANIZE PARTITION
、EXCHANGE PARTITION
、ANALYZE PARTITION
、CHECK PARTITION
和 REPAIR PARTITION
选项不能与单个 ALTER TABLE
中的其他 alter 规范组合,因为上面列出的选项作用于单个分区。
关于分区选项的更多信息,请参阅 第 15.1.20 节,“CREATE TABLE 语句”,以及 第 15.1.9.1 节,“ALTER TABLE 分区操作”。有关 ALTER TABLE ... EXCHANGE PARTITION
语句的信息和示例,请参阅 第 26.3.3 节,“使用表交换分区和子分区”。