如何让JOINS更快?

时间:2013-07-29 11:09:15

标签: mysql

我有这个查询开头:

SELECT DISTINCT spentits.*
FROM `spentits`
WHERE (spentits.user_id IN
         (SELECT following_id
          FROM `follows`
          WHERE `follows`.`follower_id` = '44'
            AND `follows`.`accepted` = 1)
       OR spentits.user_id = '44')
ORDER BY id DESC 
LIMIT 15 OFFSET 0

此查询执行10ms

但是,一旦我添加了一个简单的连接:

SELECT DISTINCT spentits.*
FROM `spentits`
LEFT JOIN wishlist_items ON wishlist_items.user_id = 44 AND wishlist_items.spentit_id = spentits.id
WHERE (spentits.user_id IN
         (SELECT following_id
          FROM `follows`
          WHERE `follows`.`follower_id` = '44'
            AND `follows`.`accepted` = 1)
       OR spentits.user_id = '44')
ORDER BY id DESC 
LIMIT 15 OFFSET 0

此执行时间增加11x。现在需要执行120ms。有趣的是,如果我删除LEFT JOIN子句 ORDER BY id DESC,则时间会回到10ms

我是数据库的新手,所以我不明白这一点。为什么删除这些条款中的任何一个会加快11x的速度?我怎样才能保持原样但速度更快?

我在每个表的spentits.user_idfollows.follower_idfollows.acceptedprimary ids上都有索引。

说明:

1   PRIMARY spentits    index   index_spentits_on_user_id   PRIMARY 4   NULL    15 Using where; Using temporary
1   PRIMARY wishlist_items  ref index_wishlist_items_on_user_id,index_wishlist_items_on_spentit_id  index_wishlist_items_on_spentit_id  5   spentit.spentits.id 1   Using where; Distinct
2   SUBQUERY    follows index_merge index_follows_on_follower_id,index_follows_on_following_id,index_follows_on_accepted

index_follows_on_follower_id,index_follows_on_accepted  5,2 NULL    566 Using intersect(index_follows_on_follower_id,index_follows_on_accepted); Using where

3 个答案:

答案 0 :(得分:2)

你也应该有索引:

  

wishlist_items.spentit_id

因为您正在加入该列

答案 1 :(得分:0)

LEFT JOIN很容易解释:所有条目与所有其他条目的交叉产品。然后应用连接的条件(在您的情况下:左侧的所有条目并在右侧找到拟合的条目)。因此,如果您的用过的表很大,那么服务器需要一些时间。建议你摆脱你的子查询并进行三次连接。从最小的表开始,以避免大量数据。

答案 2 :(得分:0)

在第二个示例中,subselect为每个spentits.user_id运行。

如果您这样写,它会更快,因为子选择运行一次:

SELECT DISTINCT spentits.*
FROM `spentits`, (SELECT following_id
          FROM `follows`
          WHERE `follows`.`follower_id` = '44'
            AND `follows`.`accepted` = 1)
       OR spentits.user_id = '44') as `follow`
LEFT JOIN wishlist_items ON wishlist_items.user_id = 44 AND wishlist_items.spentit_id = spentits.id
WHERE (spentits.user_id IN
         (follow)
ORDER BY id DESC 
LIMIT 15 OFFSET 0

如您所见,子选择移动到查询的FROM部分并创建一个虚构的tabel(或视图)。 这个虚构的表格是一个内联视图。

JOIN和内联视图每次都比WHERE部分中的子选择更快。