文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  ALTER TABLE 語句

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 陳述式還有幾個額外層面,將在本節的以下主題中說明:

資料表選項

table_options 表示可在 CREATE TABLE 陳述式中使用的資料表選項種類,例如 ENGINEAUTO_INCREMENTAVG_ROW_LENGTHMAX_ROWSROW_FORMATTABLESPACE

如需所有資料表選項的說明,請參閱第 15.1.20 節,「CREATE TABLE 陳述式」。但是,當給定資料表選項時,ALTER TABLE 會忽略 DATA DIRECTORYINDEX DIRECTORYALTER TABLE 僅允許將它們作為分割選項,並且要求您擁有 FILE 權限。

搭配 ALTER TABLE 使用資料表選項可提供一種方便的方式來變更單一資料表特性。例如:

  • 如果 t1 目前不是 InnoDB 資料表,此陳述式會將其儲存引擎變更為 InnoDB

    ALTER TABLE t1 ENGINE = InnoDB;
  • 若要變更 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;

    您無法將計數器重設為小於或等於目前使用中的值。對於 InnoDBMyISAM,如果該值小於或等於 AUTO_INCREMENT 資料行中目前的最大值,則該值會重設為目前的 AUTO_INCREMENT 資料行最大值加一。

  • 若要變更預設資料表字元集:

    ALTER TABLE t1 CHARACTER SET = utf8mb4;

    另請參閱變更字元集

  • 若要新增(或變更)資料表註解:

    ALTER TABLE t1 COMMENT = 'New table comment';
  • 使用 ALTER TABLETABLESPACE 選項,在現有的一般資料表空間每個資料表檔案資料表空間和系統資料表空間之間移動 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_ATTRIBUTESECONDARY_ENGINE_ATTRIBUTE 選項用於指定主要和次要儲存引擎的表格、欄位和索引屬性。這些選項保留供未來使用。索引屬性無法變更。必須刪除索引,然後以所需的變更重新新增,這可以在單一 ALTER TABLE 陳述式中執行。

若要驗證表格選項是否已如預期變更,請使用 SHOW CREATE TABLE,或查詢 Information Schema TABLES 表格。

效能和空間需求

ALTER TABLE 操作會使用下列其中一種演算法處理

  • COPY:操作會在原始表格的副本上執行,並且表格資料會逐列從原始表格複製到新表格。不允許並行 DML。

  • INPLACE:操作會避免複製表格資料,但可能會就地重建表格。在操作的準備和執行階段,可能會短暫取得表格的獨佔中繼資料鎖定。通常支援並行 DML。

  • INSTANT:操作只會修改資料字典中的中繼資料。在操作的執行階段,可能會短暫取得表格的獨佔中繼資料鎖定。表格資料不受影響,因此操作是即時的。允許並行 DML。

對於使用 NDB 儲存引擎的表格,這些演算法的運作方式如下

  • COPYNDB 會建立表格的副本並加以變更;然後 NDB Cluster 處理常式會在舊版和新版的表格之間複製資料。隨後,NDB 會刪除舊表格並重新命名新表格。

    這有時也稱為 複製離線 ALTER TABLE

  • INPLACE:資料節點會進行所需的變更;NDB Cluster 處理常式不會複製資料或以其他方式參與。

    這有時也稱為 非複製線上 ALTER TABLE

  • INSTANTNDB 不支援。

如需更多資訊,請參閱第 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 設定與值不是 DEFAULTALGORITHM 子句之間發生衝突,則 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 表格除外)。

    • 透過將新的列舉或設定成員新增至有效成員值清單的結尾,修改 ENUMSET 欄位的定義,只要資料類型的儲存大小不變更即可。例如,將成員新增至具有 8 個成員的 SET 欄位會將每個值的必要儲存空間從 1 個位元組變更為 2 個位元組;這需要表格副本。在清單中間新增成員會導致重新編號現有成員,這需要表格副本。

    • 變更空間欄位的定義以移除 SRID 屬性。(新增或變更 SRID 屬性需要重建,而且無法就地完成,因為伺服器必須驗證所有值是否具有指定的 SRID 值。)

    • 在下列情況下,變更欄位字元集

      • 欄位資料類型為 CHARVARCHARTEXT 類型或 ENUM

      • 字元集變更從 utf8mb3 變更為 utf8mb4,或從任何字元集變更為 binary

      • 欄位上沒有索引。

    • 在下列情況下,變更產生的欄位

      • 對於 InnoDB 表格,修改產生的儲存欄位的陳述式,但不會變更其類型、運算式或可為 Null 性。

      • 對於非 InnoDB 資料表,修改已產生儲存或虛擬欄位的陳述式,但不會變更其類型、運算式或是否可為 NULL 的屬性。

      這類變更的一個範例是變更欄位註解。

  • 重新命名索引。

  • 新增或刪除次要索引,適用於 InnoDBNDB 資料表。請參閱第 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 操作」

  • 新增或刪除虛擬欄位。

  • 新增或刪除欄位的預設值。

  • 修改 ENUMSET 欄位的定義。其限制與上述針對 ALGORITHM=INSTANT 所述的限制相同。

  • 變更索引類型。

  • 重新命名資料表。其限制與上述針對 ALGORITHM=INSTANT 所述的限制相同。

