有问题的数据库:AWS RDS、MySQL 8、InnoDB。GP3 存储。
我正在尝试将行批量插入到数据库中的多个表中。
我省略了目标表中的所有二级索引,它只有 PK。目标表未分区。
导入的源数据(不在 MySQL 中)按日期范围分区。对于每个分区,我都有一个脚本,它选择一批数据并将其插入到 MySQL。每个分区的批处理循环脚本同时并行运行。
每个批次作为每个表的 pandas 数据帧加载,完成各种转换,然后使用 pandas to_sql
“multi”插入方法将该批次的数据帧插入到 MySQL(在一个数据库事务中)。
我可以想出各种方法来改进这一点。所有 MySQL 批量插入建议中出现的两个建议是 a) 按 PK 顺序插入和 b) 使用LOAD DATA IN FILE
. 我目前两者都不做。但在我彻底重写所有代码之前,我想了解运行当前代码时看到的症状:
我们可以看到导入运行了约 1 小时。并行批处理脚本的数量始终保持一致。批量大小始终保持一致。每个批次需要约 60 秒的时间来处理和插入。在上图中,约 200 个批次(数百万行)已成功处理。但 IOPS 在 30 分钟内大致线性增加,直到达到预配置限制并受到限制。
我的问题是:如果我的插入速率恒定,为什么 IOPS 不断线性增加?
在提出问题之前我对此有一个假设,但还有很多其他可能发生的事情我可能不知道。
最后我开始检验我的假设,它似乎是正确的。
正如问题中提到的,所有二级索引(以及唯一和外键约束)都已从表中省略。但主键保留在原处。
保留 PK 的原因是我读过一些建议,在导入后添加 PK 会非常昂贵,因为由于是“聚集”索引,它必须重建整个表。
我在本地计算机上使用较小的数据(约 250k 行)进行了一些测试,并观察到省略 PK + 之后添加它比仅在 PK 仍然存在的情况下插入要慢。
然而,当运行全尺寸导入并观察不断增加的 IOPS 时,我猜测这可能是由于我们并行插入行的方式导致的,导致插入不可能按照严格的 PK 顺序到达。假设是一批行的每次提交都必须重新洗牌 PK 索引,因此随着索引大小的增长,每次提交的工作量线性增长。
所以我重新运行导入并删除 PK
CREATE TABLE
并看到以下内容:...漂亮的平面图,远低于 IOPS 限制。
所以我现在已经获得了所有数据,我“只需”重新添加必要的索引。