mysql - 选择更新与更新,然后选择

标签 mysql performance innodb

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

  1. 开始交易
  2. SELECT FOR UPDATE(SELECT pk FROM table WHERE status='new' LIMIT 100 FOR UPDATE)
  3. 更新(更新表 SET status='locked' WHERE pk BETWEEN X AND Y)
  4. 提交
  5. 删除(从表中删除 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. 删除(从表中删除 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

优化没有成功的原因是什么?

最佳答案

根据您的流程描述,我了解到:

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

如果是这种情况,那么您做对了,因为与您提到的第二种方法相比,这种方法的锁更少。

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

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

关于mysql - 选择更新与更新,然后选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5014303/

相关文章:

mysql - 内连接返回大量重复项

c++ - 快速读取带有 float 的文本文件

php - 如何优化服务器上​​的 html、css 运行时以获得更好的加载时间?

mysql - 为什么我的 InnoDB 表总是消失?我该如何预防?

只有一个 varchar 作为外键的 MySQL 表

Mysql转义函数;使用选择查询生成更新查询

php - 使用 jQuery 向 MySQL 表中插入数据

Mysql order by if 条件 - 错误的顺序

sql - 查询以某物开头和结尾的字符串的性能

mysql - 将数据从 myisam 复制到 innodb