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.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;
如需將資料表切換至
InnoDB
儲存引擎時的注意事項,請參閱第 17.6.1.5 節,「將資料表從 MyISAM 轉換為 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
子句,則不允許透過將資料表移動至不同的資料表空間或變更儲存引擎來變更資料表加密。如果資料表使用不支援加密的儲存引擎,則不允許指定值不是
'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
語法不支援將資料表從暫時資料表空間移動至持續性資料表空間。DATA DIRECTORY
子句(在CREATE TABLE ... TABLESPACE
中支援)在ALTER TABLE ... TABLESPACE
中不受支援,並且如果指定則會忽略。如需有關
TABLESPACE
選項的功能和限制的詳細資訊,請參閱CREATE TABLE
。
MySQL NDB Cluster 9.0 支援設定
NDB_TABLE
選項,以控制資料表的分割平衡(片段計數類型)、從任何複本讀取功能、完整複寫或這些選項的任何組合,作為ALTER TABLE
陳述式資料表註解的一部分,其方式與CREATE TABLE
相同,如下列範例所示:ALTER TABLE t1 COMMENT = "NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";
也可以設定
NDB
資料行 的NDB_COMMENT
選項,作為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 和查詢。如需更多資訊,請參閱 並行控制。
若要強制 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
表格,修改產生的儲存欄位的陳述式,但不會變更其類型、運算式或可為 Null 性。對於非
InnoDB
資料表,修改已產生儲存或虛擬欄位的陳述式,但不會變更其類型、運算式或是否可為 NULL 的屬性。
這類變更的一個範例是變更欄位註解。
重新命名索引。
新增或刪除次要索引,適用於
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 9.0 支援使用標準 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 不會自動將這些參考重新命名為已重新命名的欄位
參照已重新命名欄位的產生欄位和分割區運算式。您必須在與重新命名欄位的同一個
ALTER TABLE
陳述式中使用CHANGE
重新定義此類運算式。參照已重新命名欄位的檢視表和預存程式。您必須手動變更這些物件的定義,使其參照新的欄位名稱。
若要重新排列資料表內的欄位,請在 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
不同,如果指定 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
操作不適用於它們。
如果 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 資料表
在自己的單獨檔案表空間中建立的 InnoDB
資料表,可以使用 DISCARD TABLESPACE
和 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
語句可以在其他變更規範中包含 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 節,「使用資料表交換分割區和子分割區」。