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 回ヒットしています。各投票が 1 つの「ItemID」に関連付けられている可能性がある場合は、1 回行われる独自の「Sum」として事前に集計することをお勧めします。

さらに、最後の「HAVING」句は投票の直接の基礎であるため、投票で左結合を持つことはデッドポイントになり、最終的には通常の結合で終了します。

そうは言っても、適格な HAVING 条件を前もって FINISH する投票で FIRST を事前にクエリし、コンテンツ アイテムやその他の結合に参加します... User_Favorites に対するクエリはカウントであり、0 (ない) のいずれかになります。見つかった)、または 1 (見つかった)。case/when は必要ないはずです

最初のクエリ エイリアス「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

説明計画を理解するには、このリンクを参照してください。そのセクションを下ってみてください。何を探す必要があるかが明確に説明されています。

説明計画の詳細は、情報が少ないように見えます。Oracle のsql developerを使用してみてください。これはオープンソースであり、Explain Plan に関する適切な詳細を提供します。

于 2011-10-22T06:52:30.263 に答える
0

commentsvotes、およびにアクセスするためのキーはありませんuser_favorites。テーブルが非常に小さい場合を除き、それらのテーブルにインデックスuseridを追加してみてください。itemid

于 2011-10-13T13:27:08.663 に答える
0

次のインデックスを追加します。

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

さらに、 possible_keys 列が NULL の場合、そのテーブルに使用できるキーがないことを意味します。最適化に使用されていない場合でも、クエリの列に存在する場合はそこに表示されます。ほとんどの場合、これらのテーブルには、クエリでアクセスされていない列に主キーがあります。

于 2011-10-22T12:28:15.373 に答える