Mysql 带锁模式S和X的InnoDB死锁
在我的应用程序中,我有两个查询(来自不同的进程),它们会导致死锁 查询#1Mysql 带锁模式S和X的InnoDB死锁,mysql,locking,innodb,deadlock,Mysql,Locking,Innodb,Deadlock,在我的应用程序中,我有两个查询(来自不同的进程),它们会导致死锁 查询#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]; 这两个查询都需要很长时间,因为这些表
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
锁不兼容,query#1最多会等待30秒,此时我会出现死锁:
序列化失败:尝试获取锁时发现1213死锁;尝试重新启动事务
根据我所读到的,我想我有几个选择:
设置会话事务隔离级别READ UNCOMMITTED禁用锁定;
。我不明白这意味着什么,我担心数据会被破坏。我目前在应用程序中不使用显式事务,但将来可能会使用编辑:我已尝试在varcharfield上设置索引,但表仍处于锁定状态。我怀疑当
更新
部分实际执行时会发生锁定。有没有其他解决此问题的建议?A.如果我们假设索引varcharField
占用大量磁盘空间,并且添加新列不会对您造成太大影响,我可以建议以下方法:
varcharField
为空,则此字段将存储0,否则为1希望有帮助。您只能索引varchar列的一部分,它仍然可以工作,并且需要的空间更少。只需指定索引大小:
CREATE INDEX someindex ON sometable (varcharcolumn(32))
我能够通过在两个查询周围添加显式的
locktable
语句来解决这个问题。这原来是一个更好的解决方案,因为每个查询都会影响很多记录,而且这两个都是后台进程。他们现在互相伺候
虽然这对我来说是个不错的解决方案,但显然不是每个人都能找到的答案。用
WRITE
锁定意味着您无法读取
。只有读取
锁定才允许其他人读取
谢谢您的建议。我昨晚试过了,但还是遇到了僵局。我在SELECT
查询中运行了EXPLAIN
,它们都使用了预期的索引。我怀疑必须先运行更新
,然后我的选择
才能工作。@Brad你能为问题添加解释吗?我想看看它们。我非常感谢你的帮助。通过显式锁定表,我可以绕过这个问题。我认为这个问题是由于保密协议我不能透露的问题的一部分,我在问题中的简化并没有充分说明这个问题。再次感谢您的帮助!谢谢你的建议。我曾尝试使用Darhazer建议的索引,但没有效果。我怀疑必须先运行更新
,然后才能允许运行我的选择
。您还有其他建议吗?如果仍然存在问题,请将显示innodb状态的结果放入“死锁”部分,谢谢您的帮助。我通过显式锁定表解决了这个问题。不幸的是,我认为死锁一定是由查询的其他部分引起的,由于保密协议的原因,我不能透露。我对这个问题的简化是不够的。不过,我非常感谢你在解决这个问题上的帮助。