文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  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 子句,則不允許透過將資料表移至不同的資料表空間或變更儲存引擎來變更資料表加密。

    如果資料表使用的儲存引擎不支援加密,則不允許指定 ENCRYPTION 子句的值不是 'N'''。如果使用不支援加密的儲存引擎,在已啟用加密的結構描述中嘗試建立沒有 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 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_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 會將 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 設定和值不是 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

      • 字元集變更為從 utf8mb3utf8mb4,或是任何字元集到 binary

      • 欄位上沒有索引。

    • 當符合這些條件時,變更產生的欄位

      • 對於 InnoDB 表格,修改產生的儲存欄位但不變更其類型、表達式或可空性的語句。

      • 對於非 InnoDB 表格,修改產生的儲存或虛擬欄位但不變更其類型、表達式或可空性的語句。

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

  • 重新命名索引。

  • 對於 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 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 ... 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 不會自動重新命名對重新命名欄位的這些參照

  • 參照重新命名欄位的產生欄位和分割區表達式。您必須使用 CHANGE 在與重新命名欄位的相同 ALTER TABLE 語句中重新定義這些表達式。

  • 參照重新命名欄位的視圖和儲存程式。您必須手動變更這些物件的定義以參照新的欄位名稱。

若要重新排序表格中的欄位,請在 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 不同,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 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 會變更內部產生和使用者定義的 CHECK 約束名稱(以字串 tbl_name_chk_ 開頭),以反映新的表格名稱。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 表格

使用 DISCARD TABLESPACEIMPORT TABLESPACE 子句,可以從備份或從另一個 MySQL 伺服器執行個體匯入在其自己的file-per-table 表空間中建立的 InnoDB 表格。請參閱第 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 節,「與表格交換分割區和子分割區」