SELECT FOR UPDATE与UPDATE,然后SELECT

时间:2011-02-16 08:49:13

标签: mysql performance innodb

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

  1. START TRANSACTION
  2. SELECT FOR UPDATE(SELECT pk FROM table WHERE status ='new'LIMIT 100 FOR UPDATE)
  3. UPDATE(UPDATE表SET状态='已锁定'在X和Y之间的位置)
  4. COMMIT
  5. DELETE(删除表格WHERE pk BETWEEN X和Y)
  6. 来自forum.percona.com的人给了我一条建议 - 不要使用SELECT FOR UPDATE和UPDATE,因为执行事务需要更长的时间(2个查询),并且等待导致的锁定超时。他们的建议是(自动提交):

    1. 更新(更新表SET状态='已锁定',线程= Z LIMIT 100)
    2. SELECT(SELECT pk FROM table WHERE thread = Z)
    3. DELETE(删除表格WHERE pk BETWEEN X和Y)
    4. 它本来应该提高性能。然而,相反,我得到了更多的死锁并等待锁定超时比以前......

      我读了很多关于优化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 个答案:

答案 0 :(得分:2)

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

  1. 您的表中有许多行需要处理。
  2. 从该表中选择一行(用于更新),以便其他线程无法访问同一行。
  3. 完成后,您更新行并提交交易。
  4. 然后从数据库中删除该行。
  5. 如果是这种情况,那么你做的是正确的事情,因为这将比你提到的第二种方法具有更少的锁定。

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

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