【问题标题】:Disadvantages of MySQL Row LockingMySQL 行锁定的缺点
【发布时间】:2012-09-26 03:33:13
【问题描述】:

我在 MySQL 中使用行锁定(事务)来创建作业队列。使用的引擎是 InnoDB。

SQL 查询

START TRANSACTION;
SELECT * 
FROM mytable 
WHERE status IS NULL 
ORDER BY timestamp DESC LIMIT 1 
FOR UPDATE;
UPDATE mytable SET status = 1;
COMMIT;

据此webpage

The problem with SELECT FOR UPDATE is that it usually creates a single synchronization point for all of the worker processes, and you see a lot of processes waiting for the locks to be released with COMMIT.

问题:这是否意味着在执行第一个查询时,需要一些时间才能完成之前的事务,当第二个类似查询发生在第一个事务提交之前,它必须在执行查询之前等待它完成?如果这是真的,那么我不明白为什么单行的行锁定(我假设)会影响下一个不需要读取该锁定行的事务查询?

此外,是否可以通过执行UPDATE 而不是事务来解决此问题(并且仍然实现行锁定对作业队列的效果)?

UPDATE mytable SET status = 1
WHERE status IS NULL
ORDER BY timestamp DESC
LIMIT 1

【问题讨论】:

  • 锁定是基于存储引擎的——你用的是什么?
  • 谢谢(还有 9 个字符)
  • 不幸的是,您的 status IS NULL ORDER BY 查询保证了对 mytable. 的全表扫描 索引对于 IS NULL 搜索没有帮助。如果您可以重构代码以消除 NULL 状态值、搜索其他值并为此使用索引,您将节省大量的表扫描时间。
  • status的默认值设置为0并对其进行索引会更好吗?
  • 是的,该方案将使您的“查找下一个符合处理条件的 mytable 行”操作更快。

标签: php mysql sql rabbitmq


【解决方案1】:

如果您将 FOR UPDATE 与使用页锁或行锁的存储引擎一起使用,则查询检查的行将被写锁定,直到当前事务结束。使用LOCK IN SHARE MODE 设置一个共享锁,允许其他事务读取检查的行但不允许update or delete 它们。 关于这个查询

UPDATE mytable SET status = 1
WHERE status IS NULL
ORDER BY timestamp DESC
LIMIT 1

因为innodb

在处理 SQL 语句的过程中自动获取锁我认为它的工作原理是一样的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 2013-07-27
    • 2012-04-06
    相关资源
    最近更新 更多