MySQL 8.0 InnoDB对即时加字段的会支持(instant add column)(译)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 8.0 InnoDB对即时加字段的会支持(instant add column)(译)相关的知识,希望对你有一定的参考价值。
原文地址:https://mysqlserverteam.com/mysql-8-0-innodb-now-supports-instant-add-column/
MySQL 5.6是第一个支持INPLACE DDL的版本。在MySQL 5.6之前,执行DDL的唯一方法是逐行复制行。
INPLACE DDL主要由InnoDB处理,而逐行COPY在服务器层处理。直到8.0(请参阅实验版本),InnoDB甚至通过为INPLACE DDL算法重建表来向表中添加列。
- 对于大型表,可能要花费很长时间,尤其是在复制环境中。
- 磁盘空间需求将增加一倍以上,大小与现有表大致相同。
- DDL操作占用资源,并且对CPU,内存和IO提出了很高的要求,这从用户事务中争夺资源。
- 如果涉及复制,slave要一直要等待到DDL的完成,才能开始同步。
许多用户向我们询问了如何避免耗时的schema changes。现在,可以通过(始终)指定ALGORITHM = INSTANT来实现,这将保证操作立即完成(如果不支持则无法完成)。
此外,如果根本未指定ALGORITHM,则服务器将首先尝试DEFAULT = INSTANT算法,如果无法完成,则服务器将尝试INPLACE算法;如果SE无法支持,服务器将最终尝试COPY算法。
新语法如下:
ALTER TABLE table_name [alter_specification], ALGORITHM=INSTANT;
此更改也会影响LOCK = ...语义。无需为即时算法指定LOCK。如果使用ALGORITHM = INSTANT,则LOCK不能设置为DEFAULT以外的任何其他值,否则会出现错误:
ALTER TABLE t1 ALTER COLUMN i SET DEFAULT 11, ALGORITHM=INSTANT, LOCK=NONE; ERROR HY000: Incorrect usage of ALGORITHM=INSTANT and LOCK=NONE/SHARED/EXCLUSIVE # ALGORITHM=INSTANT and LOCK=DEFAULT are OK though. ALTER TABLE t1 ALTER COLUMN i SET DEFAULT 13, ALGORITHM=INSTANT, LOCK=DEFAULT;
ALTER TABLE t1 ALTER COLUMN i SET DEFAULT 12, DROP COLUMN j, ALGORITHM=INSTANT; ERROR 0A000: ALGORITHM=INSTANT is not supported for this operation. Try ALGORITHM=COPY/INPLACE
当前,Innodb的即时DDL支持如下操作
- Change index option
- Rename table (in ALTER way)
- SET/DROP DEFAULT
- MODIFY COLUMN
- Add/drop virtual columns
- Add columns(non-generated) – 我们称之为即时DDL
mysql> CREATE TABLE t1 (a INT, b INT, KEY(b)); Query OK, 0 rows affected (0.70 sec) mysql> # Modify the index can be instant if it‘s a trivial change mysql> ALTER TABLE t1 DROP KEY b, ADD KEY b(b) USING BTREE, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.14 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> # Rename the table through ALTER TABLE can be instant mysql> ALTER TABLE t1 RENAME TO t2, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.26 sec) mysql> # SET DEFAULT to a column can be instant mysql> ALTER TABLE t2 ALTER COLUMN b SET DEFAULT 100, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.09 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> # DROP DEFAULT to a column can be instant mysql> ALTER TABLE t2 ALTER COLUMN b DROP DEFAULT, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> # MODIFY COLUMN can be instant mysql> ALTER TABLE t2 ADD COLUMN c ENUM(‘a‘, ‘b‘, ‘c‘), ALGORITHM = INSTANT; Query OK, 0 rows affected (0.35 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE t2 MODIFY COLUMN c ENUM(‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘), ALGORITHM=INSTANT; Query OK, 0 rows affected (0.12 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> # ADD/DROP virtual column can be instant mysql> ALTER TABLE t2 ADD COLUMN (d INT GENERATED ALWAYS AS (a + 1) VIRTUAL), ALGORITHM = INSTANT; Query OK, 0 rows affected (0.38 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE t2 DROP COLUMN d, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.40 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> # Do two operations instantly in the same statement mysql> ALTER TABLE t2 ALTER COLUMN a SET DEFAULT 20, ALTER COLUMN b SET DEFAULT 200, ALGORITHM = INSTANT; Query OK, 0 rows affected (0.20 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DROP TABLE t2; Query OK, 0 rows affected (0.36 sec)
它的工作原理是什么
即时DDL的原理实现描述的确实比较晦涩,其原理下面两张图大概也能表述出来,简单说就是:相对原始的新增字段就将整张表重建相比,instant加字段的方式进修改元数据来提升性能。
2,“即时”加字段的过程:基于行的存储规则发生变化之后(增加字段),仅修改元数据
,
3,“即时”加字段之后,查询的处理过程。
4,“即时”加字段后,新增数据的处理
mysql> CREATE TABLE t1 (a INT, b INT); Query OK, 0 rows affected (0.06 sec) mysql> SELECT table_id, name, instant_cols FROM information_schema.innodb_tables WHERE name LIKE ‘%t1%‘; +----------+---------+--------------+ | table_id | name | instant_cols | +----------+---------+--------------+ | 1065 | test/t1 | 0 | +----------+---------+--------------+ 1 row in set (0.22 sec) mysql> SELECT table_id, name, has_default, default_value FROM information_schema.innodb_columns WHERE table_id = 1065; +----------+------+-------------+---------------+ | table_id | name | has_default | default_value | +----------+------+-------------+---------------+ | 1065 | a | 0 | NULL | | 1065 | b | 0 | NULL | +----------+------+-------------+---------------+ 2 rows in set (0.38 sec)
mysql> ALTER TABLE t1 ADD COLUMN c INT, ADD COLUMN d INT DEFAULT 1000, ALGORITHM=INSTANT; Query OK, 0 rows affected (0.07 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> SELECT table_id, name, instant_cols FROM information_schema.innodb_tables WHERE name LIKE ‘%t1%‘; +----------+---------+--------------+ | table_id | name | instant_cols | +----------+---------+--------------+ | 1065 | test/t1 | 2 | +----------+---------+--------------+ 1 row in set (0.03 sec) mysql> SELECT table_id, name, has_default, default_value FROM information_schema.innodb_columns WHERE table_id = 1065; +----------+------+-------------+---------------+ | table_id | name | has_default | default_value | +----------+------+-------------+---------------+ | 1065 | a | 0 | NULL | | 1065 | b | 0 | NULL | | 1065 | c | 1 | NULL | | 1065 | d | 1 | 800003e8 | +----------+------+-------------+---------------+ 4 rows in set (0.36 sec)
mysql> ALTER TABLE t1 ADD COLUMN e VARCHAR(100) DEFAULT ‘Hello MySQL!‘; Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> SELECT table_id, name, instant_cols FROM information_schema.innodb_tables WHERE name LIKE ‘%t1%‘; +----------+---------+--------------+ | table_id | name | instant_cols | +----------+---------+--------------+ | 1065 | test/t1 | 2 | +----------+---------+--------------+ 1 row in set (0.03 sec) mysql> SELECT table_id, name, has_default, default_value FROM information_schema.innodb_columns WHERE table_id = 1065; +----------+------+-------------+--------------------------+ | table_id | name | has_default | default_value | +----------+------+-------------+--------------------------+ | 1065 | a | 0 | NULL | | 1065 | b | 0 | NULL | | 1065 | c | 1 | NULL | | 1065 | d | 1 | 800003e8 | | 1065 | e | 1 | 48656c6c6f204d7953514c21 | +----------+------+-------------+--------------------------+ 5 rows in set (0.36 sec)
- 在较旧的版本中,将预先检查行大小,因此ADD COLUMN在开始时将失败。但是,使用新的即时ADD COLUMN,行大小将仅在以后对行进行更新时进行检查。
- 在早期版本中,如果表或索引已损坏,则可以通过重建表来“修复”问题。使用即时添加列会带来更多挑战,我们正在寻找减轻这种情况的方法。
- 仅支持在一条语句中添加列,也就是说,如果同一条语句中还有其他非INSTANT操作,则无法立即完成
- 仅支持最后添加列,不支持在现有列中间
- 不支持很少使用的COMPRESSED行格式
- 不支持已经有全文索引的表
- 不支持DD表空间中的任何表(???)
- 不支持临时表(随COPY一起提供)
以上是关于MySQL 8.0 InnoDB对即时加字段的会支持(instant add column)(译)的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 8.0 innodb_undo_tablespace废弃掉