items中的数据集包含大约440万行
updatedcreated分别在每个表上索引

EXPLAIN SELECT i.id, j.id
    FROM jobs j
JOIN items i ON j.items_id = i.id
WHERE j.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
    OR j.created > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
    OR i.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE);

我得到的是:
1   SIMPLE  i   index   PRIMARY,updated_idx                     updated_idx       5     NULL            4168353    Using index
1   SIMPLE  j   ref     items_id_idx,updated_idx,created_idx    items_id_idx      9      my_db.i.id     1          Using where

正如您所看到的,在使用updated_idx时,这些项仍在接近全表扫描时运行。
为什么会发生这种事,我能避免吗?
也尝试过,但表现更差:
EXPLAIN SELECT i.id, j.id
    FROM jobs j
WHERE j.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
    OR j.created > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
    OR j.items_id IN
         (SELECT i.id FROM items i WHERE i.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE));

最佳答案

MySql没有很好地优化where条件或条件。将查询重写为3个用union连接的单独选择。这样,每个查询都可以使用适当的索引:

SELECT i.id, j.id
    FROM jobs j
JOIN items i ON j.items_id = i.id
WHERE j.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
UNION DISTINCT
SELECT i.id, j.id
    FROM jobs j
JOIN items i ON j.items_id = i.id
WHERE j.created > DATE_SUB(NOW(), INTERVAL 60 MINUTE)
UNION DISTINCT
SELECT i.id, j.id
    FROM jobs j
JOIN items i ON j.items_id = i.id
WHERE i.updated > DATE_SUB(NOW(), INTERVAL 60 MINUTE);

关于mysql - 如何防止此JOIN查询执行几乎全表扫描,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33489206/

10-12 14:36
查看更多