2009-04-14 3 views
3

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

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

социологическое исследование, почему мне это нужно:

Возьмите Stack Overflow, например.

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

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

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

То же самое касается вопросов ТЕГИ.

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 

ответ

1

LIMIT действительно применяется после GROUP BY.

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

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

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

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

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

Update:

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

:-D прочитал мой последний комментарий Seb. (Что касается непомеченных вопросов, в моей конкретной системе у меня нет такого случая, всегда есть тег по умолчанию, но это не часть этого вопроса) Спасибо! –

4

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

  • ОТ
  • ГДЕ
  • GROUP
  • HAVING
  • СНП
  • ВЫБОР
  • LIMIT

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

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

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

все они будут сгруппированы вместе.

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

EDIT:

Вам нужно что-то вроде этого (смотрите на ИНЕКЕ):

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 
+0

Я отредактировал свой вопрос, чтобы добавить пояснения и примеры. –

+0

Рассматривая свой вопрос, вы не имеете только одну строку для каждой группы, но многие: в случае stackoverflow у вас будет только один пользователь в строке, но многие значки - например, такие строки, как (uid, badge_id и т. Д.). .): (1, 2, ...), (1, 3, ...), (1, 12, ...) и т. Д. – Seb

+0

да, но только один question_id, который является группой по индексу. и для каждой группы I GROUP_CONCAT теги/значки. Если у меня есть LIMIT из 15 и у меня есть 100 вопросов, я бы хотел, чтобы запрос остановился после того, как он сгруппировал 15 вопросов и не выполнил полное сканирование таблицы. –

1

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

 Смежные вопросы

  • Нет связанных вопросов^_^