【问题标题】:How to prevent this JOIN query from doing an almost full table scan如何防止此 JOIN 查询进行几乎全表扫描
【发布时间】:2016-02-03 00:29:18
【问题描述】:

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 join indexing


    【解决方案1】:

    MySql 没有优化或者条件在 where 条件太好。将您的查询重写为与联合连接的 3 个单独的选择。这样每个查询都可以使用适当的索引:

    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);
    

    【讨论】:

    • 嗯,这比我想象的要容易。谢谢!
    • 请注意,这需要 3 个索引,而 OP 似乎有。
    猜你喜欢
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 2021-06-29
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    相关资源
    最近更新 更多