如果我在唯一键上使用GROUP BY,并将一个LIMIT子句应用于查询,那么在应用该限制之前,是否会计算所有组?
如果表中有100条记录(每个记录都有唯一的键),那么在应用100之前,是否会在临时表中创建LIMIT记录(用于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发布于 2009-04-14 14:33:19
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发布于 2009-04-14 13:50:11
是的,查询执行的顺序是:
极限是计算的最后一件事,所以你的分组会很好。
现在,看看您重新措辞的问题,那么您不是每组只有一行,而是很多:在堆栈溢出的情况下,每一行只有一个用户,但是有许多标记。
(uid, badge_id, etc.)
(1, 2, ...)
(1, 3, ...)
(1, 12, ...)所有这些都将被组合在一起。
为了避免全表扫描,您所需要的只是索引。此外,如果您需要求和,例如,您无法避免全面扫描。
编辑:
您需要这样的东西(看看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-14 14:04:20
如果要分组的字段是索引的,则不应该进行完整的表扫描。
https://stackoverflow.com/questions/747639
复制相似问题