为啥 MySQL 会挂在这个简单的子查询上?
Posted
技术标签:
【中文标题】为啥 MySQL 会挂在这个简单的子查询上?【英文标题】:Why is MySQL hanging on this simple subquery?为什么 MySQL 会挂在这个简单的子查询上? 【发布时间】:2017-07-23 01:25:05 【问题描述】:我有这个在大约 5 秒内运行并返回大约 500 条记录的简单查询,但是为什么我尝试在复合语句中使用它 mysql 只是挂起
SELECT DISTINCT ARTIST_ID FROM WORK
GROUP BY ARTIST_ID
HAVING AVG(WORK_MILLIS_VIEWED) > 10
然而,下面的查询永远不会终止。根据进程列表,它只是创建了一个临时表,尽管它的运行时间应该只比子查询稍长一些,因为艺术家表非常小。
SELECT ARTIST_NAME FROM ARTIST
WHERE ARTIST_ID IN (SELECT DISTINCT ARTIST_ID
FROM WORK GROUP BY ARTIST_ID
HAVING AVG(WORK_MILLIS_VIEWED) > 10)
我犯了一个愚蠢的错误吗?数据库似乎没有做任何其他事情。
【问题讨论】:
【参考方案1】:MySQL 很难处理 WHERE 子句中的子查询。它通常会决定多次运行子查询(每次与子查询比较的不同 ARTIST_ID 值一次),即使您知道并且我知道子查询不会更改。
解决方法是在 FROM 子句中运行子查询并加入它:
SELECT A.ARTIST_NAME
FROM (
SELECT ARTIST_ID FROM WORK
GROUP BY ARTIST_ID HAVING AVG(WORK_MILLIS_VIEWED) > 10
) AS T
JOIN ARTIST A ON A.ARTIST_ID = T.ARTIST_ID
这将至少只运行一次子查询,并在连接到另一个表实例时将其存储在一个临时表中。
您还将受益于按该顺序对列对 (ARTIST_ID, WORK_MILLIS_VIEWED)
的索引。
【讨论】:
啊,我明白了,所以 MySQL 正在重复聚合查询,这大约需要 500x5 秒 - 但我可以更改隔离级别,它应该会消失。 @awiebe - 如果隔离级别有这种效果,请告诉我们。 @Rick James - 好吧,看起来我可以更改隔离级别,因为我的数据库不活跃,这适用于我的应用程序,但对其他人不利。在这种情况下,最好的办法似乎是获取子查询表上的锁。 好的,最后,我使用了表锁,将统计数据拉入我的业务逻辑,然后将它们放回艺术家中并进行更新。此操作不适用于事务存储引擎,因此您能做的最好的事情就是暂停事务片刻,快速运行批处理作业,更新然后解锁。以上是关于为啥 MySQL 会挂在这个简单的子查询上?的主要内容,如果未能解决你的问题,请参考以下文章