4

希望了解我的EXPLAIN结果在这里的含义,并尽我所能优化此查询和我的表。

查询:

SELECT i.pending,
       i.itemid, 
       i.message,
       i.cid, 
       i.dateadded, 
       i.entrypoint,  
       SUM(CASE WHEN v.direction = 1 THEN 1
                     WHEN v.direction = 2 THEN -1
                     ELSE 0 END) AS votes,
       c.name AS cname,
       c.tag AS ctag,
       i.userid,
       (SELECT COUNT(commentid) FROM `comments` WHERE comments.itemid = i.itemid) AS commentcount,
       CASE WHEN NOT EXISTS (SELECT voteid FROM `votes` WHERE votes.itemid = i.itemid AND votes.userid = @userid) THEN '0' ELSE '1' END AS hasVoted,
       CASE WHEN NOT EXISTS (SELECT voteid FROM `user_favorites` WHERE user_favorites.itemid = i.itemid AND user_favorites.userid = @userid) THEN '0' ELSE '1' END AS isFavorite
    FROM `contentitems` i
      LEFT JOIN votes v ON i.itemid = v.itemid
      LEFT JOIN `user_favorites` uv ON i.itemid = uv.itemid AND (uv.userid = @userid)
      INNER JOIN  `categories` c ON i.cid = c.cid
    GROUP BY i.itemid
    HAVING SUM(CASE WHEN v.direction = 1 THEN 1
                    WHEN v.direction = 2 THEN -1
                    ELSE 0 END) > -3 AND i.pending = 0
    ORDER BY i.dateadded DESC

(编辑格式)

解释结果:

+----+--------------------+----------------+--------+-------------------------+-------------------------+---------+------------------------+------+-------------------------------------------------------
| id |    select_type     |     table      |  type  |      possible_keys                  key                               | key_len | ref                     | rows |              Extra              |
+----+--------------------+----------------+--------+-------------------------+-------------------------+---------+------------------------+------+------------------------------------------------------+
|  1 | PRIMARY            | i              | ALL    | NULL                              | NULL                              | NULL    | NULL                    |  121 | Using temporary; Using filesort |
|  1 | PRIMARY            | v              | ref    | fk_contentitemsitemid_votesitemid | fk_contentitemsitemid_votesitemid | 4       | db33481_mydb.i.itemid   |    2 |                                 |
|  1 | PRIMARY            | uv             | ALL    | NULL                              | NULL                              | NULL    | NULL                    |    7 |                                 |
|  1 | PRIMARY            | c              | eq_ref | PRIMARY                           | PRIMARY                           | 4       | db33481_mydb.i.cid      |    1 |                                 |
|  4 | DEPENDENT SUBQUERY | user_favorites | ALL    | NULL                              | NULL                              | NULL    | NULL                    |    7 | Using where                     |
|  3 | DEPENDENT SUBQUERY | votes          | ref    | fk_contentitemsitemid_votesitemid | fk_contentitemsitemid_votesitemid | 4       | func                    |    2 | Using where                     |
|  2 | DEPENDENT SUBQUERY | comments       | ALL    | NULL                              | NULL                              | NULL    | NULL                    |   26 | Using where                     |
+----+--------------------+----------------+--------+-------------------------+-------------------------+---------+------------------------+------+------------------------------------------------------+
4

4 回答 4

1

首先,您有一个选择不存在的投票 ID,然后在 from 中进行左连接,最后在 have 中进行总和。这击中了您的投票表 3 次。如果每个投票可能与单个“ItemID”相关联,那么最好将其本身预先聚合为它自己的“Sum”完成一次。

此外,由于您的最终“HAVING”子句是投票的直接基础,因此对投票进行左连接成为一个死点,并最终以正常的 JOIN 结束。

话虽如此,我会预先查询 FIRST 的选票,即 FINISH 与预先符合条件的 HAVING 条件,然后加入内容项和其他连接......对 User_Favorites 的查询是一个计数,要么是 0(不是找到),或 1(找到)。应该不需要案例/何时

我的第一个查询别名“PQ”代表“PreQuery”

SELECT
      PQ.ItemID,
      PQ.VSum as Votes,
      PQ.HasVoted,
      i.pending,
      i.itemid, 
      i.message,
      i.cid, 
      i.dateadded, 
      i.entrypoint,  
      i.userid,
      c.name AS cname,
      c.tag AS ctag,
      ( SELECT COUNT(commentid) 
           FROM `comments` 
           WHERE comments.itemid = PQ.itemid) AS commentcount,
      ( SELECT COUNT(*) FROM user_favorites uf
              WHERE uf.itemid = PQ.itemid 
                AND uf.userid = @userid ) AS isFavorite
   from 
      ( SELECT
              v.itemid,
              SUM( case when v.Direction = 1 then 1
                        when v.Direction = 2 then -1
                        ELSE 0 end ) as VSum,
              MAX( if( votes.userid = @userid, 1, 0 ) AS HasVoted 
           from 
              votes v
           group by 
              v.itemid
           having
              VSum > -3 ) PQ

         JOIN ContentItems i
            ON PQ.ItemID = i.ItemID
            and i.Pending = 0

         JOIN Categories c
            ON i.cid = c.cid

   ORDER BY 
      i.dateadded DESC

其他人表示需要索引,同意。我会确保每个表在用户 ID 或项目 ID(或两者都在适当的情况下)都有各自的索引。

再加上其他几点...您最初开始查询查询所有 ContentItem,但左加入投票...但随后应用用户 ID 的元素。这绝对是针对特定用户的查询。话虽这么说,我将另外预先启动整个查询,其中仅选择用户 ID 已完成任何操作的 ItemID...然后继续查询。

于 2011-10-24T00:24:20.087 回答
0

我看到没有用于访问commentsvotes和的密钥user_favorites。除非表真的很小,否则您应该尝试在这些表上userid和其中添加索引。itemid

于 2011-10-13T13:27:08.663 回答
0

尝试查看此链接以了解解释计划。试着往下看那部分,它清楚地解释了你需要寻找的东西。

超过你的解释计划看起来像有更少的信息。请尝试使用oracle 的sql developer。它是开源的,并且确实为您提供了有关解释计划的详细信息。

于 2011-10-22T06:52:30.263 回答
0

我会添加以下索引:

ALTER TABLE comments ADD INDEX (commentid)
ALTER TABLE user_favorites ADD INDEX (itemid, voteid)

此外,如果 possible_keys 列显示为 NULL,则表示该表没有可用的键。即使它们不用于优化,如果它们存在于查询中的列中,它们也会显示在那里。最有可能的是,您在查询中未访问的列上的这些表上有一个主键。

于 2011-10-22T12:28:15.373 回答