2011-10-12 2 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가 있습니다. 그 다음에 왼쪽 참여가 시작되고 마지막으로 합계가 표시됩니다. 이것은 당신의 표를 3 번 ​​치고 있습니다. 각 투표가 단일 "품목 ID"와 연관 될 가능성이있는 경우, 그 자체로 미리 집계되는 것이 가장 좋을 것입니다.

또한 마지막 "HAVING"절이 Votes의 직접적인 기초이기 때문에 투표에 대한 왼쪽 가입은 부재 중이되어 궁극적으로 정상 JOIN으로 끝납니다.

내가 말했듯이, 자격있는 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"을 나타내는 케이스/필요가 없어야합니다, 동의했다. 각 테이블에 사용자 ID 또는 항목 ID (또는 해당되는 경우 모두)에 대한 각각의 색인이 있는지 확인합니다.

몇 가지 다른 점 ... 처음에는 모든 ContentItem을 쿼리하지만 왼쪽으로 투표에 참여했습니다 ...하지만 사용자 ID의 요소를 적용합니다. 이것은 특정 사용자에 대한 쿼리의 냄새를 명확하게합니다.즉, 나는 사용자 ID가 아무 것도하지 않은 ItemID 만 선택하여 전체 쿼리를 추가로 미리 시작할 것입니다. 그런 다음 쿼리를 계속 진행하십시오.

+0

', 1, 0) 근처에 구문 오류가 있습니다. HasVoted, 답변을 업데이트 할 수 있습니까? – barfoon

+0

@ barfoon, 답변이 업데이트되었습니다. 먼저 제거해야했습니다. ")"... – DRapp

0
내가 comments, votes에 액세스하는 데 사용되는 키와이없는 것을 볼

하고, user_favorites. 테이블이 정말로 작은 경우가 아니면 useriditemid에 인덱스를 추가해야합니다.

+0

내가 언급 한 세 테이블에 기본 키가 있습니다. 어떻게 쿼리를 사용하도록 말할 수 있습니까? 아니면 각 테이블에 기본 키와 사용자 ID/itemid를 포함하는 복합 키를 만들어야합니까? – barfoon

+0

복합 키를 만들어보십시오. –

0

이 계획을 이해하기 위해서는이 내용을 보시기 바랍니다. link 그 부분을 내려가보십시오, 그것은 당신이 무엇을 찾아야하는지 명확하게 설명합니다.

설명 계획보다 많은 정보가 적은 것 같습니다. oracle의 sql developer을 사용해보십시오. 그것은 오픈 소스이며, 당신에게 설명 플랜에 대한 세부 사항을 제공합니다.

0

나는 다음과 같은 인덱스를 추가 할 다음이 possible_keys 컬럼이 NULL 말한다면

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

또한, 그것은 해당 테이블에 대한 사용 가능한 키가 없음을 의미합니다. 최적화에 사용되지 않더라도 쿼리의 열에 해당 값이 있으면 표시됩니다. 대부분 쿼리의 액세스 권한이없는 열의 테이블에 기본 키가 있습니다.

관련 문제