【问题标题】:InnoDB deadlock with lock modes S and X具有锁定模式 S 和 X 的 InnoDB 死锁
【发布时间】:2011-10-27 02:12:02
【问题描述】:

在我的应用程序中,我有两个不时发生的查询(来自不同的进程),这会导致死锁。

查询 #1

UPDATE tblA, tblB SET tblA.varcharfield=tblB.varcharfield WHERE tblA.varcharfield IS NULL AND [a few other conditions];

查询 #2

INSERT INTO tmp_tbl SELECT * FROM tblA WHERE [various conditions];

这两个查询都需要很长时间,因为这些表有数百万行。当查询 #2 运行时,tblA 似乎被锁定在模式 S。查询#1 似乎需要X 锁。由于这与 S 锁不兼容,因此查询 #1 最多等待 30 秒,此时我会遇到死锁:

序列化失败:1213 尝试获取锁时发现死锁;尝试重启事务

根据我读到的in the documentation,我认为我有几个选择:

  1. 在 tblA.varcharfield 上设置索引。不幸的是,我认为这将需要一个非常大的索引来存储 varchar(512) 的字段。 (请参阅下面的编辑...这不起作用。)
  2. 使用SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 禁用锁定。我不明白这意味着什么,并且担心数据损坏。我目前没有在我的应用程序中使用显式事务,但我可能会在未来的某个时候使用。
  3. 将耗时的查询拆分成小块,以便它们可以在 MySQL 中排队和运行,而不会达到 30 秒超时。这并不能真正解决问题的核心,而且我担心当我的数据库服务器繁忙时,问题会再次发生。
  4. 只是一遍又一遍地重试查询...这不是我希望的选择。

我应该如何进行?我应该考虑其他方法吗?


编辑:我已尝试在 varcharfield 上设置索引,但表仍处于锁定状态。我怀疑锁定发生在UPDATE 部分实际执行时。还有其他解决此问题的建议吗?

【问题讨论】:

    标签: mysql locking innodb deadlock


    【解决方案1】:

    A.如果我们假设索引varcharField 会占用大量磁盘空间并且添加新列不会对您造成严重影响,我可以建议以下方法:

    1. 创建数据类型为“tinyint”的新字段
    2. 索引它。
    3. 如果varcharField 为空,此字段将存储 0,否则为 1。
    4. 重写第一个查询以根据新字段进行更新。在这种情况下,它不会导致整个表锁定。

    希望对你有帮助。

    【讨论】:

    • 感谢您的建议。按照 Darhazer 的建议,我尝试使用索引,但无济于事。我怀疑UPDATE 必须在我的SELECT 被允许运行之前运行。您还有其他建议吗?
    • 如果还是有问题,请把show innodb status的结果放在“死锁”部分
    • 感谢您的帮助。我通过显式锁定表解决了这个问题。不幸的是,我认为死锁一定是由查询的其他部分引起的,由于 NDA,我无法透露。我对相关查询的简化是不够的。不过,我非常感谢您在解决这个问题方面的帮助。
    【解决方案2】:

    您只能索引 varchar 列的一部分,它仍然可以工作,并且需要更少的空间。只需指定索引大小:

    CREATE INDEX someindex ON sometable (varcharcolumn(32))
    

    【讨论】:

    • 感谢您的建议。我昨晚试过了,但仍然陷入僵局。我在SELECT 查询上运行了EXPLAIN,它们都按预期使用索引。我怀疑UPDATE 必须在我的SELECT 工作之前运行。
    • @Brad 你能在问题中添加解释吗?我想看看他们
    • 非常感谢您的帮助。我能够通过明确锁定表来解决这个问题。我认为问题是由于 NDA 而我无法透露的查询的一部分,并且我对问题的简化并没有充分表明问题。再次感谢您的帮助!
    【解决方案3】:

    我能够通过在两个查询周围添加明确的LOCK TABLE 语句来解决这个问题。结果证明这是一个更好的解决方案,因为每个查询都会影响很多记录,而且这两个都是后台进程。他们现在互相等待。

    http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html

    虽然这对我来说是一个不错的解决方案,但显然不是每个人的答案。用WRITE 锁定意味着你不能READ。只有READ 锁将允许其他人READ

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多