items中的数据集包含大约440万行updated
和created
分别在每个表上索引
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/