Ключ GROUP BY on UNIQUE вычисляет все группы перед применением предложения LIMIT? - PullRequest
3 голосов
/ 14 апреля 2009

Если I GROUP BY для уникального ключа и применить к запросу предложение LIMIT, будут ли рассчитаны все группы до применения ограничения?

Если у меня есть сто записей в таблице (каждая имеет уникальный ключ), Будет ли у меня 100 записей во временной таблице, созданной (для GROUP BY) до применения LIMIT?

Пример использования, почему мне это нужно:

Например, Stack Overflow.

Каждый запрос, который вы запускаете, чтобы показать список вопросов, также показывает пользователя, который задал этот вопрос, и количество значков, которые у него есть.

Итак, если вопрос пользователя <-> один к одному, у пользователя <-> значков один - много.

Единственный способ сделать это в одном запросе (а не в вопросе, а в другом для пользователей, а затем объединить результаты) - это сгруппировать запрос по первичному ключу (question_id) и присоединить + group_concat к таблице user_badges.

То же самое касается вопросов 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

Ответы [ 3 ]

4 голосов
/ 14 апреля 2009

Да, порядок выполнения запроса:

  • FROM
  • ГДЕ
  • GROUP
  • HAVING
  • СНП
  • SELECT
  • LIMIT

LIMIT - это последнее, что рассчитывается, поэтому ваша группировка будет в порядке.

Теперь, глядя на ваш перефразированный вопрос, тогда у вас будет не одна строка на группу, а много: в случае stackoverflow у вас будет только один пользователь на строку, но много значков - т.е.

(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
1 голос
/ 14 апреля 2009

LIMIT применяется после GROUP BY.

Будет ли создаваться временная таблица, зависит от того, как построены ваши индексы.

Если у вас есть индекс в поле группировки и вы не упорядочиваете по совокупным результатам, тогда применяется INDEX SCAN FOR GROUP BY, и каждый агрегат подсчитывается на лету.

Это означает, что если вы не выберете агрегат из-за LIMIT, он никогда не будет рассчитан.

Но если вы упорядочиваете по совокупности, то, конечно, все они должны быть рассчитаны, прежде чем их можно будет отсортировать.

Вот почему они сначала рассчитываются, а затем применяется filesort.

Обновление:

Что касается вашего запроса, посмотрите, что EXPLAIN EXTENDED говорит об этом.

Скорее всего, question_id - это PRIMARY KEY для вашей таблицы, и, скорее всего, он будет использоваться при сканировании.

Это означает, что filesort не будет применяться, и само соединение никогда не произойдет после строки 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
  • Во-первых, это более читабельно,
  • Во-вторых, это более эффективно, а
  • В-третьих, он будет возвращать даже непомеченные вопросы (чего нет у вашего текущего запроса).
1 голос
/ 14 апреля 2009

Если поле, по которому вы группируете, проиндексировано, полное сканирование таблицы не должно выполняться.

...