写这个查询的最佳方法是什么?几个JOINS

时间:2014-07-10 20:14:25

标签: mysql

我有这个查询(下面),虽然它确实有效我想知道它是否是最好的,因为它将对数千条​​记录。我会尝试尽力解释。

SELECT items.*, 
       p.file                        AS item_pic, 
       i_f.id                        AS favorite_id, 
       COALESCE(f.favorite_count, 0) AS favorite_count, 
       COALESCE(b.num_buys, 0)       AS num_buys, 
       COALESCE(c.comment_count, 0)  AS comment_count 
FROM   items i 
       INNER JOIN (SELECT file, 
                          item_id 
                   FROM   item_pics 
                   ORDER  BY item_pics.id ASC) AS p 
               ON p.item_id = i.id 
       LEFT JOIN (SELECT COUNT(*) AS favorite_count, 
                         item_id 
                  FROM   item_favorites 
                  GROUP  BY item_id) AS f 
              ON f.item_id = i.id 
       LEFT JOIN (SELECT COUNT(*) AS num_buys, 
                         item_id 
                  FROM   purchases 
                  GROUP  BY item_id) AS b 
              ON b.item_id = i.id 
       LEFT JOIN (SELECT COUNT(*) AS comment_count, 
                         item_id 
                  FROM   comments 
                  GROUP  BY item_id) AS c 
              ON c.item_id = i.id 
       LEFT JOIN item_favorites AS i_f 
              ON i.id = i_f.item_id 
                 AND i_f.userid = '14' 
GROUP  BY i.id 
LIMIT  0, 20

所以我们选择数据库中的项目。第一个连接用于图片(项目有多张图片,但我只想要一张)。

下次加入是收藏计数。每次用户收藏某些内容时,它会将其添加到带有一些信息的表格收藏夹中,因此我只想获取该项目的收藏夹总数。

接下来是此商品的购买数量。与收藏夹几乎相同。

之后是评论。再次,这就像购买和收藏计数一样。

最后一次加入是查看登录用户(id 14)是否已收藏此项,否则我使用COALESCE返回0。

就像我说这一切都能正常工作但是在购买表中加载大约6700个项目和大约180K行的表需要几秒钟,一次只能加载20个(我做滚动/加载类似于Facebook的/ Twitter等)。已在所有表上正确设置索引。一旦完成/正确,我想知道如何限制过去七天的购买结果,并按购买次数(num_buys)订购。

编辑:EXPLAIN的结果

enter image description here

1 个答案:

答案 0 :(得分:0)

我想你想要第一张照片(最低身份证),并且需要照片,其他一切都是可选的。

我猜你正在做子查询,因为你认为加入不相关的子查询(只连接一次连接表)会比相关的子查询或普通的JOIN更快。但是,您最终必须两次查找记录,第二次查找(对于实际连接)不会使用索引,因为派生(临时表)没有索引。

尝试正常的JOIN:

SELECT items.*,
    p.file AS item_pic,
    COALESCE(i_f.id, 0) AS favorite_id,
    COUNT(f.item_id) AS favorite_count,
    COUNT(b.item_id) AS num_buys,
    COUNT(c.item_id) AS comment_count
FROM items i
STRAIGHT_JOIN item_pics p
  ON p.item_id = i.id
LEFT JOIN item_pics p2
  ON p2.item_id = i.id
  AND p2.id < p1.id
LEFT JOIN item_favorites f
  ON f.item_id = i.id
LEFT JOIN purchases b
  ON b.item_id = i.id
LEFT JOIN comments c
  ON c.item_id = i.id
LEFT JOIN item_favorites AS i_f 
    ON i_f.item_id  = i.id
    AND i_f.userid = '14'
WHERE p2.id IS NULL
GROUP BY i.id
LIMIT 20

图片上的双重加入是反加入WHERE p2.id IS NULL,用于检索具有最低id的图片。