MySQL (InnoDB) 中发现死锁

发布于 2024-10-02 08:18:47 字数 312 浏览 5 评论 0原文

在数据库中运行某个查询时(所有表都使用 InnoDB 存储引擎),我经常收到以下错误:“尝试获取锁定时发现死锁;尝试重新启动事务”

查询是 DELETE FROM session WHERE userid != 0 AND 最后活动 < 1289594761 AND admin = 1 AND userid NOT IN (SELECT userid FROM users WHERE (userflags & 1048576))

当我将 NOT IN 部分添加到 WHERE 语句中时,错误开始发生。 为什么这会引起问题?我可以采取什么措施来防止这种情况发生?

I'm getting the following error pretty often when running a certain query in my database (all tables use the InnoDB storage engine): "Deadlock found when trying to get lock; try restarting transaction"

The query is DELETE FROM sessions WHERE userid != 0 AND lastactivity < 1289594761 AND admin = 1 AND userid NOT IN (SELECT userid FROM users WHERE (userflags & 1048576))

The errors started to occur when I've added the NOT IN part to my WHERE statement.
Why is this causing issues and what can I do to prevent this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

滴情不沾 2024-10-09 08:18:47

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

SELECT userid into #tmptable FROM users WHERE (userflags & 1048576);

从会话中删除,其中 userid != 0 AND lastactivity < 1289594761 AND admin = 1 AND userid NOT IN(从 #tmptable 中选择用户 ID);

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

An easy solution would be to separate this into two consecutive queries. I.e.,:

SELECT userid into #tmptable FROM users WHERE (userflags & 1048576);

DELETE FROM sessions WHERE userid != 0 AND lastactivity < 1289594761 AND admin = 1 AND userid NOT IN (select userid from #tmptable);

That way you're working with a local session copy of the values from the second table and not causing a read lock on it. However, this is just a quick-and-dirty solution. A better solution would be to analyze the transaction lock settings from all activities that touch these two tables and to rewrite the query, if you'll be re-using it regularly.

思慕 2024-10-09 08:18:47

想必您会更频繁地收到错误,因为现在查询速度要慢得多。

userflags 上的 & 操作使子查询不可索引。标志词通常不是好的模式设计,因为它们需要破坏索引的计算。如果您经常进行位测试查询,则单独的小数据类型列(例如 TINYINT)可能会更好。

如果您的模式按照它看起来的方式工作,您应该能够使用简单的 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 上的联接是非 ANSI SQL 扩展在 MySQL 中。)

Presumably you get the error more often because this is now a much slower query.

The & op on userflags makes the subquery unindexable. Flag words aren't usually good schema design, as they require computation that defeats indexing. If you are doing bit testing queries a lot, separate columns of small datatypes (eg TINYINT) may be better.

If your schema works the way it looks like it might, you should be able to do this using a simple JOIN, which usually performs better than a subqueries:

DELETE sessions
FROM sessions
JOIN users ON users.userid=sessions.userid
WHERE sessions.lastactivity<1289594761 AND admin=1
AND (users.userflags&1048576)=0

(joins on DELETE is a non-ANSI SQL extension in MySQL.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文