INNER JOIN 的时候,加锁的顺序是怎样的?

2022-09-16 09:52:27 +08:00
 zhanglintc

这两天遇到一个死锁的问题,两个程序同时使用 delete 删除两张表,A 程序使用的是T1 LEFT JOIN T2,B 程序使用的是T2 INNER JOIN T1。此时会出现死锁。

因为两个程序的 SQL 连结表的时候,T1 、T2 表的顺序不同,所以尝试把 B 程序T2 INNER JOIN T1调整成T1 INNER JOIN T2,依然会出现死锁。

最后把 B 程序也改成 LEFT JOIN:T1 LEFT JOIN T2,多次尝试后没有发生死锁。但是如果把 B 程序改成T2 LEFT JOIN T1的话,会非常容易发生死锁。

而且SHOW ENGINE INNODB STATUS查看死锁信息信息的时候明确可以看到是record lock

所以我想问的是,是不是T1 LEFT JOIN T2的时候,会优先把 T1 里的所有 record 锁上,然后再锁 T2 里的 record 。 但是T1 INNER JOIN T2的时候,顺序就不一定了。

我猜测的是:

有人知道是不是这么回事吗?

1212 次点击
所在节点    问与答
1 条回复
zhanglintc
2022-09-27 14:27:10 +08:00
已经破案了,可以参考这篇文章: https://blog.csdn.net/mccand1234/article/details/105455626

总结一下就是,正常情况下,`T1 INNER JOIN T2`的确是先锁左表 T1 ,然后锁右表 T2 。
但是当 T1 表的数据量**远大于**T2 表的情况下,优化器可能会先读取 T2 表,然后读取 T1 表。此时读取顺序就跟书写顺序无关了。在我这个 case 里就表现为无论如何都会发生死锁。

然后可以通过`STRAIGHT_JOIN`替换`INNER JOIN`来强制保证先锁左表,再锁右表。

还有就是 LEFT JOIN 是可以保证先锁左表再锁右表的。

最后想看锁表顺序可以通过`EXPLAIN`来看。比如`EXPLAIN SELECT T1 AS tab1 INNER JOIN T2 AS tab2`查看先读取的 T1 还是 T2 表。先读哪个就会先锁哪个。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/880452

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX