AWS RDS下MySQL ADD COLUMN慢
Posted
技术标签:
【中文标题】AWS RDS下MySQL ADD COLUMN慢【英文标题】:MySQL ADD COLUMN slow under AWS RDS 【发布时间】:2021-10-20 16:10:56 【问题描述】:我有一个具有以下设置的 RDS mysql:
类:db.m5.xlarge 存储:预置 1000 IOPS (SSD)然后我想在一个大小约为 20 GB 的表中添加几列(根据INFORMATION_SCHEMA.files
)。这是我的声明:
ALTER TABLE MY_TABLE
ADD COLUMN NEW_COLUMN_1 DECIMAL(39, 30) NULL,
ADD COLUMN NEW_COLUMN_2 DECIMAL(39, 30) NULL,
ADD COLUMN NEW_COLUMN_3 INT(10) UNSIGNED NULL,
ADD CONSTRAINT SOME_CONSTRAINT FOREIGN KEY (NEW_COLUMN_3) REFERENCES SOME_OTHER_TABLE(SOME_OTHER_PK),
ADD COLUMN NEW_COLUMN_4 DATE NULL;
此查询需要 172 分钟才能执行。大部分时间都花在将数据处理到临时表上。
在该操作期间,没有执行其他查询(读取或写入)。我只有自己的数据库。 SHOW FULL PROCESSLIST
说 State
等于 copy to tmp table
我的查询。
我不明白的是,AWS RDS 控制台告诉我写入吞吐量在 30 MB/s 和 35 MB/s 之间持续了 172 分钟。
假设写入吞吐量为 30 MB/s,我应该能够写入 30 * 60 * 172 = 309600 MB = 302 GB。这比操作期间创建的临时表的大小 (20 GB) 大得多。
那么两个问题:
-
mysql/rds 在我的临时表旁边写了什么?有没有办法禁用它,以便我可以获得创建临时表的全部带宽?
有什么方法可以加速该操作吗?写入 20 GB 数据需要 3 小时似乎相当长。
【问题讨论】:
最好在dba.stackexchange.com提出这个问题 【参考方案1】:我使用的是 MySQL 5.7。根据MySQL blog post,8.0 版改进了这种情况:“InnoDB 现在支持 Instant ADD COLUMN”。
因此,我更改了查询以使用新功能。
-- Completes in 0.375 seconds!
ALTER TABLE MY_TABLE
ADD COLUMN NEW_COLUMN_1 DECIMAL(39, 30) NULL,
ADD COLUMN NEW_COLUMN_2 DECIMAL(39, 30) NULL,
ADD COLUMN NEW_COLUMN_3 INT(10) UNSIGNED NULL,
-- 'ALGORITHM=INSTANT' is not compatible with foreign keys.
-- The foreign key will need to be added in another statement
-- ADD CONSTRAINT SOME_CONSTRAINT FOREIGN KEY (NEW_COLUMN_3) REFERENCES SOME_OTHER_TABLE(SOME_OTHER_PK),
ADD COLUMN NEW_COLUMN_4 DATE NULL,
-- the new option
ALGORITHM=INSTANT;
-- This completed in about 6 minutes.
-- Adding the foreign creates an index under the hood.
-- This index was 1.5 GB big.
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE MY_TABLE
ADD FOREIGN KEY (NEW_COLUMN_3) REFERENCES SOME_OTHER_TABLE(SOME_OTHER_PK);
SET FOREIGN_KEY_CHECKS=1;
所以我的结论:
如果可以的话,升级到 MySQL 8 确保始终使用(如果可能)ALGORITHM=INSTANT
选项。
【讨论】:
【参考方案2】:InnoDB 可能是您正在使用的存储引擎,因为它是默认存储引擎。 InnoDB 会执行一些看似多余的 I/O,以确保没有数据丢失。
例如:
在缓冲池中修改的数据和索引页必须写入表空间。在添加列的过程中,表格可能需要拆分一些页面,因为行变得更宽,每页容纳的行更少。 在将页面写入表空间期间,InnoDB 首先将这些页面写入双写缓冲区,以确保在页面写入期间发生崩溃时不会丢失数据。 事务被写入 InnoDB 重做日志,这甚至可能导致多次覆盖日志中的同一块。 如果为复制目的而启用,事务也会写入二进制日志。尽管在 ALTER TABLE 语句的转换中这不应该是一个很大的成本,因为 DDL 语句总是以语句格式而不是行格式写入二进制日志。您还询问了如何加快 ALTER TABLE 的速度。希望它运行得更快的原因通常是因为在 ALTER TABLE 期间,表被锁定并且可能会阻塞并发查询。
在我的公司,我们使用免费工具pt-online-schema-change,因此我们可以在更改表格时或多或少地继续使用表格。以这种方式完成更改实际上需要更长的时间,但它并没有那么不方便,因为它不会阻止我们对表的访问。
【讨论】:
以上是关于AWS RDS下MySQL ADD COLUMN慢的主要内容,如果未能解决你的问题,请参考以下文章
使用 AWS RDS 的 Django `TransactionTestCase` 测试用例非常慢