### 13.1.9 ALTER TABLE 语句

[13.1.9.1 ALTER TABLE 分区操作](alter-table-partition-operations.html)
[13.1.9.2 ALTER TABLE 和生成的列](alter-table-generated-columns.html)
[13.1.9.3 ALTER TABLE 示例](alter-table-examples.html)

[](<>)[](<>)[](<>)

```
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.html)改变表的结构。例如，您可以添加或删除列、创建或销毁索引、更改现有列的类型或重命名列或表本身。您还可以更改用于表格或表格注释的存储引擎等特征。

-   使用[`更改表`](alter-table.html)， 你需要[`改变`](privileges-provided.html#priv_alter),[`创建`](privileges-provided.html#priv_create)， 和[`插入`](privileges-provided.html#priv_insert)表的特权。重命名表需要[`改变`](privileges-provided.html#priv_alter)和[`降低`](privileges-provided.html#priv_drop)旧桌子上，[`改变`](privileges-provided.html#priv_alter),[`创建`](privileges-provided.html#priv_create)， 和[`插入`](privileges-provided.html#priv_insert)在新桌子上。

-   在表名之后，指定要进行的更改。如果没有给出，[`更改表`](alter-table.html)什么也没做。

-   许多允许更改的语法类似于[`创建表`](create-table.html)陈述。*`列定义`*子句使用相同的语法`添加`和`改变`至于[`创建表`](create-table.html).有关详细信息，请参阅[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html).

-   这个单词`柱子`是可选的，可以省略，除了`重命名列`（将列重命名操作与`改名`表重命名操作）。

-   多种的`添加`,`改变`,`降低`， 和`改变`子句允许在单个[`更改表`](alter-table.html)语句，用逗号分隔。这是标准 SQL 的 MySQL 扩展，每个子句只允许一个[`更改表`](alter-table.html)陈述。例如，要在单个语句中删除多个列，请执行以下操作：

    ```
    ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
    ```

-   如果存储引擎不支持尝试[`更改表`](alter-table.html)操作，可能会导致警告。此类警告可以显示为[`显示警告`](show-warnings.html).看[第 13.7.7.42 节，“显示警告声明”](show-warnings.html).有关故障排除的信息[`更改表`](alter-table.html)， 看[第 B.3.6.1 节，“ALTER TABLE 的问题”](alter-table-problems.html).

-   有关生成的列的信息，请参阅[第 13.1.9.2 节，“ALTER TABLE 和生成的列”](alter-table-generated-columns.html).

-   有关使用示例，请参阅[第 13.1.9.3 节，“ALTER TABLE 示例”](alter-table-examples.html).

-   `InnoDB`在 MySQL 8.0.17 及更高版本中，支持在 JSON 列上添加多值索引，使用*`关键部分`*规范可以采取的形式`（投掷 *`json_path`* 作为 *`类型`* 大批）`.看[多值指数](create-index.html#create-index-multi-valued)，有关多值索引的创建和使用以及多值索引的限制和限制的详细信息。

-   随着[`mysql_info()`](https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html)C API函数，您可以找出复制了多少行[`更改表`](alter-table.html).看[mysql\_信息（）](https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html).

     [](<>)

    有几个额外的方面`更改表`声明，在本节的以下主题下进行描述：

-   [表选项](alter-table.html#alter-table-options)

-   [性能和空间要求](alter-table.html#alter-table-performance)

-   [并发控制](alter-table.html#alter-table-concurrency)

-   [添加和删​​除列](alter-table.html#alter-table-add-drop-column)

-   [重命名、重新定义和重新排序列](alter-table.html#alter-table-redefine-column)

-   [主键和索引](alter-table.html#alter-table-index)

-   [外键和其他约束](alter-table.html#alter-table-foreign-key)

-   [更改字符集](alter-table.html#alter-table-character-set)

-   [导入 InnoDB 表](alter-table.html#alter-table-import)

-   [MyISAM 表的行顺序](alter-table.html#alter-table-row-order)

-   [分区选项](alter-table.html#alter-table-partition-options)

#### 表选项

*`表选项`*表示可以在[`创建表`](create-table.html)声明，例如`引擎`,`自动递增`,`AVG_ROW_LENGTH`,`MAX_ROWS`,`ROW_FORMAT`， 要么`表空间`.

有关所有表格选项的说明，请参阅[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html).然而，[`更改表`](alter-table.html)忽略`数据目录`和`索引目录`当作为表格选项给出时。[`更改表`](alter-table.html)仅允许它们作为分区选项，并要求您拥有`文件`特权。

使用表选项[`更改表`](alter-table.html)提供了一种更改单个表特征的便捷方式。例如：

-   如果`t1`目前不是`InnoDB`表，此语句将其存储引擎更改为`InnoDB`：

    ```
    ALTER TABLE t1 ENGINE = InnoDB;
    ```

    -   看[第 15.6.1.5 节，“将表从 MyISAM 转换为 InnoDB”](converting-tables-to-innodb.html)切换表时的注意事项`InnoDB`存储引擎。

    -   当您指定一个`引擎`条款，[`更改表`](alter-table.html)重建表。即使表已经具有指定的存储引擎也是如此。

    -   跑步[`更改表 *`tbl_name`* 引擎=INNODB`](alter-table.html)在现有的`InnoDB`表执行“空”[`更改表`](alter-table.html)操作，可用于碎片整理`InnoDB`表，如中所述[第 15.11.4 节，“对表进行碎片整理”](innodb-file-defragmenting.html).跑步[`更改表 *`tbl_name`* 力量`](alter-table.html)在一个`InnoDB`表执行相同的功能。

    -   [`更改表 *`tbl_name`* 引擎=INNODB`](alter-table.html)和[`更改表 *`tbl_name`* 力量`](alter-table.html)采用[在线 DDL](innodb-online-ddl.html).有关详细信息，请参阅[第 15.12 节，“InnoDB 和在线 DDL”](innodb-online-ddl.html).

    -   尝试更改表的存储引擎的结果受所需存储引擎是否可用以及设置的影响[`NO_ENGINE_SUBSTITUTION`](sql-mode.html#sqlmode_no_engine_substitution)SQL 模式，如中所述[第 5.1.11 节，“服务器 SQL 模式”](sql-mode.html).

    -   为防止意外丢失数据，[`更改表`](alter-table.html)不能用于将表的存储引擎更改为`合并`要么`黑洞`.

-   要更改`InnoDB`使用压缩行存储格式的表：

    ```
    ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
    ```

-   这`加密`子句启用或禁用页面级数据加密`InnoDB`桌子。必须安装并配置密钥环插件以启用加密。

    如果[`table_encryption_privilege_check`](server-system-variables.html#sysvar_table_encryption_privilege_check)变量启用时，[`TABLE_ENCRYPTION_ADMIN`](privileges-provided.html#priv_table-encryption-admin)需要特权才能使用`加密`子句的设置与默认模式加密设置不同。

    在 MySQL 8.0.16 之前，`加密`仅当更改驻留在每表文件表空间中的表时才支持子句。从 MySQL 8.0.16 开始，`加密`位于通用表空间中的表也支持子句。

    对于驻留在通用表空间中的表，表和表空间加密必须匹配。

    不允许通过将表移动到不同的表空间或更改存储引擎来更改表加密，除非明确指定`加密`条款。

    从 MySQL 8.0.16 开始，指定一个`加密`子句的值不是`'N'`要么`''`如果表使用不支持加密的存储引擎，则不允许。此前，该条款被接受。试图创建一个没有`加密`也不允许使用不支持加密的存储引擎在启用加密的模式中使用子句。

    有关详细信息，请参阅[第 15.13 节，“InnoDB 静态数据加密”](innodb-data-encryption.html).

-   要重置当前的自动增量值：

    ```
    ALTER TABLE t1 AUTO_INCREMENT = 13;
    ```

    您不能将计数器重置为小于或等于当前使用的值。对彼此而言`InnoDB`和`MyISAM`, 如果该值小于或等于当前在`自动递增`列，值被重置为当前最大值`自动递增`列值加一。

-   要更改默认表字符集：

    ```
    ALTER TABLE t1 CHARACTER SET = utf8;
    ```

    也可以看看[更改字符集](alter-table.html#alter-table-character-set).

-   添加（或更改）表格注释：

    ```
    ALTER TABLE t1 COMMENT = 'New table comment';
    ```

-   采用`更改表`与`表空间`移动选项`InnoDB`现有表之间[通用表空间](glossary.html#glos_general_tablespace),[每表文件](glossary.html#glos_file_per_table)表空间和[系统表空间](glossary.html#glos_system_tablespace).看[使用 ALTER TABLE 在表空间之间移动表](general-tablespaces.html#general-tablespaces-moving-non-partitioned-tables).

    -   `改变表...表空间`操作总是会导致全表重建，即使`表空间`属性与之前的值相比没有变化。

    -   `改变表...表空间`语法不支持将表从临时表空间移动到持久表空间。

    -   这`数据目录`子句，支持[`创建表...表空间`](create-table.html), 不支持`改变表...表空间`, 如果指定则被忽略。

    -   有关功能和限制的更多信息`表空间`选项，见[`创建表`](create-table.html).

-   MySQL NDB Cluster 8.0 支持设置`NDB_TABLE`用于控制表的分区平衡（片段计数类型）、从任何副本读取功能、完全复制或这些的任意组合的选项，作为表注释的一部分`更改表`以与 for 相同的方式声明[`创建表`](create-table.html)，如本例所示：

    ```
    ALTER TABLE t1 COMMENT = "NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";
    ```

    请记住，`更改表...评论...`丢弃表的任何现有注释。看[设置 NDB\_表选项](create-table.html#create-table-comment-ndb-table-options)，以获取更多信息和示例。

-   `引擎属性`和`SECONDARY_ENGINE_ATTRIBUTE`选项（自 MySQL 8.0.21 起可用）用于指定主存储引擎和辅助存储引擎的表、列和索引属性。这些选项保留供将来使用。索引属性不能更改。必须删除索引并将其添加回所需的更改，这可以一次执行[`更改表`](alter-table.html)陈述。

    要验证表选项是否按预期更改，请使用[`显示创建表`](show-create-table.html)，或查询[`INFORMATION_SCHEMA.TABLES`](information-schema-tables-table.html)桌子。

#### 性能和空间要求

[`更改表`](alter-table.html)使用以下算法之一处理操作：

-   `复制`：对原表的副本进行操作，将原表中的表数据逐行复制到新表中。不允许并发 DML。

-   `到位`: 操作避免复制表数据，但可能会就地重建表。在操作的准备和执行阶段，可能会短暂地对表进行独占元数据锁定。通常，支持并发 DML。

-   `立即的`: 操作只修改数据字典中的元数据。在准备和执行过程中，不会对表进行独占元数据锁，表数据不受影响，操作是即时的。允许并发 DML。（在 MySQL 8.0.12 中引入）

    这`算法`子句是可选的。如果`算法`子句被省略，MySQL 使用`算法=即时`用于存储引擎和[`更改表`](alter-table.html)支持它的条款。否则，`算法=就地`用来。如果`算法=就地`不支持，`算法=复制`用来。

笔记

使用将列添加到分区表后`算法=即时`, 不再可能执行[`ALTER TABLE ...交换分区`](alter-table-partition-operations.html)在桌子上。

指定一个`算法`子句要求操作对支持它的子句和存储引擎使用指定的算法，否则会失败并出现错误。指定`算法=默认`与省略`算法`条款。

[`更改表`](alter-table.html)使用`复制`算法等待正在修改表的其他操作完成。对表副本应用更改后，将数据复制过来，删除原始表，并将表副本重命名为原始表的名称。虽然[`更改表`](alter-table.html)操作执行时，原始表可以被其他会话读取（除了后面提到的例外）。更新和写入表后开始[`更改表`](alter-table.html)操作开始被停止，直到新表准备好，然后自动重定向到新表。表的临时副本在原始表的数据库目录中创建，除非它是`重命名为`将表移动到位于不同目录中的数据库的操作。

前面提到的例外是[`更改表`](alter-table.html)在准备好从表和表定义缓存中清除过时的表结构时阻止读取（不仅仅是写入）。此时，它必须获得一个排他锁。为此，它会等待当前读取器完成，并阻止新的读取和写入。

一个[`更改表`](alter-table.html)使用`复制`算法防止并发 DML 操作。仍然允许并发查询。也就是说，一个表复制操作总是至少包含以下并发限制：`锁定=共享`（允许查询但不允许 DML）。您可以进一步限制支持`锁`通过指定子句`锁定=独家`，这可以防止 DML 和查询。有关详细信息，请参阅[并发控制](alter-table.html#alter-table-concurrency).

强制使用`复制`算法[`更改表`](alter-table.html)否则不会使用它的操作，请指定`算法=复制`或启用[`old_alter_table`](server-system-variables.html#sysvar_old_alter_table)系统变量。如果两者之间发生冲突`old_alter_table`设置和一个`算法`子句的值不是`默认`， 这`算法`子句优先。

为了`InnoDB`表，一个[`更改表`](alter-table.html)使用`复制`算法在驻留在 a 中的表上[共享表空间](glossary.html#glos_shared_tablespace)可以增加表空间使用的空间量。此类操作需要与表中的数据加上索引一样多的额外空间。对于驻留在共享表空间中的表，操作期间使用的额外空间不会像驻留在共享表空间中的表那样释放回操作系统。[每表文件](glossary.html#glos_file_per_table)表空间。

有关联机 DDL 操作的空间要求的信息，请参阅[第 15.12.3 节，“在线 DDL 空间要求”](innodb-online-ddl-space-requirements.html).

[`更改表`](alter-table.html)支持的操作`到位`算法包括：

-   `更改表`支持的操作`InnoDB` [在线 DDL](glossary.html#glos_online_ddl)特征。看[第 15.12.1 节，“在线 DDL 操作”](innodb-online-ddl-operations.html).

-   重命名表。MySQL 重命名表对应的文件*`tbl_name`*无需复制。（您也可以使用[`重命名表`](rename-table.html)语句重命名表。看[第 13.1.36 节，“重命名 TABLE 语句”](rename-table.html).) 专门为重命名表授予的权限不会迁移到新名称。它们必须手动更改。

-   仅修改表元数据的操作。这些操作是即时的，因为服务器不接触表格内容。仅元数据操作包括：

    -   重命名列。在 NDB Cluster 8.0.18 及更高版本中，也可以在线执行此操作。

    -   更改列的默认值（除了[`新开发银行`](mysql-cluster.html)表）。

    -   修改定义[`枚举`](enum.html)要么[`放`](set.html)通过向列添加新的枚举或集合成员*结尾*只要数据类型的存储大小不发生变化，则有效成员值的列表。例如，将成员添加到[`放`](set.html)具有 8 个成员的列将每个值所需的存储空间从 1 个字节更改为 2 个字节；这需要一个表格副本。在列表中间添加成员会导致对现有成员重新编号，这需要一个表副本。

    -   更改空间列的定义以删除`SRID`属性。（添加或更改`SRID`属性确实需要重建并且不能在适当的位置完成，因为服务器必须验证所有值都具有指定的 SRID 值。）

    -   从 MySQL 8.0.14 开始，当这些条件适用时，更改列字符集：

        -   列数据类型为[`字符`](char.html),[`VARCHAR`](char.html)， 一种[`文本`](blob.html)键入，或[`枚举`](enum.html).

        -   字符集更改来自`utf8mb3`到`utf8mb4`, 或任何字符集`二进制`.

        -   列上没有索引。

    -   从 MySQL 8.0.14 开始，当这些条件适用时，更改生成的列：

        -   为了`InnoDB`表，修改生成的存储列但不更改其类型、表达式或可空性的语句。

        -   对于非`InnoDB`表，修改生成的存储或虚拟列但不更改其类型、表达式或可空性的语句。

            此类更改的一个示例是对列注释的更改。

-   重命名索引。

-   添加或删除二级索引，用于[`InnoDB`](innodb-storage-engine.html)和[`新开发银行`](mysql-cluster.html)表。看[第 15.12.1 节，“在线 DDL 操作”](innodb-online-ddl-operations.html).

-   为了[`新开发银行`](mysql-cluster.html)表，在可变宽度列上添加和删除索引的操作。这些操作在线发生，无需复制表，也不会在大部分时间内阻塞并发 DML 操作。看[第 23.6.11 节，“在 NDB 集群中使用 ALTER TABLE 进行在线操作”](mysql-cluster-online-operations.html).

-   修改索引可见性`更改索引`手术。

-   包含生成列的表的列修改，这些列依赖于具有`默认`如果修改的列不包含在生成的列表达式中，则为 value。例如，改变`空值`可以在不重建表的情况下就地完成单独列的属性。

`更改表`支持的操作`立即的`算法包括：

-   添加一列。此功能被称为“即时`添加列`”。限制适用。看[第 15.12.1 节，“在线 DDL 操作”](innodb-online-ddl-operations.html).

-   添加或删除虚拟列。

-   添加或删除列默认值。

-   修改定义[`枚举`](enum.html)要么[`放`](set.html)柱子。与上述相同的限制适用于`算法=即时`.

-   更改索引类型。

-   重命名表。与上述相同的限制适用于`算法=即时`.

    有关支持的操作的更多信息`算法=即时`， 看[第 15.12.1 节，“在线 DDL 操作”](innodb-online-ddl-operations.html).

[`更改表`](alter-table.html)将 MySQL 5.5 时间列升级到 5.6 格式`添加列`,`更改列`,`修改栏目`,`添加索引`， 和`力量`操作。此转换无法使用`到位`算法，因为必须重建表，所以指定`算法=就地`在这些情况下会导致错误。指定`算法=复制`如有必要。

如果`更改表`对用于对表进行分区的多列索引的操作`钥匙`更改列的顺序，只能使用`算法=复制`.

这`未经验证`和`通过验证`条款影响是否[`更改表`](alter-table.html)执行就地操作[虚拟生成列](glossary.html#glos_virtual_generated_column)修改。看[第 13.1.9.2 节，“ALTER TABLE 和生成的列”](alter-table-generated-columns.html).

NDB Cluster 8.0 支持使用相同的在线操作`算法=就地`与标准 MySQL 服务器一起使用的语法。`新开发银行`不支持在线更改表空间；从 NDB 8.0.21 开始，它是不允许的。看[第 23.6.11 节，“在 NDB 集群中使用 ALTER TABLE 进行在线操作”](mysql-cluster-online-operations.html)， 了解更多信息。

NDB 8.0.27 及更高版本，执行复制时`更改表`, 检查以确保没有对受影响的表进行并发写入。如果它发现任何已被制造，[`新开发银行`](mysql-cluster.html)拒绝`更改表`声明并提出[`ER_TABLE_DEF_CHANGED`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_def_changed).

`更改表`和`丢弃...分区...表空间`要么`导入...分区...表空间`不创建任何临时表或临时分区文件。

`更改表`和`添加分区`,`删除分区`,`合并分区`,`重建分区`， 要么`重组分区`不创建临时表（除非与[`新开发银行`](mysql-cluster.html)表）；但是，这些操作可以并且确实会创建临时分区文件。

`添加`要么`降低`操作为`范围`要么`列表`分区是立即操作或几乎是立即操作。`添加`要么`合并`操作为`哈希`要么`钥匙`分区在所有分区之间复制数据，除非`线性哈希`要么`线性键`被使用；这实际上与创建一个新表相同，尽管`添加`要么`合并`操作是逐个分区执行的。`改组`操作只复制更改的分区，不触及未更改的分区。

为了`MyISAM`表，您可以通过设置[`myisam_sort_buffer_size`](server-system-variables.html#sysvar_myisam_sort_buffer_size)系统变量为高值。

#### 并发控制

为了[`更改表`](alter-table.html)支持它的操作，您可以使用`锁`子句来控制在更改表时对表的并发读取和写入级别。为该子句指定非默认值使您可以在更改操作期间要求一定数量的并发访问或排他性，并在请求的锁定程度不可用时停止操作。

仅有的`锁定 = 默认`允许使用的操作`算法=即时`.另一个`锁`子句参数不适用。

的参数`锁`子句是：

-   `锁定 = 默认`

    给定的最大并发级别`算法`条款（如果有）和`更改表`operation：如果支持，允许并发读写。如果不是，则允许并发读取（如果支持）。如果不是，则强制执行独占访问。

-   `锁定 = 无`

    如果支持，允许并发读取和写入。否则，会发生错误。

-   `锁定 = 共享`

    如果支持，允许并发读取但阻止写入。即使给定的存储引擎支持并发写入，写入也会被阻止`算法`条款（如果有）和`更改表`手术。如果不支持并发读取，则会发生错误。

-   `锁定 = 独家`

    强制执行独占访问。即使给定的存储引擎支持并发读/写，也会这样做`算法`条款（如果有）和`更改表`手术。

#### 添加和删​​除列

采用`添加`向表中添加新列，以及`降低`删除现有列。`降低 *`col_name`*`是标准 SQL 的 MySQL 扩展。

要在表格行中的特定位置添加列，请使用`第一的`要么`后 *`col_name`*`.默认是最后添加列。

如果一个表只包含一列，则不能删除该列。如果您打算删除表格，请使用[`删除表`](drop-table.html)而是声明。

如果从表中删除列，则这些列也会从它们所属的任何索引中删除。如果删除了构成索引的所有列，则该索引也将被删除。如果你使用`改变`要么`调整`为了缩短列上存在索引的列，并且生成的列长度小于索引长度，MySQL会自动缩短索引。

为了`更改表...添加`，如果该列具有使用非确定性函数的表达式默认值，则该语句可能会产生警告或错误。有关详细信息，请参阅[第 11.6 节，“数据类型默认值”](data-type-defaults.html)， 和[第 17.1.3.7 节，“使用 GTID 进行复制的限制”](replication-gtids-restrictions.html).

#### 重命名、重新定义和重新排序列

[](<>)[](<>)[](<>)[](<>)

这`改变`,`调整`,`重命名列`， 和`改变`子句允许更改现有列的名称和定义。它们具有以下比较特征：

-   `改变`：

    -   可以重命名列并更改其定义，或两者兼而有之。

    -   比拥有更多的能力`调整`要么`重命名列`，但以牺牲某些操作的便利性为代价。`改变`如果不重命名，则需要将列命名两次，如果只重命名，则需要重新指定列定义。

    -   和`第一的`要么`后`, 可以重新排序列。

-   `调整`：

    -   可以更改列定义但不能更改其名称。

    -   比方便`改变`更改列定义而不重命名它。

    -   和`第一的`要么`后`, 可以重新排序列。

-   `重命名列`：

    -   可以更改列名，但不能更改其定义。

    -   比方便`改变`重命名列而不更改其定义。

-   `改变`：仅用于更改列默认值。

[](<>)[](<>)

`改变`是标准 SQL 的 MySQL 扩展。`调整`和`重命名列`是用于 Oracle 兼容性的 MySQL 扩展。

要更改列以更改其名称和定义，请使用`改变`，指定旧名称和新名称以及新定义。例如，要重命名一个`INT 非空`从列`一种`到`b`并更改其定义以使用`大整数`数据类型同时保留`非空`属性，请执行以下操作：

```
ALTER TABLE t1 CHANGE a b BIGINT NOT NULL;
```

要更改列定义但不更改其名称，请使用`改变`要么`调整`.和`改变`，语法需要两个列名，因此您必须指定相同的名称两次以保持名称不变。例如，更改列的定义`b`， 做这个：

```
ALTER TABLE t1 CHANGE b b INT NOT NULL;
```

`调整`在不更改名称的情况下更改定义更方便，因为它只需要一次列名：

```
ALTER TABLE t1 MODIFY b INT NOT NULL;
```

要更改列名但不更改其定义，请使用`改变`要么`重命名列`.和`改变`，语法需要列定义，因此要保持定义不变，您必须重新指定列当前具有的定义。例如，要重命名一个`INT 非空`从列`b`到`一种`， 做这个：

```
ALTER TABLE t1 CHANGE b a INT NOT NULL;
```

`重命名列`在不更改定义的情况下更改名称更方便，因为它只需要旧名称和新名称：

```
ALTER TABLE t1 RENAME COLUMN b TO 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;
```

对于使用列定义更改`改变`要么`调整`, 定义必须包括数据类型和应该应用于新列的所有属性，而不是索引属性，例如`首要的关键`要么`独特`.原始定义中存在但未为新定义指定的属性不会结转。假设有一列`col1`定义为`INT UNSIGNED DEFAULT 1 COMMENT '我的专栏'`并且您按如下方式修改列，仅打算更改`INT`到`大整数`：

```
ALTER TABLE t1 MODIFY col1 BIGINT;
```

该语句将数据类型从`INT`到`大整数`，但它也会降低`未签名`,`默认`， 和`评论`属性。要保留它们，语句必须明确包括它们：

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

对于使用的数据类型更改`改变`要么`调整`, MySQL 尽量将现有的列值转换为新类型。

警告

这种转换可能会导致数据更改。例如，如果您缩短字符串列，则值可能会被截断。如果转换为新数据类型会导致数据丢失，为防止操作成功，请在使用前启用严格 SQL 模式[`更改表`](alter-table.html)（看[第 5.1.11 节，“服务器 SQL 模式”](sql-mode.html)）。

如果你使用`改变`要么`调整`为了缩短列上存在索引的列，并且生成的列长度小于索引长度，MySQL会自动缩短索引。

对于重命名的列`改变`要么`重命名列`, MySQL 自动将这些引用重命名为重命名的列：

-   引用旧列的索引，包括不可见索引和禁用`MyISAM`索引。

-   引用旧列的外键。

    对于重命名的列`改变`要么`重命名列`, MySQL 不会自动将这些引用重命名为重命名的列：

-   生成的列和分区表达式引用重命名的列。你必须使用`改变`重新定义这样的表达方式[`更改表`](alter-table.html)语句作为重命名列的语句。

-   引用重命名列的视图和存储的程序。您必须手动更改这些对象的定义以引用新列名。

    要重新排序表中的列，请使用`第一的`和`后`在`改变`要么`调整`操作。

[](<>)

`改变...设置默认值`要么`改变...删除默认值`分别为列指定新的默认值或删除旧的默认值。如果旧的默认值被删除并且该列可以`空值`，新的默认值是`空值`.如果列不能`空值`, MySQL 分配一个默认值，如中所述[第 11.6 节，“数据类型默认值”](data-type-defaults.html).

从 MySQL 8.0.23 开始，`改变...设置可见`和`ALTER ...设置不可见`启用要更改的列可见性。看[第 13.1.20.10 节，“不可见的列”](invisible-columns.html).

#### 主键和索引

[](<>)[](<>)[](<>)

`删除主键`滴[首要的关键](glossary.html#glos_primary_key).如果没有主键，则会发生错误。有关主键性能特征的信息，尤其是对于`InnoDB`表，见[第 8.3.2 节，“主键优化”](primary-key-optimization.html).

如果[`sql_require_primary_key`](server-system-variables.html#sysvar_sql_require_primary_key)系统变量已启用，尝试删除主键会产生错误。

[](<>)[](<>)

如果你添加一个`唯一索引`要么`首要的关键`对于一个表，MySQL 将它存储在任何非唯一索引之前，以允许尽早检测到重复键。

[](<>)[](<>)[](<>)

[`删除索引`](drop-index.html)删除索引。这是标准 SQL 的 MySQL 扩展。看[第 13.1.27 节，“DROP INDEX 语句”](drop-index.html).要确定索引名称，请使用`显示索引 *`tbl_name`*`.

一些存储引擎允许您在创建索引时指定索引类型。的语法*`索引类型`*说明符是`使用 *`类型名称`*`.有关详细信息`使用`， 看[第 13.1.15 节，“CREATE INDEX 语句”](create-index.html).首选位置在列列表之后。期望在未来的 MySQL 版本中支持在列列表之前使用该选项。

*`index_option`*值指定索引的附加选项。`使用`就是这样一种选择。有关允许的详细信息*`index_option`*值，见[第 13.1.15 节，“CREATE INDEX 语句”](create-index.html).

`重命名索引 *`old_index_name`* 到 *`新索引名称`*`重命名索引。这是标准 SQL 的 MySQL 扩展。表的内容保持不变。*`old_index_name`*必须是表中现有索引的名称，该索引未被相同的删除[`更改表`](alter-table.html)陈述。*`新索引名称`*是新的索引名称，它不能在应用更改后与结果表中的索引名称重复。两个索引名称都不能`基本的`.

[](<>)[](<>)[](<>)

如果你使用[`更改表`](alter-table.html)在一个`MyISAM`表中，所有非唯一索引都在单独的批次中创建（如[`维修台`](repair-table.html)）。这应该使[`更改表`](alter-table.html)当你有很多索引时要快得多。

为了`MyISAM`表，键更新可以显式控制。采用`ALTER TABLE ... 禁用键`告诉 MySQL 停止更新非唯一索引。然后使用`ALTER TABLE ...启用键`重新创建丢失的索引。`MyISAM`使用一种比逐个插入键快得多的特殊算法来执行此操作，因此在执行批量插入操作之前禁用键应该会带来相当大的加速。使用`ALTER TABLE ... 禁用键`需要[`指数`](privileges-provided.html#priv_index)除了前面提到的特权之外的特权。

虽然禁用了非唯一索引，但它们在语句中会被忽略，例如[`选择`](select.html)和[`解释`](explain.html)否则会使用它们。

经过一个[`更改表`](alter-table.html)声明，可能需要运行[`分析表`](analyze-table.html)更新索引基数信息。看[第 13.7.7.22 节，“显示索引语句”](show-index.html).

[](<>)

这`更改索引`操作允许索引可见或不可见。优化器不使用不可见索引。索引可见性的修改适用于除主键之外的索引（显式或隐式）。此功能与存储引擎无关（任何引擎都支持）。有关详细信息，请参阅[第 8.3.12 节，“不可见索引”](invisible-indexes.html).

#### 外键和其他约束

[](<>)[](<>)

这`外键`和`参考`条款得到支持`InnoDB`和`新开发银行`存储引擎，它实现`添加 [约束 [*`象征`*]] 外键 [*`索引名称`*] （...） 参考 ... （...）`.看[第 13.1.20.5 节，“外键约束”](create-table-foreign-keys.html).对于其他存储引擎，这些子句被解析但被忽略。

为了[`更改表`](alter-table.html), 不像[`创建表`](create-table.html),`添加外键`忽略*`索引名称`*如果给定并使用自动生成的外键名称。作为一种解决方法，包括`约束`子句指定外键名称：

```
ADD CONSTRAINT name FOREIGN KEY (....) ...
```

重要的

MySQL 默默地忽略内联`参考`规范，其中引用被定义为列规范的一部分。MySQL 只接受`参考`被定义为单独的子句的一部分`外键`规格。

笔记

分区`InnoDB`表不支持外键。此限制不适用于`新开发银行`表，包括那些显式分区的表`[线性]键`.有关详细信息，请参阅[第 24.6.2 节，“与存储引擎相关的分区限制”](partitioning-limitations-storage-engines.html).

[](<>)[](<>)[](<>)

MySQL Server 和 NDB Cluster 都支持使用[`更改表`](alter-table.html)删除外键：

```
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
```

在同一个文件中添加和删除外键[`更改表`](alter-table.html)声明支持[`ALTER TABLE ...算法=INPLACE`](alter-table.html)但不是为了[`ALTER TABLE ...算法=复制`](alter-table.html).

服务器禁止对可能导致失去参照完整性的外键列进行更改。一种解决方法是使用[`ALTER TABLE ... 删除外键`](alter-table.html)在更改列定义之前[`ALTER TABLE ... 添加外键`](alter-table.html)之后。禁止更改的示例包括：

-   更改可能不安全的外键列的数据类型。例如，改变[`VARCHAR(20)`](char.html)到[`VARCHAR(30)`](char.html)是允许的，但将其更改为[`VARCHAR(1024)`](char.html)不是因为这会改变存储单个值所需的长度字节数。

-   改变一个`空值`列到`非空`在非严格模式下被禁止以防止转换`空值`值默认为非`空值`值，在引用的表中没有对应的值。严格模式下允许该操作，但如果需要任何此类转换，则会返回错误。

`更改表 *`tbl_name`* 改名 *`new_tbl_name`*`更改内部生成的外键约束名称和用户定义的以字符串“开头的外键约束名称”*`tbl_name`*\_ibfk\_”来反映新的表名。`InnoDB`解释以字符串“”开头的外键约束名称*`tbl_name`*\_ibfk\_” 作为内部生成的名称。

[](<>)

在 MySQL 8.0.16 之前，[`更改表`](alter-table.html)只允许以下有限版本的`查看`约束添加语法，被解析和忽略：

```
ADD CHECK (expr)
```

从 MySQL 8.0.16 开始，[`更改表`](alter-table.html)许可证`查看`添加、删除或更改现有表的约束：

-   添加一个新的`查看`约束：

    ```
    ALTER TABLE tbl_name
        ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED];
    ```

    约束语法元素的含义与for相同[`创建表`](create-table.html).看[第 13.1.20.6 节，“检查约束”](create-table-check-constraints.html).

-   删除现有的`查看`约束命名*`象征`*：

    ```
    ALTER TABLE tbl_name
        DROP CHECK symbol;
    ```

-   改变现有的`查看`约束命名*`象征`*被强制执行：

    ```
    ALTER TABLE tbl_name
        ALTER CHECK symbol [NOT] ENFORCED;
    ```

    这`删除检查`和`更改检查`子句是标准 SQL 的 MySQL 扩展。

    从 MySQL 8.0.19 开始，[`更改表`](alter-table.html)允许更通用（和 SQL 标准）语法来删除和更改任何类型的现有约束，其中约束类型由约束名称确定：

-   删除一个名为*`象征`*：

    ```
    ALTER TABLE tbl_name
        DROP CONSTRAINT symbol;
    ```

    如果[`sql_require_primary_key`](server-system-variables.html#sysvar_sql_require_primary_key)系统变量已启用，尝试删除主键会产生错误。

-   更改现有约束是否名为*`象征`*被强制执行：

    ```
    ALTER TABLE tbl_name
        ALTER CONSTRAINT symbol [NOT] ENFORCED;
    ```

    仅有的`查看`可以将约束更改为未强制执行。始终强制执行所有其他约束类型。

    SQL 标准规定所有类型的约束（主键、唯一索引、外键、检查）属于同一个命名空间。在 MySQL 中，每个约束类型的每个模式都有自己的命名空间。因此，每个模式的每种约束类型的名称必须是唯一的，但不同类型的约束可以具有相同的名称。当多个约束具有相同的名称时，`丢弃约束`和`添加约束`模棱两可并且发生错误。在这种情况下，必须使用特定于约束的语法来修改约束。例如，使用`删除主键`或 DROP FOREIGN KEY 删除主键或外键。

    如果表更改导致违反强制执行`查看`约束，发生错误并且表没有被修改。发生错误的操作示例：

-   尝试添加`自动递增`属性到在 a 中使用的列`查看`约束。

-   尝试添加强制`查看`约束或强制执行非强制`查看`现有行违反约束条件的约束。

-   尝试修改、重命名或删除在`查看`约束，除非在同一语句中也删除了该约束。例外：如果`查看`约束仅指单个列，删除列会自动删除约束。

`更改表 *`tbl_name`* 改名 *`new_tbl_name`*`内部生成和用户定义的更改`查看`以字符串“”开头的约束名称*`tbl_name`*\_查克\_”来反映新的表名。MySQL 解释`查看`以字符串“”开头的约束名称*`tbl_name`*\_查克\_” 作为内部生成的名称。

#### 更改字符集

[](<>)更改表格默认字符集和所有字符列 ([`字符`](char.html),[`VARCHAR`](char.html),[`文本`](blob.html)) 到一个新的字符集，使用这样的语句：

```
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
```

该语句还更改所有字符列的排序规则。如果您指定否`整理`子句来指示要使用的排序规则，该语句使用字符集的默认排序规则。如果此排序规则不适合预期的表用途（例如，如果它将从区分大小写的排序规则更改为不区分大小写的排序规则），请显式指定排序规则。

对于具有数据类型的列[`VARCHAR`](char.html)或其中之一[`文本`](blob.html)类型，`转换为字符集`根据需要更改数据类型，以确保新列足够长以存储与原始列一样多的字符。例如，一个[`文本`](blob.html)column 有两个长度字节，用于存储该列中值的字节长度，最大为 65,535。为一个`拉丁语1` [`文本`](blob.html)列，每个字符需要一个字节，因此该列最多可以存储 65,535 个字符。如果该列转换为`utf8`，每个字符可能需要最多三个字节，最大可能长度为 3 × 65,535 = 196,605 字节。这个长度不适合[`文本`](blob.html)列的长度字节，因此 MySQL 将数据类型转换为[`中文本`](blob.html)，它是长度字节可以记录的值为 196,605 的最小字符串类型。同样，一个[`VARCHAR`](char.html)列可能会转换为[`中文本`](blob.html).

为避免刚刚描述的类型的数据类型更改，请勿使用`转换为字符集`.相反，使用`调整`更改单个列。例如：

```
ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8;
ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M) CHARACTER SET utf8;
```

如果您指定`转换为字符集二进制`， 这[`字符`](char.html),[`VARCHAR`](char.html)， 和[`文本`](blob.html)列被转换为其对应的二进制字符串类型（[`二进制`](binary-varbinary.html),[`变量`](binary-varbinary.html),[`斑点`](blob.html)）。这意味着这些列不再有字符集和后续`转换成`操作不适用于他们。

如果*`字符集名称`*是`默认`在一个`转换为字符集`操作，由命名的字符集[`字符集数据库`](server-system-variables.html#sysvar_character_set_database)使用系统变量。

警告

这`转换成`操作在原始字符集和命名字符集之间转换列值。这是*不是*如果您在一个字符集中有一列，您想要什么（例如`拉丁语1`) 但存储的值实际上使用了其他一些不兼容的字符集（如`utf8`）。在这种情况下，您必须对每个此类列执行以下操作：

```
ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
```

这样做的原因是当您转换为或从[`斑点`](blob.html)列。

仅更改*默认*表的字符集，使用以下语句：

```
ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;
```

这个单词`默认`是可选的。默认字符集是如果您没有为稍后添加到表中的列指定字符集时使用的字符集（例如，使用`ALTER TABLE ...添加列`）。

当。。。的时候[`foreign_key_checks`](server-system-variables.html#sysvar_foreign_key_checks)如果系统变量已启用，这是默认设置，则不允许在包含外键约束中使用的字符串列的表上进行字符集转换。解决方法是禁用[`foreign_key_checks`](server-system-variables.html#sysvar_foreign_key_checks)在执行字符集转换之前。您必须在重新启用之前对涉及外键约束的两个表执行转换[`foreign_key_checks`](server-system-variables.html#sysvar_foreign_key_checks).如果你重新启用[`foreign_key_checks`](server-system-variables.html#sysvar_foreign_key_checks)仅转换其中一个表后，`删除级联`要么`更新级联`由于在这些操作期间发生的隐式转换，操作可能会损坏引用表中的数据（错误 #45290、错误 #74816）。

#### 导入 InnoDB 表

[](<>)[](<>)

一个`InnoDB`自己创建的表[每表文件](glossary.html#glos_file_per_table)可以使用从备份或另一个 MySQL 服务器实例导入表空间`丢弃桌面`和`导入表空间`条款。看[第 15.6.1.3 节，“导入 InnoDB 表”](innodb-table-import.html).

#### MyISAM 表的行顺序

[](<>)

`订购方式`使您能够创建具有特定顺序的行的新表。此选项主要在您知道大部分时间以特定顺序查询行时很有用。通过在对表进行重大更改后使用此选项，您可能可以获得更高的性能。在某些情况下，如果表按您稍后要对其排序的列进行排序，则可能会使 MySQL 更容易排序。

笔记

插入和删除后，表不会按指定顺序保留。

`订购方式`语法允许为排序指定一个或多个列名，每个列名可选地后跟`ASC`要么`DESC`分别表示升序或降序排序。默认为升序。只允许列名作为排序条件；不允许任意表达。该子句应在任何其他子句之后最后给出。

`订购方式`没有意义`InnoDB`表因为`InnoDB`总是根据[聚集索引](glossary.html#glos_clustered_index).

在分区表上使用时，`更改表...订购者`仅对每个分区中的行进行排序。

#### 分区选项

*`分区选项`*表示可与分区表一起用于重新分区、添加、删除、丢弃、导入、合并和拆分分区以及执行分区维护的选项。

这是可能的[`更改表`](alter-table.html)声明包含一个`分区方式`要么`删除分区`条款中除了其他变更规范，但`分区方式`要么`删除分区`子句必须在任何其他规范之后最后指定。这`添加分区`,`删除分区`,`丢弃分区`,`导入分区`,`合并分区`,`重组分区`,`交换分区`,`分析分区`,`检查分区`， 和`修复分区`选项不能与其他更改规范组合在一起`更改表`，因为刚刚列出的选项作用于各个分区。

有关分区选项的详细信息，请参阅[第 13.1.20 节，“CREATE TABLE 语句”](create-table.html)， 和[第 13.1.9.1 节，“ALTER TABLE 分区操作”](alter-table-partition-operations.html).有关信息和示例`ALTER TABLE ...交换分区`陈述，见[第 24.3.3 节，“用表交换分区和子分区”](partitioning-management-exchange.html).
