40秒奇怪的sql性能难题

edd*_*xie 2 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";
Run Code Online (Sandbox Code Playgroud)

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

所以分解:

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

运行0.1秒,只有39行匹配.

会员总数仅为~500.我不明白为什么这会花很长时间......我错过了什么?

我正在使用mysql 5.6在RDS上运行

Gor*_*off 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'
                 );
Run Code Online (Sandbox Code Playgroud)

为了提高性能,您需要一个索引events(memberId, createdAt).

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

对于SELECTs,这是在几个版本之前修复的.也许这个问题在非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 ;
Run Code Online (Sandbox Code Playgroud)

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