如需有關支援 ALGORITHM=INSTANT 的操作的詳細資訊,請參閱第 17.12.1 節「線上 DDL 操作」

ALTER TABLE 會將 MySQL 5.5 的時間欄位升級為 5.6 格式,以用於 ADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEXFORCE 操作。由於必須重建資料表,因此無法使用 INPLACE 演算法執行此轉換,因此在這些情況下指定 ALGORITHM=INPLACE 會導致錯誤。如有必要,請指定 ALGORITHM=COPY

如果使用 KEY 來分割資料表的多欄索引上的 ALTER TABLE 操作變更了欄位的順序,則只能使用 ALGORITHM=COPY 來執行。

WITHOUT VALIDATIONWITH 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 ... TABLESPACEIMPORT ... PARTITION ... TABLESPACEALTER TABLE 不會建立任何臨時資料表或臨時分割區檔案。

使用 ADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREBUILD PARTITIONREORGANIZE PARTITIONALTER TABLE 不會建立臨時資料表(與 NDB 資料表搭配使用時除外);但是,這些操作可能會建立臨時分割區檔案。

針對 RANGELIST 分割區的 ADDDROP 操作是立即或幾乎立即的操作。針對 HASHKEY 分割區的 ADDCOALESCE 操作會複製所有分割區之間的資料,除非使用了 LINEAR HASHLINEAR KEY;這實際上與建立新的資料表相同,儘管 ADDCOALESCE 操作是按分割區執行的。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 col_name 是 MySQL 對標準 SQL 的延伸。

若要在資料表列中的特定位置新增欄位,請使用 FIRSTAFTER col_name。預設是將欄位新增到最後。

如果資料表只包含一個欄位,則無法刪除該欄位。如果您打算移除資料表,請改用 DROP TABLE 陳述式。

如果從資料表中刪除欄位,則也會從它們所屬的任何索引中移除這些欄位。如果組成索引的所有欄位都被刪除,則索引也會被刪除。如果您使用 CHANGEMODIFY 來縮短索引存在的欄位,且產生的欄位長度小於索引長度,則 MySQL 會自動縮短索引。

對於 ALTER TABLE ... ADD,如果欄位具有使用非決定性函式的運算式預設值,則該陳述式可能會產生警告或錯誤。如需更多資訊,請參閱第 13.6 節「資料類型預設值」第 19.1.3.7 節「使用 GTID 進行複寫的限制」

重新命名、重新定義和重新排序欄位

CHANGEMODIFYRENAME COLUMNALTER 子句可讓您變更現有欄位的名稱和定義。它們具有以下比較特性

  • CHANGE:

    • 可以重新命名欄位並變更其定義,或兩者皆可。

    • 功能比 MODIFYRENAME COLUMN 更強大,但某些操作的便利性較差。CHANGE 如果不重新命名欄位,則需要命名欄位兩次,如果只重新命名欄位,則需要重新指定欄位定義。

    • 透過 FIRSTAFTER,可以重新排序欄位。

  • MODIFY:

    • 可以變更欄位定義,但不能變更其名稱。

    • 變更欄位定義但不重新命名時,比 CHANGE 更方便。

    • 透過 FIRSTAFTER,可以重新排序欄位。

  • RENAME COLUMN:

    • 可以變更欄位名稱,但不能變更其定義。

    • 重新命名欄位但不變更其定義時,比 CHANGE 更方便。

  • ALTER:僅用於變更欄位預設值。

