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
,需要对表拥有ALTER
、CREATE
和INSERT
权限。重命名表需要对旧表拥有ALTER
和DROP
权限,对新表拥有ALTER
、CREATE
和INSERT
权限。 -
在表名后指定要执行的修改操作。如果不指定任何操作,
ALTER TABLE
什么也不做。 -
许多允许的修改语法与
CREATE TABLE
语句的子句类似。column_definition
子句使用与CREATE TABLE
相同的语法来执行第15.1.20节,“CREATE TABLE 语句”中有更多信息。 -
关键字
COLUMN
可选,除非是RENAME COLUMN
(以区分列重命名操作和表重命名操作)。 -
ADD
、ALTER
、DROP
、CHANGE
子句可以在同一个ALTER TABLE
语句中,使用逗号分隔。这是MySQL的扩展功能,标准SQL只允许每个语句中一个子句。例如,要在单个语句中删除多列,可以这样做:ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
-
如果存储引擎不支持某个
ALTER TABLE
操作,可能会出现警告。这些警告可以使用SHOW WARNINGS
显示。关于ALTER TABLE
的 troubleshooting,见第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
支持在JSON列上添加多值索引,使用key_part
指定可以以形式(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
作为表选项,但允许它们作为分区选项,并且需要您拥有FILE
特权。
使用表选项与ALTER TABLE
提供了改变单个表特性的便捷方式。例如:
-
如果
t1
当前不是InnoDB
表,这个语句将其存储引擎更改为InnoDB
:ALTER TABLE t1 ENGINE = InnoDB;
-
关于将表从MyISAM转换到
InnoDB
存储引擎的考虑见第17.6.1.5节,“从 MyISAM 转换到 InnoDB”。 -
当您指定
ENGINE
子句时,ALTER TABLE
重建表。这也适用于已经具有指定存储引擎的表。 -
ALTER TABLE
对现有tbl_name
ENGINE=INNODBInnoDB
表执行“空”ALTER 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
表的页面级别数据加密。需要安装和配置密钥ring插件以启用加密。如果启用了
table_encryption_privilege_check
变量,需要TABLE_ENCRYPTION_ADMIN
特权以使用与默认架构加密设置不同的ENCRYPTION
子句。ENCRYPTION
也支持在公共表空间中的表。在公共表空间中,表和表空间加密必须一致。
通过移动表或更改存储引擎来更改表加密不允许,不得不指定
ENCRYPTION
子句。如果表使用不支持加密的存储引擎,指定
ENCRYPTION
子句的值不是'N'
或''
是不可允许的。尝试在不支持加密的存储引擎中创建一个没有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 ... TABLESPACE
操作总是导致全表重建,即使TABLESPACE
属性没有从前一个值改变。 -
ALTER TABLE ... TABLESPACE
语句不支持将表从临时表空间移到持久表空间。 -
DATA DIRECTORY
子句,支持CREATE TABLE ... TABLESPACE
,但不支持ALTER TABLE ... TABLESPACE
,如果指定将被忽略。 -
关于
CREATE TABLE
的TABLESPACE
选项能力和限制,详见.
-
-
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_ATTRIBUTE
和SECONDARY_ENGINE_ATTRIBUTE
选项用于指定主、副存储引擎的表、列和索引属性。这些选项保留供将来使用。索引不能被修改,需要先删除再添加,所有可以在单个ALTER TABLE
语句中进行。
要验证表选项是否被更改为预期的方式,可以使用SHOW CREATE TABLE
,或者查询信息架构TABLES
表。
ALTER TABLE
操作使用以下算法之一进行处理:
-
COPY
:对原始表进行copy,逐行将数据从原始表复制到新表。并发DML不允许。 -
INPLACE
:操作避免了表数据的copy,但可能在执行过程中重建表。在准备和执行阶段,可能会短暂地获取表独占锁。通常情况下,支持并发DML。 -
INSTANT
:只修改数据字典中的元数据。在执行阶段,可能会短暂地获取表独占锁。表数据不受影响,使操作实时完成。支持并发DML。
对于使用NDB
存储引擎的表,这些算法工作方式如下:
-
COPY
:NDB
创建了表的副本,然后将数据从原始表复制到新表。最后,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
。
使用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 theInnoDB
online DDL feature. See Section 17.12.1, “Online DDL Operations”. -
重命名一个表。MySQL不复制文件,直接将对应的
tbl_name
文件重命名。(也可以使用RENAME TABLE
语句来重命名表。见第15.1.36节,“RENAME TABLE 语句”。对重命名后的表授予的特权不自动迁移到新名称,需要手动修改。 -
只修改表元数据的操作这些操作是立即完成的,因为服务器不触摸表内容。只修改元数据的操作包括:
-
重命名一个列。在 NDB 集群中,这个操作也可以在线执行。
-
更改一个列的默认值(除了
NDB
表). -
修改一个
ENUM
或SET
列的定义,添加新的枚举值或集合成员到末尾有效值列表中,只要数据类型存储大小不变。例如,对于一个SET
列添加成员,需要的每个值存储空间从1字节变为2字节;在列表中间添加成员会导致现有成员重新编号,这也需要复制表。 -
更改空间列的定义以删除
SRID
属性。添加或更改SRID
属性需要重建,不能在原地完成,因为服务器必须验证所有值都具有指定的SRID
值。 -
更改列字符集,以下情况适用:
-
更改生成列,以下情况适用:
-
对于
InnoDB
表,修改存储的生成列但不改变其类型、表达式或可空性。 -
对于非
InnoDB
表,修改存储或虚拟列但不改变其类型、表达式或可空性。
例如,修改列注释。
-
-
-
重命名索引。
-
添加或删除次级索引,适用于
InnoDB
和NDB
表。见第17.12.1节,“在线DDL操作”. -
对于
NDB
表,添加和删除变长列上的索引操作。这些操作在线进行,不会阻塞大多数时间内的并发DML操作。见第25.6.12节,“NDB集群中的ALTER TABLE在线操作”. -
使用
ALTER INDEX
操作修改索引可见性。 -
修改包含生成列的表,生成列依赖于具有默认值的列,如果修改的列不参与生成列表达式。例如,单独修改一个列的
NULL
属性可以在不重建表的情况下完成。
ALTER TABLE
操作支持INSTANT
算法包括:
-
添加列。这个特性称为““
Instant
””。存在限制。见第17.12.1节,“在线DDL操作”.ADD COLUMN
-
删除列。这一特性称为“Instant
DROP COLUMN
”。存在限制。请参见第17.12.1节,“在线DDL操作”。 -
添加或删除虚拟列。
-
添加或删除列默认值。
-
更改索引类型。
-
重命名表格。同上述
ALGORITHM=INSTANT
所描述的限制。
关于支持ALGORITHM=INSTANT
操作的更多信息,请参见第17.12.1节,“在线DDL操作”。
ALTER TABLE
将MySQL 5.5的时间戳列升级到5.6格式,对于ADD COLUMN
、CHANGE COLUMN
、MODIFY COLUMN
、ADD INDEX
和FORCE
操作。由于表格需要重建,因此在这些情况下指定ALGORITHM=INPLACE
将导致错误,需要指定ALGORITHM=COPY
。
如果对一个多列索引执行ALTER TABLE
操作,用于将表按KEY
分区,但改变了列的顺序,那么只能使用ALGORITHM=COPY
。
WITHOUT VALIDATION
和WITH 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 ... TABLESPACE
或IMPORT ... PARTITION ... TABLESPACE
不创建临时表或临时分区文件。
ALTER TABLE
使用ADD PARTITION
、DROP PARTITION
、COALESCE PARTITION
、REBUILD PARTITION
或REORGANIZE PARTITION
不创建临时表(except 使用NDB
表),但是这些操作可以和会创建临时分区文件。
ADD
或DROP
操作用于RANGE
或LIST
分区是即时操作或非常快的操作;ADD
或COALESCE
操作用于HASH
或KEY
分区将数据从所有分区复制,除非使用了LINEAR HASH
或LINEAR KEY
;这等同于创建一个新表,但是ADD
或COALESCE
操作是按分区进行的。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
是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
更强大,但是在某些操作中需要付出更多代价。需要在不重命名列时指定列名称,且如果只重命名列则需要重新指定列定义。 -
可以使用
FIRST
或AFTER
来重新排列列。
-
-
MODIFY
:-
只能改变列定义,不改变其名称。
-
比
CHANGE
更方便地改变列定义而不重命名它。 -
可以使用
FIRST
或AFTER
来重新排列列。
-
-
RENAME COLUMN
:-
只能重命名列,不改变其定义。
-
比使用
CHANGE
更方便地重命名一个列而不改变其定义。
-
-
ALTER
: 只用于修改列的默认值。
CHANGE
是MySQL对标准SQL的扩展。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'
,你想将其修改为BIGINT
,那么该语句会将数据类型从INT
改为BIGINT
,同时也会丢弃UNSIGNED
、DEFAULT
和COMMENT
属性。为了保留它们,该语句必须包含它们的明确指定:
ALTER TABLE t1 MODIFY col1 BIGINT;
使用CHANGE
或MODIFY
修改数据类型时,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.
这次转换可能会改变数据。例如,如果您缩短字符串列,值可能被截断。在使用ALTER TABLE
之前,启用严格SQL模式,以防止转换操作结果导致数据丢失(见第7.1.11节,“服务器 SQL 模式”)。
如果使用CHANGE
或MODIFY
缩短存在索引的列,并且结果列长度小于索引长度,MySQL自动将索引缩短。
通过CHANGE
或RENAME COLUMN
重命名的列,MySQL自动重命名这些引用:
-
对旧列的索引,包括不可见索引和禁用MyISAM索引。
-
对旧列的外键。
通过CHANGE
或RENAME COLUMN
重命名的列,MySQL不自动重命名这些引用:
-
引用重命名列的生成列和分区表达式。您必须在同一个
ALTER TABLE
语句中重新定义这些表达式。 -
引用重命名列的视图和存储程序。您必须手动修改这些对象的定义,以引用新列名称。
要在表中重新排列列,使用FIRST
和AFTER
在CHANGE
或MODIFY
操作中。
ALTER ... SET DEFAULT
或ALTER ... DROP DEFAULT
指定列的新默认值或删除旧默认值,分别。如果旧默认值被删除且该列可以为NULL
,新的默认值为NULL
。如果该列不能为NULL
,MySQL将按照第13.6节,“数据类型默认值”中描述的方式分配默认值。
ALTER ... SET VISIBLE
和ALTER ... SET INVISIBLE
使列可见性可以被更改。请参阅第15.1.20.10节,“不可见列”。
Primary Keys and 索引
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
。
如果你对ALTER TABLE
一个MyISAM
表,所有非唯一索引将在单独的批次中创建(类似REPAIR TABLE
)。这应该使ALTER TABLE
在你有许多索引时速度更快。
MyISAM
表中,可以控制键更新。使用 ALTER TABLE ... DISABLE KEYS
告诉 MySQL 停止更新非唯一索引,然后使用 ALTER TABLE ... ENABLE KEYS
重新创建缺失的索引。MyISAM
使用特殊算法,速度远快于逐一插入键,所以在执行 bulk 插入操作前禁用键可以获得明显加速。使用 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节,“外键约束”。其他存储引擎则将子句解析但忽略。symbol
]] FOREIGN KEY [index_name
] (...) REFERENCES ... (...)
ALTER TABLE
,不同于CREATE TABLE
,ADD FOREIGN KEY
如果给出index_name
则忽略,并使用自动生成的外键名称。作为解决方案,请包含CONSTRAINT
子句指定外键名称:
ADD CONSTRAINT name FOREIGN KEY (....) ...
MySQL忽略inlineREFERENCES
语句,定义在列规范中的引用关系。MySQL只接受独立的FOREIGN KEY
语句中定义的REFERENCES
子句。
分区表不支持外键约束。这一限制不适用于第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 CONSTRAINT
和 ADD 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
子句来指明使用哪种排序规则,语句将使用默认的排序规则。如果这个排序规则对于表的预期用途不合适(例如,如果要从敏感排序规则变为不敏感排序规则),请指定排序规则。
对于具有VARCHAR
或TEXT
类型的列,CONVERT TO CHARACTER SET
会根据需要更改数据类型,以确保新的列足够存储原始列中的字符数。例如,一个TEXT
列有两个长度字节,用于存储该列的值的字节长度,最大为65535个字节。对于一个latin1
TEXT
列,每个字符需要一个字节,所以该列最多可以存储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 binary
CHAR
、VARCHAR
和TEXT
列将被转换为相应的二进制字符串类型(BINARY
、VARBINARY
、BLOB
)。这意味着这些列不再具有字符集,后续的CONVERT TO
操作对它们无效。
如果
charset_name
在CONVERT TO CHARACTER SET
操作中是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
后,可能会导致引用表中的数据损坏(Bug #45290,Bug #74816).
Importing InnoDB 表
可以使用文件-per-table表空间创建的InnoDB表,可以从备份或另一个MySQL服务器实例中导入,使用DISCARD TABLEPACE
和IMPORT TABLESPACE
子句。详见第17.6.1.3节,“导入InnoDB表”.
Row Order for MyISAM 表
ORDER BY
允许您在创建新表时,按照特定的顺序排列行。这个选项主要有用处是在您知道大多数情况下查询的行顺序时。使用这个选项后对表进行了主要修改,您可能可以获得更高的性能。在某些情况下,如果表按要排序的列已经排序,MySQL也可能会更容易排序。
删除和插入操作后,表不再保持指定的顺序。
ORDER BY
语法允许指定一个或多个列名来进行排序,每个列名可选地后跟ASC
或DESC
,分别表示升序和降序排列顺序,默认是升序。只允许列名作为排序标准;不允许任意表达式。该子句应该在其他子句后面。
ORDER BY
对于InnoDB
表无意义,因为InnoDB
总是根据聚簇索引来排序表行。
在分区表上使用 ALTER TABLE ... ORDER BY
时,只对每个分区进行行排序。
分区 Options
partition_options
表示与分区表相关的选项,可以用于重分区、添加、删除、丢弃、导入、合并和拆分分区,执行分区维护操作。
ALTER TABLE
语句可以包含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
语句中,因为这些选项都作用于单个分区。
关于分区选项的更多信息,见第15.1.20节,“CREATE TABLE 语句”和第15.1.9.1节,“ALTER TABLE 分区操作”。关于ALTER TABLE ... EXCHANGE PARTITION
语句的信息和示例,见第26.3.3节,“交换分区和子分区与表”。