2011-10-12 51 views
4

想要了解我的EXPLAIN結果在這裏意味着什麼,並儘可能優化此查詢和我的表。mySQL - 如何解釋我的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      | 
+----+--------------------+----------------+--------+-------------------------+-------------------------+---------+------------------------+------+------------------------------------------------------+ 

回答

1

首先,您有一個選擇不存在的投票ID,然後在from中做一個左連接,最後在having中做一個總和。這是你的投票表3次。如果每次投票都可能與單個「ItemID」相關聯,那麼最好將其自身作爲自己的「總和」進行一次預彙總。

此外,由於您的最終「HAVING」條款是投票的直接基礎,因此左投票成爲死點並最終以正常JOIN結束。

所有的說法,我會預先查詢FIRST的FINISH與預選的合格HAVING條件,然後加入到內容項和其他連接...對User_Favorites的查詢是一個計數,並將是0(未找到)或1(找到)。不應該有任何需要

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 

其他人已經指示針對索引的需要的情況下,/當

我的第一個查詢別名「PQ」代表「PreQuery」,同意。我會確保每個表都有相應的用戶標識或項目標識(或者兩者都適用)的索引。

夫婦其他點...您最初開始查詢查詢所有ContentItems,但左連接到票...但隨後應用用戶ID的元素。這個DEFINITELY對特定用戶的查詢有異味。話雖如此,我還將額外預先啓動整個查詢,只選擇ItemIDs,用戶ID已完成任何操作...然後繼續查詢。

+0

'),1,0附近有語法錯誤)AS HasVoted,你能更新你的答案嗎? – barfoon

+0

@barfoon,答案更新後,不得不刪除第一個「)」... – DRapp

0

我看到,有沒有用於訪問commentsvotes鍵, user_favorites。除非這些表格非常小​​,否則您應該嘗試在這些表格中添加useriditemid的索引。

+0

我在你提到的三個表上有一個主鍵,我怎麼能告訴查詢使用它們?或者我應該在每個表上創建一個組合鍵,相應地包含主要和userid/itemid? – barfoon

+0

嘗試創建一個組合鍵。 –

0

試試看這link爲理解解釋計劃。嘗試按照這一部分,它清楚地解釋了你需要尋找的東西。

你的解釋計劃看起來像有更少的信息。請嘗試使用oracle的sql developer。它是開源的,並且提供了有關解釋計劃的詳細信息。

0

我想補充以下指標:

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

此外,如果possible_keys列說NULL,則意味着有該表沒有用的密鑰。即使它們不用於優化,如果它們存在於查詢中的列中,它們也會顯示在那裏。很可能,您在查詢中未訪問的列上的這些表上有一個主鍵。