3

GROUP BY一意のキーを使用してクエリに句を適用すると、LIMIT制限が適用される前にすべてのグループが計算されますか?

テーブルに 100 のレコードがある場合 (それぞれに一意のキーがあります)、が適用される前に100( 用に) 一時テーブルにレコードが作成されますか?GROUP BYLIMIT

これが必要なケーススタディ:

例を挙げてみましょうStack Overflow

質問のリストを表示するために実行する各クエリには、この質問をしたユーザーと、そのユーザーが持っているバッジの数も表示されます。

したがって、ユーザー<-> 質問は 1 対 1 ですが、ユーザー <-> バッジは 1 つに複数あります。

1 つのクエリでこれを行う唯一の方法 (質問に対して 1 つとユーザーに対して別のクエリを組み合わせて結果を結合するのではありません) は、主キー (question_id) でクエリをグループ化し、user_badges テーブルに join+group_concat することです。

同じことが質問 TAGS にも当てはまります。

Code example:
Table Questions:
question_id  (int)(pk)|   question_body(varchar)


Table tag-question:
question-id (int) | tag_id (int)


SELECT:

SELECT quesuestions.question_id,
       questions.question_body,
       GROUP-CONCAT(tag_id,' ') AS 'tags-ids'
FROM
       questions
   JOIN
       tag_question
   ON
       questions.question_id=tag-question.question-id
GROUP BY
       questions.question-id
LIMIT 15
4

3 に答える 3

4

はい、クエリが実行される順序は次のとおりです。

  • から
  • どこ
  • グループ
  • 持っている
  • 選別
  • 選択する
  • リミット

LIMIT は最後に計算されるため、グループ化は問題ありません。

さて、言い換えられた質問を見ると、グループごとに 1 行だけではなく、多くの行があります。stackoverflow の場合、行ごとに 1 人のユーザーしかありませんが、多くのバッジがあります。

(uid, badge_id, etc.)
(1, 2, ...)
(1, 3, ...)
(1, 12, ...)

それらはすべて一緒にグループ化されます。

全テーブル スキャンを回避するために必要なのは、インデックスだけです。その上、たとえばSUMが必要な場合は、フルスキャンを避けることはできません.

編集:

次のようなものが必要になります (WHERE 句を見てください)。

SELECT
  quesuestions.question_id,
  questions.question_body,
  GROUP_CONCAT(tag_id,' ') AS 'tags_ids'
FROM
  questions q1
  JOIN tag_question tq
    ON q1.question_id = tq.question-id
WHERE
  q1.question_id IN (
    SELECT
      tq2.question_id
    FROM
      tag_question tq2
        ON q2.question_id = tq2.question_id
      JOIN tag t
        tq2.tag_id = t.tag_id
    WHERE
      t.name = 'the-misterious-tag'
  )
GROUP BY
  q1.question_id
LIMIT 15
于 2009-04-14T13:50:11.087 に答える
1

グループ化しているフィールドがインデックス化されている場合、完全なテーブル スキャンを実行するべきではありません。

于 2009-04-14T14:04:20.427 に答える
1

LIMITの後に適用されGROUP BYます。

一時テーブルが作成されるかどうかは、インデックスの作成方法によって異なります。

グループ化フィールドにインデックスがあり、集計結果で順序付けしない場合、INDEX SCAN FOR GROUP BYが適用され、各集計がその場でカウントされます。

つまり、 のために集計を選択しLIMITないと、計算されません。

しかし、集計で並べ替える場合は、もちろん、並べ替える前にすべてを計算する必要があります。

そのため、それらが最初に計算され、次にfilesortが適用されます。

アップデート:

クエリについてEXPLAIN EXTENDEDは、その内容を参照してください。

ほとんどの場合、テーブルの であり、スキャンで使用される可能性が最も高いですquestion_idPRIMARY KEY

つまり、nofilesortが適用され、結合自体が15'th行の後に発生することはありません。

確認するには、クエリを次のように書き換えます。

SELECT question_id,
       question_body,
       (
       SELECT  GROUP_CONCAT(tag_id, ' ')
       FROM    tag_question t
       WHERE   t.question_id = q.question_id
       )
FROM   questions q
ORDER BY
       question_id
LIMIT 15
  • まず、読みやすく、
  • 第二に、より効率的であり、
  • 第三に、タグ付けされていない質問も返します (現在のクエリにはありません)。
于 2009-04-14T14:33:19.500 に答える