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
相同的ADD
和CHANGE
語法。如需更多資訊,請參閱 第 15.1.20 節,「CREATE TABLE 語法」。除了
RENAME COLUMN
之外,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.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 語法」。但是,ALTER TABLE
會忽略作為資料表選項給定的 DATA DIRECTORY
和 INDEX DIRECTORY
。ALTER TABLE
僅允許它們作為分割區選項,並要求您具有 FILE
權限。
搭配使用資料表選項與 ALTER TABLE
提供了一種變更單一資料表特性的便捷方式。例如:
如果
t1
目前不是InnoDB
資料表,此語法會將其儲存引擎變更為InnoDB
ALTER TABLE t1 ENGINE = InnoDB;
請參閱 第 17.6.1.5 節,「將資料表從 MyISAM 轉換為 InnoDB」,了解將資料表切換至
InnoDB
儲存引擎時的注意事項。當您指定
ENGINE
子句時,ALTER TABLE
會重建資料表。即使資料表已經具有指定的儲存引擎,情況也是如此。在現有的
InnoDB
資料表上執行ALTER TABLE
會執行 「null」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
子句,則不允許透過將資料表移至不同的資料表空間或變更儲存引擎來變更資料表加密。如果資料表使用的儲存引擎不支援加密,則不允許指定
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 在表空間之間移動資料表。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
選項,以控制資料表的分割平衡(片段計數類型)、從任何副本讀取功能、完整複寫或這些的任何組合,作為ALTER TABLE
陳述式中的資料表註解的一部分,其方式與CREATE TABLE
相同,如下範例所示ALTER TABLE t1 COMMENT = "NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";
也可以在
ALTER TABLE
陳述式中為NDB
資料表的欄位設定NDB_COMMENT
選項,如下所示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 會將 ALGORITHM=INSTANT
用於儲存引擎,以及支援它的 ALTER TABLE
子句。否則,會使用 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
子句的操作的並行性,方法是指定 LOCK=EXCLUSIVE
,這會阻止 DML 和查詢。如需更多資訊,請參閱並行控制。
若要強制 ALTER TABLE
操作使用 COPY
演算法(否則不會使用它),請指定 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
屬性可以在不重建表格的情況下就地完成。
支援 INSTANT
演算法的 ALTER TABLE
操作包括
新增欄位。此功能稱為「「即時
ADD COLUMN
」」。有適用限制。請參閱 第 17.12.1 節「線上 DDL 操作」。捨棄欄位。此功能稱為「「即時
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
操作。此轉換無法使用 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 Server 相同的 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
會移除索引。這是標準 SQL 的 MySQL 延伸。請參閱 第 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
會重新命名索引。這是標準 SQL 的 MySQL 延伸。表格的內容保持不變。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 節「外鍵約束」。對於其他儲存引擎,子句會被剖析但會被忽略。symbol
]] FOREIGN KEY [index_name
] (...) REFERENCES ... (...)
對於 ALTER TABLE
,與 CREATE TABLE
不同,ADD FOREIGN KEY
會忽略給定的 index_name
,並使用自動產生的外鍵名稱。作為因應措施,請包含 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
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
欄位有兩個長度位元組,用於儲存欄位中值的位元組長度,最大值為 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
操作不適用於它們。
如果 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
,則由於在這些操作期間發生的隱含轉換,ON DELETE CASCADE
或 ON UPDATE CASCADE
操作可能會損壞參照表格中的資料 (Bug #45290, Bug #74816)。
匯入 InnoDB 表格
使用 DISCARD TABLESPACE
和 IMPORT TABLESPACE
子句,可以從備份或從另一個 MySQL 伺服器執行個體匯入在其自己的file-per-table 表空間中建立的 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
陳述式中,可以包含 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
中與其他變更規格組合使用,因為剛列出的選項會作用於個別的分割區。
有關分割區選項的更多資訊,請參閱第 15.1.20 節,「CREATE TABLE 陳述式」和第 15.1.9.1 節,「ALTER TABLE 分割區操作」。有關 ALTER TABLE ... EXCHANGE PARTITION
陳述式的資訊和範例,請參閱第 26.3.3 節,「與表格交換分割區和子分割區」。