40秒奇怪的sql性能难题

时间:2017-08-06 14:33:04

标签: mysql sql

我正在运行查询以更新用户的字段,如下所示:

UPDATE Members SET abc = abc + 1 where Members.id in (
SELECT DISTINCT(memberId) FROM Events WHERE Events.createdAt > "2017-08-06 13:10:00";

令人震惊的是,有大约500名成员,此查询运行40秒......

所以分解:

SELECT DISTINCT(memberId) FROM Events WHERE Events.createdAt > "2017-08-06 13:10:00"

运行0.1秒,并且只有39行匹配。

会员总数仅约500人。我不明白为什么这会花费那么久......我错过了什么?

我在使用mysql 5.6的RDS上运行

1 个答案:

答案 0 :(得分:6)

尝试替换为exists

UPDATE Members m
    SET abc = abc + 1 
    WHERE EXISTS (SELECT 1
                  FROM events e
                  WHERE e.memberId = m.id AND
                        e.createdAt > '2017-08-06 13:10:00'
                 );

为了提高性能,您需要events(memberId, createdAt)上的索引。

我的猜测是MySQL为Members中的每一行运行子查询一次。这与你的计时时间一致 - 约0.1秒* ~500行约为50秒,距离40秒不远。

对于SELECT s,这在几个版本之前已经修复。也许这个问题在非SELECT查询中仍然存在。

您也可以将其写为:

UPDATE Members m JOIN
       (SELECT DISTINCT e.memberId
        FROM events e
        WHERE e.createdAt > '2017-08-06 13:10:00'
       ) e
       ON e.memberId = m.id
    SET abc = abc + 1 ;

这是否比exists版本更快,取决于数据的特征。如果没有建议的索引,这可能会更快。