来自 Go 的连续 MySQL 查询在某个点后变得更慢
Consecutive MySQL queries from Go become MUCH slower after some point
我正在用 go 编写一个作业,它经过一些 MySQL tables,根据一些条件选择一些行,从中提取电子邮件地址并向每个行发送电子邮件.
过滤过程会查看 table(我们称之为 storage
),它非常大(已转储 ~6gb),如下所示:
Columns:
id varchar(64) PK
path varchar(64) PK
game varchar(64)
guid varchar(64)
value varchar(512)
timestamp timestamp
有两个索引:(id, path)
(如上所示的 PK)和 guid
。
该作业首先从一个 table 中检索一长串 guid,然后对它们进行批处理并在 storage
table:
上执行类似这样的连续查询
SELECT guid, timestamp FROM storage
WHERE game = 'somegame'
AND path = 'path' AND value = 'value' AND timestamp >= '2015-04-22 00:00:00.0' AND timestamp <= '2015-04-29T14:53:07+02:00'
AND guid IN ( ... )
其中 IN
子句包含一个 guid 列表。
我需要检索时间戳才能进一步过滤。
当 运行ning 针对我的本地 MySQL 时,一切都按预期进行,查询大约需要 180 毫秒,每批 1000 个 guid。
当 运行针对 Amazon RDS 上的同一个数据库 时,查询开始很快,但在某个时间点后,它们突然开始需要大约 30 秒,并继续这样做直到工作结束。
我尝试了很多方法来解决这个问题,但无法找出原因。一些注意事项:
- 该作业仅使用一个
sql.DB
对象。另外,我准备了一次上述声明并大量重复使用它。
- 一开始以为是因为RDS DB是运行ning MySQL 5.5,而我是运行ning 5.6。我做了一个 RDS 数据库的副本,升级到 5.6,运行 再次工作。问题又出现了。
- 两个数据库中的数据量相同:我转储了生产数据库并将其导入到我的本地数据库和运行作业中。相同的行为(它仍然在本地快速 运行)。
- RDS 节点的 AWS 监控没有显示任何明显的峰值。 CPU 使用率从 1% 跃升至 10%,作业似乎只打开了几个连接 (~4)。
- 我有一个同事 运行 在他们的 PC 上工作,指向 my MySQL 数据库,只是为了确保出色的性能没有源于连接是本地的这一事实。它 运行 和我的 PC 一样快(诚然,通过 LAN)。
- 我 运行 从我的本地 PC 和 一个 Amazon EC2 节点 针对 RDS 的作业,这是相当大的更接近RDS。从EC2开始,表现更好,但问题还是出现了。
- 作业并发度很高,每一步都有输入和输出通道(缓冲区大小为1000),工作由goroutines执行。在这些步骤之间,我有其他 goroutines 对前一个 goroutine 的输出进行批处理。
- 突然变慢,一个查询需要几毫秒,下一个需要几十秒。
我完全不知道为什么会这样。任何建议,将不胜感激。
所以,经过大量试验,我找到了解决方案。
我在涉及的 RDS 实例上使用磁存储,保证 运行大约 100 IOPS。这限制了我们查询数据的速度。
我用 2000 Provisioned IOPS 测试过,工作 运行 很快。
我正在用 go 编写一个作业,它经过一些 MySQL tables,根据一些条件选择一些行,从中提取电子邮件地址并向每个行发送电子邮件.
过滤过程会查看 table(我们称之为 storage
),它非常大(已转储 ~6gb),如下所示:
Columns:
id varchar(64) PK
path varchar(64) PK
game varchar(64)
guid varchar(64)
value varchar(512)
timestamp timestamp
有两个索引:(id, path)
(如上所示的 PK)和 guid
。
该作业首先从一个 table 中检索一长串 guid,然后对它们进行批处理并在 storage
table:
SELECT guid, timestamp FROM storage
WHERE game = 'somegame'
AND path = 'path' AND value = 'value' AND timestamp >= '2015-04-22 00:00:00.0' AND timestamp <= '2015-04-29T14:53:07+02:00'
AND guid IN ( ... )
其中 IN
子句包含一个 guid 列表。
我需要检索时间戳才能进一步过滤。
当 运行ning 针对我的本地 MySQL 时,一切都按预期进行,查询大约需要 180 毫秒,每批 1000 个 guid。
当 运行针对 Amazon RDS 上的同一个数据库 时,查询开始很快,但在某个时间点后,它们突然开始需要大约 30 秒,并继续这样做直到工作结束。
我尝试了很多方法来解决这个问题,但无法找出原因。一些注意事项:
- 该作业仅使用一个
sql.DB
对象。另外,我准备了一次上述声明并大量重复使用它。 - 一开始以为是因为RDS DB是运行ning MySQL 5.5,而我是运行ning 5.6。我做了一个 RDS 数据库的副本,升级到 5.6,运行 再次工作。问题又出现了。
- 两个数据库中的数据量相同:我转储了生产数据库并将其导入到我的本地数据库和运行作业中。相同的行为(它仍然在本地快速 运行)。
- RDS 节点的 AWS 监控没有显示任何明显的峰值。 CPU 使用率从 1% 跃升至 10%,作业似乎只打开了几个连接 (~4)。
- 我有一个同事 运行 在他们的 PC 上工作,指向 my MySQL 数据库,只是为了确保出色的性能没有源于连接是本地的这一事实。它 运行 和我的 PC 一样快(诚然,通过 LAN)。
- 我 运行 从我的本地 PC 和 一个 Amazon EC2 节点 针对 RDS 的作业,这是相当大的更接近RDS。从EC2开始,表现更好,但问题还是出现了。
- 作业并发度很高,每一步都有输入和输出通道(缓冲区大小为1000),工作由goroutines执行。在这些步骤之间,我有其他 goroutines 对前一个 goroutine 的输出进行批处理。
- 突然变慢,一个查询需要几毫秒,下一个需要几十秒。
我完全不知道为什么会这样。任何建议,将不胜感激。
所以,经过大量试验,我找到了解决方案。
我在涉及的 RDS 实例上使用磁存储,保证 运行大约 100 IOPS。这限制了我们查询数据的速度。
我用 2000 Provisioned IOPS 测试过,工作 运行 很快。