CHANGE 是 MySQL 對標準 SQL 的延伸。MODIFYRENAME COLUMN 是 MySQL 為了與 Oracle 相容的延伸。

若要變更欄位以同時變更其名稱和定義,請使用 CHANGE,指定舊名稱和新名稱以及新定義。例如,若要將 INT NOT NULL 欄位從 a 重新命名為 b,並變更其定義以使用 BIGINT 資料類型,同時保留 NOT NULL 屬性,請執行此操作

ALTER TABLE t1 CHANGE a b BIGINT NOT NULL;

若要變更欄位定義但不變更其名稱,請使用 CHANGEMODIFY。使用 CHANGE 時,語法需要兩個欄位名稱,因此您必須指定相同的名稱兩次,以保持名稱不變。例如,若要變更欄位 b 的定義,請執行此操作

ALTER TABLE t1 CHANGE b b INT NOT NULL;

MODIFY 更方便變更定義而不變更名稱,因為它只需要欄位名稱一次

ALTER TABLE t1 MODIFY b INT NOT NULL;

若要變更欄位名稱但不變更其定義,請使用 CHANGERENAME 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;

一般來說,您不能將欄位重新命名為資料表中已存在的名稱。但是,有時情況並非如此,例如當您交換名稱或透過循環移動它們時。如果資料表具有名為 abc 的欄位,則這些是有效的操作

-- 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;

對於使用 CHANGEMODIFY 的欄位定義變更,定義必須包含資料類型和所有應套用於新欄位的屬性,除了索引屬性(例如 PRIMARY KEYUNIQUE)。原始定義中存在但未指定為新定義的屬性不會被帶入。假設欄位 col1 定義為 INT UNSIGNED DEFAULT 1 COMMENT 'my column',並且您如下修改該欄位,目的僅在於將 INT 變更為 BIGINT

ALTER TABLE t1 MODIFY col1 BIGINT;

該陳述式將資料類型從 INT 變更為 BIGINT,但也刪除了 UNSIGNEDDEFAULTCOMMENT 屬性。若要保留這些屬性,該陳述式必須明確包含它們

ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';

對於使用 CHANGEMODIFY 的資料類型變更,MySQL 會盡可能嘗試將現有的欄位值轉換為新類型。

警告

此轉換可能會導致資料變更。例如,如果您縮短字串欄位,值可能會被截斷。若要防止在轉換為新資料類型會導致資料遺失時作業成功,請在使用 ALTER TABLE 之前啟用嚴格 SQL 模式(請參閱 第 7.1.11 節「伺服器 SQL 模式」)。

如果您使用 CHANGEMODIFY 來縮短欄位,而該欄位上存在索引,且縮短後的欄位長度小於索引長度,則 MySQL 會自動縮短索引。

對於透過 CHANGERENAME COLUMN 重新命名的欄位,MySQL 會自動將這些參考重新命名為已重新命名的欄位

  • 參照舊欄位的索引,包括隱形索引和停用的 MyISAM 索引。

  • 參照舊欄位的外鍵。

對於透過 CHANGERENAME COLUMN 重新命名的欄位,MySQL 不會自動將這些參考重新命名為已重新命名的欄位

  • 參照已重新命名欄位的產生欄位和分割區運算式。您必須在與重新命名欄位的同一個 ALTER TABLE 陳述式中使用 CHANGE 重新定義此類運算式。

  • 參照已重新命名欄位的檢視表和預存程式。您必須手動變更這些物件的定義,使其參照新的欄位名稱。

若要重新排列資料表內的欄位,請在 CHANGEMODIFY 操作中使用 FIRSTAFTER

ALTER ... SET DEFAULTALTER ... DROP DEFAULT 分別指定欄位的新預設值或移除舊的預設值。如果移除舊的預設值且欄位可以為 NULL,則新的預設值為 NULL。如果欄位不能為 NULL,則 MySQL 會按照 第 13.6 節「資料類型預設值」中所述指派預設值。

ALTER ... SET VISIBLEALTER ... SET INVISIBLE 可讓變更欄位的可見性。請參閱 第 15.1.20.10 節「隱形欄位」

主鍵和索引

DROP PRIMARY KEY 會刪除主鍵。如果沒有主鍵,則會發生錯誤。如需有關主鍵的效能特性資訊,特別是針對 InnoDB 資料表,請參閱 第 10.3.2 節「主鍵最佳化」

如果啟用 sql_require_primary_key 系統變數,則嘗試刪除主鍵會產生錯誤。

