我在数据库中运行某个查询时经常遇到以下错误(所有表都使用InnoDB存储引擎):“尝试获取锁定时发现死锁;尝试重新启动事务”
查询为DELETE FROM sessions WHERE userid != 0 AND lastactivity < 1289594761 AND admin = 1 AND userid NOT IN (SELECT userid FROM users WHERE (userflags & 1048576))
当我将NOT IN部分添加到我的WHERE语句时,错误开始发生。 为什么这会导致问题,我该怎么做才能防止这种情况发生?
答案 0 :(得分:2)
一个简单的解决方案是将其分成两个连续的查询。即,:
将用户标识选择到#tmptable FROM users WHERE(userflags&amp; 1048576);
DELETE FROM sessions WHERE userid!= 0 AND lastactivity&lt; 1289594761 AND admin = 1 AND userid NOT IN(从#tmptable中选择userid);
这样您就可以使用第二个表中的值的本地会话副本,而不会导致读取锁定。但是,这只是一个快速而肮脏的解决方案。如果您将定期重新使用它,更好的解决方案是分析触及这两个表的所有活动的事务锁定设置并重写查询。
答案 1 :(得分:2)
大概你会更频繁地得到错误,因为现在这是一个慢得多的查询。
&
上的userflags
操作使子查询无法索引。标记字通常不是好的模式设计,因为它们需要计算来抵消索引。如果您正在进行大量的测试查询,那么单独的小数据类型列(例如TINYINT
)可能会更好。
如果您的架构按其可能的方式工作,您应该能够使用简单的JOIN执行此操作,该JOIN通常比子查询执行得更好:
DELETE sessions
FROM sessions
JOIN users ON users.userid=sessions.userid
WHERE sessions.lastactivity<1289594761 AND admin=1
AND (users.userflags&1048576)=0
(DELETE
上的连接是MySQL中的非ANSI SQL扩展。)