簡體   English   中英

mySQL - 如何解釋我的EXPLAIN結果並優化此查詢?

[英]mySQL - How can I interpret my EXPLAIN results and optimize this query?

想要了解我的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                     |
+----+--------------------+----------------+--------+-------------------------+-------------------------+---------+------------------------+------+------------------------------------------------------+

首先,你有一個選擇不存在的投票ID,然后在from中進行左連接,最后在有一個和。 這是你的投票表3次。 如果每個投票可能與單個“ItemID”相關聯,那么最好將其自身預先匯總為其自己的“Sum”完成ONCE。

此外,由於你的最終“HAVING”條款是投票的直接基礎,因此在投票上進行左連接將成為一個死點並最終以正常的JOIN結束。

所有這一切,我會預先查詢FIRST與預先確定合格的HAVING條件的FINISH,然后加入內容項和其他聯接...對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的相應索引(或兩者都適當)。

結合其他點...你最初開始查詢查詢所有ContentItems,但是左邊加入投票...但是然后應用用戶ID的元素。 這絕對是特定用戶查詢的氣味。 話雖這么說,我會額外預先啟動整個查詢,只選擇一個ItemID,用戶ID已經做了什么...然后繼續查詢。

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

嘗試查看此鏈接以了解解釋計划。 嘗試下去那一節,它清楚地解釋了你需要尋找什么。

更多關於你的解釋計划看起來更少的信息。 請嘗試從oracle使用sql developer 它是開源的,並且確實為您提供有關解釋計划的詳細信息。

我會添加以下索引:

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

此外,如果possible_keys列顯示NULL,則表示該表沒有可用的鍵。 即使它們不用於優化,如果它們存在於查詢中的列中,它們也會顯示在那里。 最有可能的是,您在查詢中未訪問的列上的那些表上有一個主鍵。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM