Является ли команда GROUP BY по UNIQUE вычисляет все группы перед применением предложения LIMIT?

89
11

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


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


Изучение конкретного случая, почему мне это нужно:


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


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


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


Единственный способ сделать это в одном запросе (а не в вопросе, а другой в отношении пользователей и затем объединить результаты) состоит в том, чтобы сгруппировать запрос с помощью первичного ключа (question_id) и join + 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

спросил(а) 2021-01-25T14:49:26+03:00 4 месяца, 2 недели назад
1
Решение
98

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


    С
    WHERE
    GROUP
    HAVING
    SORT
    SELECT
    LIMIT

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


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


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

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


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


EDIT:


Вам понадобится что-то вроде этого (смотрите предложение 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

ответил(а) 2021-01-25T14:49:26+03:00 4 месяца, 2 недели назад
63

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

ответил(а) 2021-01-25T14:49:26+03:00 4 месяца, 2 недели назад
63

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

    Во-первых, это более читаемо,
    Во-вторых, он более эффективен и
    В-третьих, он вернет даже непомеченные вопросы (которые ваш текущий запрос не делает).

ответил(а) 2021-01-25T14:49:26+03:00 4 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема