代码之家  ›  专栏  ›  技术社区  ›  ThiefMaster

在MySQL(InnoDB)中发现死锁

  •  0
  • ThiefMaster  · 技术社区  · 14 年前

    在数据库中运行某个查询时(所有表都使用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语句时,错误开始出现。 为什么这会引起问题,我能做些什么来防止这种情况发生?

    2 回复  |  直到 14 年前
        1
  •  2
  •   Cahit    14 年前

    一个简单的解决方案是将其分为两个连续的查询。即。,:

    从users WHERE(userflags&1048576)中选择userid进入tmptable;

    从userid所在的会话中删除!=0和lastactivity<1289594761和admin=1,用户id不在(从tmptable中选择用户id);

    这样,您就可以使用第二个表中值的本地会话副本,而不会对其造成读锁。然而,这只是一个快速而肮脏的解决方案。一个更好的解决方案是分析所有接触这两个表的活动的事务锁设置,并重写查询(如果您将定期使用它的话)。

        2
  •  2
  •   bobince    14 年前

    可能您会更频繁地得到错误,因为这现在是一个更慢的查询。

    这个 & 打开操作 userflags 使子查询无法编制索引。标记词通常不是很好的模式设计,因为它们需要计算来破坏索引。如果您经常执行位测试查询,请将小数据类型的列分开(例如 TINYINT )可能更好。

    如果架构的工作方式与预期的一样,则应该可以使用简单的联接来完成此操作,该联接通常比子查询执行得更好:

    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扩展。)