并发 MySQL 更新与 InnoDB 挂起(在 Amazon RDS 上)

Ala*_*lan 7 mysql innodb concurrency

我遇到了一个问题,即同时执行的多个 MySQL 更新将锁定并需要几分钟才能完成。我正在使用 InnoDB,所以我很困惑为什么会发生这种情况,因为每次更新只更新 1 行。我还使用了一个 m2.4xlarge RDS 实例(它们是最大的)。

卡住更新

这就是我正在做的事情:我有一个包含大约 100M 行的表,其中“views”是一列(已编入索引),我想更新大约 1M 行的视图。在几个不同的服务器上,我有一个这样的循环,其中每个服务器都有自己的一组要更新的行(伪代码):

mysql("set autocommit=0");
mysql("start transaction");

foreach($rows as $row) {
    mysql("update table set views=views+1 where id=$row[id]");
}

mysql("commit");
Run Code Online (Sandbox Code Playgroud)

这会遍历所有需要更新的行。当服务器数量很少时,它工作得很好,比如大约 4,但是当它增长到 10+ 时,更新开始立即挂在“更新”状态。没有说它正在等待锁定,它只是“更新”。这会发生大约 5 分钟,它最终将进行更新并继续循环并最终再次发生。

我不是在寻找进行更新的替代方法。拥有像 tmp 表和

update table,tmp_table set table.views = table.views+tmp_table.views where
  table.id = tmp_table.id
Run Code Online (Sandbox Code Playgroud)

锁定所有正在更新的行,直到它们全部完成(可能需要几个小时),这对我不起作用。他们必须在这些可怕的循环中。

我想知道为什么他们会陷入“正在更新”状态,以及我能做些什么来防止它。

tldr; 有 10 个以上的“更新”循环最终会同时锁定所有正在完成的更新,原因不明,直到他们决定最终进行更新并继续循环,直到它在几秒钟后再次发生。

显示变量:http : //pastebin.com/NdmAeJrz

显示引擎 INNODB 状态:http : //pastebin.com/Ubwu4F1h

Nic*_*mas 11

我不是在寻找进行更新的替代方法。拥有像 tmp 表之类的东西 [将] 锁定所有正在更新的行,直到它们全部完成(可能需要几个小时),这对我不起作用。他们必须在这些可怕的循环中。

我不同意。

RDBMS 的优势在于执行诸如“更新所有这些行”之类的集合操作。鉴于此,您的直觉应该告诉您,除非在极少数情况下,否则这些“可怕的循环”并不是最好的方法。

让我们看看您当前的更新逻辑并了解它在做什么。

首先,脚本中set autocommit=0行是不必要的。因为你明确地立即打开一个事务后,随着start transactionautocommit 自动变为禁用状态,直到您结束事务COMMITROLLBACK

现在是逻辑的核心:您已将所有这些单独的更新包装在一个大事务中的循环中。如果您在迭代更新背后的意图是减少锁定并增加并发性,那么包装的事务就违背了该意图。MySQL 必须在它更新的每一行上保持锁,直到事务提交,以便在事务失败或取消时立即回滚它们。此外,引擎没有提前知道将要锁定这个范围的行(这将使 MySQL 能够以适当的粒度发出锁),而是被迫快速发出大量行级锁。鉴于您要更新 100 万行,这对引擎来说是一个巨大的负担。

我提出两种解决方案:

  1. 打开autocommit并移除事务包装器。 MySQL 将能够在完成更新行后立即释放每个行锁。它仍然被迫在短时间内发出和释放大量锁,所以我怀疑这是否适合您。此外,如果在循环中途发生某些错误,由于工作不受事务限制,因此不会回滚任何内容。

  2. 在临时表中批量更新。你提到然后驳回了这个解决方案,但我打赌它会表现最好。你已经尝试过了吗?我将首先测试完整的百万行更新。如果这花费的时间太长,那么将工作分批成逐渐变小的块,直到找到最佳点:批次足够大,可以快速完成全部工作,但没有单个批次阻塞其他进程太长时间。这是DBA 在实时操作期间必须修改大量行时使用的常用技术。请记住,由于您的目标是最大程度地提高并发性,因此请继续autocommit并不要将任何此类工作包装到大量事务中,以便 MySQL 尽快释放其锁。

    请注意,随着批次逐渐变小,此解决方案最终会接近第一个解决方案。这就是为什么我相信这个解决方案会表现得更好:当数据库引擎可以将它的工作分成块时,它就会飞起来。

  • 我同意你的不同意见。喜欢细节。+1 !!! (2认同)