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
子句,用逗号分隔。这是对标准 SQL 的 MySQL 扩展,它每个ALTER TABLE
语句只允许每个子句出现一次。例如,要在单个语句中删除多个列,请执行以下操作ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
如果存储引擎不支持尝试的
ALTER TABLE
操作,则可能会导致警告。可以使用SHOW WARNINGS
显示此类警告。请参见 第 15.7.7.41 节,“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 语句”。但是,当给出 DATA DIRECTORY
和 INDEX DIRECTORY
作为表选项时,ALTER TABLE
会忽略它们。 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
FORCEALTER 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';
将
ALTER TABLE
与TABLESPACE
选项一起使用,以在现有的 通用表空间、每个表一个文件 表空间和 系统表空间 之间移动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_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 集群中使用 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
表除外)。通过将新的枚举或集合成员添加到有效成员值列表的末尾来修改
ENUM
或SET
列的定义,只要数据类型的存储大小没有更改。例如,将成员添加到具有 8 个成员的SET
列会将每个值所需的存储空间从 1 字节更改为 2 字节;这需要复制表。在列表中间添加成员会导致对现有成员重新编号,这需要复制表。更改空间列的定义以删除
SRID
属性。(添加或更改SRID
属性需要重建,并且不能就地完成,因为服务器必须验证所有值是否都具有指定的SRID
值。)在满足以下条件时更改列字符集
在满足以下条件时更改生成的列
对于
InnoDB
表,修改生成的存储列但不更改其类型、表达式或可空性的语句。对于非
InnoDB
表,修改生成的存储列或虚拟列但不更改其类型、表达式或可空性的语句。
此类更改的一个示例是对列注释的更改。
重命名索引。
对于
InnoDB
和NDB
表,添加或删除辅助索引。请参见 第 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 操作”。添加或删除虚拟列。
添加或删除列默认值。
更改索引类型。
重命名表。应用与上述
ALGORITHM=INSTANT
相同的限制。
有关支持 ALGORITHM=INSTANT
的操作的更多信息,请参见 第 17.12.1 节,“在线 DDL 操作”。
对于 ADD COLUMN
、CHANGE COLUMN
、MODIFY COLUMN
、ADD INDEX
和 FORCE
操作,ALTER TABLE
会将 MySQL 5.5 时间类型列升级为 5.6 格式。此转换无法使用 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.4 支持使用与标准 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
是 MySQL 对标准 SQL 的扩展。 MODIFY
和 RENAME COLUMN
是 MySQL 为兼容 Oracle 而提供的扩展。
要更改列以同时更改其名称和定义,请使用 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 节“不可见索引”。
外键和其他约束
InnoDB
和 NDB
存储引擎支持 FOREIGN KEY
和 REFERENCES
子句,它们实现了 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 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 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;
要仅更改表的默认字符集,请使用以下语句
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
操作可能会损坏引用表中的数据,因为在这些操作期间发生了隐式转换(错误 #45290,错误 #74816)。
导入 InnoDB 表
可以使用DISCARD TABLEPACE
和IMPORT TABLESPACE
子句从备份或其他 MySQL 服务器实例导入在其自己的每个表一个文件表空间中创建的InnoDB
表。请参阅第 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 节“将分区和子分区与表交换”。