如果您將 UNIQUE INDEXPRIMARY 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 old_index_name TO new_index_name 會重新命名索引。這是標準 SQL 的 MySQL 擴充功能。資料表的內容保持不變。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 權限。

當非唯一索引停用時,對於否則會使用它們的陳述式(例如 SELECTEXPLAIN)會忽略它們。

ALTER TABLE 陳述式之後,可能需要執行 ANALYZE TABLE 來更新索引基數資訊。請參閱 第 15.7.7.23 節「SHOW INDEX 陳述式」

ALTER INDEX 操作允許將索引設定為可見或隱形。最佳化工具不會使用隱形索引。索引可見性的修改適用於主鍵(明確或隱含)以外的索引,並且無法使用 ALGORITHM=INSTANT 執行。此功能是儲存引擎中性的(適用於任何引擎)。如需更多資訊,請參閱 第 10.3.12 節「隱形索引」

外鍵和其他約束

FOREIGN KEYREFERENCES 子句由 InnoDBNDB 儲存引擎支援,這些引擎實作 ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (...) REFERENCES ... (...)。請參閱 第 15.1.20.5 節「外鍵約束」。對於其他儲存引擎,子句會被剖析但忽略。

對於 ALTER TABLE,與 CREATE TABLE 不同,如果指定 index_nameADD 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 CHECKALTER 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 CONSTRAINTADD 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 約束名稱解讀為內部產生的名稱。

變更字元集

若要將表格預設字元集和所有字元欄位(CHARVARCHARTEXT)變更為新的字元集,請使用如下語句:

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,則 CHARVARCHARTEXT 欄位會轉換為其對應的二進位字串類型(BINARYVARBINARYBLOB)。這表示欄位不再具有字元集,且後續的 CONVERT TO 操作不適用於它們。

如果 charset_nameCONVERT 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 CASCADEON UPDATE CASCADE 操作可能會因這些操作期間發生的隱式轉換而損壞參照資料表中的資料(Bug #45290, Bug #74816)。

匯入 InnoDB 資料表

在自己的單獨檔案表空間中建立的 InnoDB 資料表,可以使用 DISCARD TABLESPACEIMPORT TABLESPACE 子句從備份或其他 MySQL 伺服器實例匯入。請參閱第 17.6.1.3 節,「匯入 InnoDB 資料表」

MyISAM 資料表的列順序

ORDER BY 允許您以特定順序建立具有列的新資料表。當您知道大多數情況下會以特定順序查詢列時,此選項非常有用。在對資料表進行重大變更後使用此選項,您可能會獲得更高的效能。在某些情況下,如果資料表依您之後要排序的欄位排序,可能會讓 MySQL 更容易進行排序。

注意

在插入和刪除後,資料表不會保持在指定的順序。

ORDER BY 語法允許指定一個或多個用於排序的欄位名稱,每個名稱可以選擇性地後面跟著 ASCDESC 來表示升序或降序排序。預設為升序。只允許欄位名稱作為排序條件;不允許任意運算式。此子句應放在任何其他子句之後。

ORDER BY 對於 InnoDB 資料表沒有意義,因為 InnoDB 總是根據叢集索引對資料表列進行排序。

在分割的資料表上使用時,ALTER TABLE ... ORDER BY 僅對每個分割區內的列進行排序。

分割選項

partition_options 表示可與分割資料表一起使用的選項,用於重新分割、新增、刪除、捨棄、匯入、合併和分割分割區,以及執行分割維護。

ALTER TABLE 語句可以在其他變更規範中包含 PARTITION BYREMOVE PARTITIONING 子句,但 PARTITION BYREMOVE PARTITIONING 子句必須在任何其他規範之後最後指定。 ADD PARTITIONDROP PARTITIONDISCARD PARTITIONIMPORT PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONEXCHANGE PARTITIONANALYZE PARTITIONCHECK PARTITIONREPAIR PARTITION 選項不能在單個 ALTER TABLE 中與其他變更規範組合,因為剛列出的選項會作用於個別分割區。

有關分割選項的更多資訊,請參閱第 15.1.20 節,「CREATE TABLE 語句」第 15.1.9.1 節,「ALTER TABLE 分割區操作」。有關 ALTER TABLE ... EXCHANGE PARTITION 語句的資訊和範例,請參閱第 26.3.3 節,「使用資料表交換分割區和子分割區」