【问题标题】:SELECT FOR UPDATE vs. UPDATE, then SELECTSELECT FOR UPDATE 与 UPDATE,然后 SELECT
【发布时间】:2011-06-28 05:02:33
【问题描述】:

我创建了一个服务应用程序,它使用多线程并行处理位于 InnoDB 表中的数据(大约 2-3 百万条记录,并且应用程序不再执行与 InnoDB 相关的查询)。每个线程对提到的表进行以下查询:

  1. 开始交易
  2. SELECT FOR UPDATE(SELECT pk FROM table WHERE status='new' LIMIT 100 FOR UPDATE)
  3. UPDATE(UPDATE table SET status='locked' WHERE pk BETWEEN X AND Y)
  4. 提交
  5. DELETE(从表中删除 X 和 Y 之间的 pk)

forum.percona.com 的人给了我一条建议——不要使用 SELECT FOR UPDATE 和 UPDATE,因为执行事务需要更长的时间(2 个查询),并导致等待锁定超时。他们的建议是(启用自动提交):

  1. UPDATE(UPDATE table SET status='locked',thread = Z LIMIT 100)
  2. SELECT (SELECT pk FROM table WHERE thread = Z)
  3. DELETE(从表中删除 X 和 Y 之间的 pk)

它应该可以提高性能。然而,相反,我遇到了比以前更多的死锁和等待锁超时......

我阅读了很多关于优化 InnoDB 的内容,并相应地调整了服务器,所以我的 InnoDB 设置是 99% 好的。第一个场景运行良好并且比第二个场景更好也证明了这一事实。 my.cnf 文件:

innodb_buffer_pool_size = 512M
innodb_thread_concurrency = 16
innodb_thread_sleep_delay = 0
innodb_log_buffer_size = 4M
innodb_flush_log_at_trx_commit=2

任何想法为什么优化没有成功?

【问题讨论】:

  • 您能否举例说明选择和更新查询?如果您通过主键访问行或使用范围索引 - 锁定间隙,则会产生很大的不同。
  • 好吧。猜猜我在哪里不去寻求建议......
  • 主题添加真实查询,请查看

标签: mysql performance innodb


【解决方案1】:

从你的流程描述中我了解到的是:

  1. 您的表中有很多行需要处理。
  2. 您从该表中选择了一行(用于更新),这样其他线程就无法访问同一行。
  3. 完成后,更新行并提交事务。
  4. 然后从数据库中删除该行。

如果是这种情况,那么您正在做正确的事情,因为与您提到的第二种方法相比,这将具有更少的锁。

您可以通过删除删除语句来进一步减少锁定争用,因为这将锁定整个表。而不是这样做添加一个标志(名为已处理的新列)并更新它。并在所有线程完成处理后删除最后的行。

您还可以通过批处理工作负载来使工作分配变得智能 - 在您的情况下,每个线程将要处理的行范围(可能使用 PK) - 在这种情况下,您可以进行简单的选择而无需FOR UPDATE 子句,它会很快工作。

【讨论】:

  • 如果是这种情况,那么您做的是正确的事情,因为与您提到的第二种方法相比,这将具有更少的锁 - 为什么?
  • 在这种情况下,您可以进行简单的选择,不需要 FOR UPDATE 子句,它会运行得很快 - 我运行 100 多个线程,这些线程使用 PK 范围来确定自己的工作负载
  • 在问题正文中添加了真实查询
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-23
  • 2017-12-15
  • 2017-12-05
  • 2014-03-10
相关资源
最近更新 更多