3

如果我GROUP BY使用唯一键并将LIMIT子句应用于查询,是否会在应用限制之前计算所有组?

如果我在表中有一百条记录(每条记录都有一个唯一的键),在应用 a 之前我会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
4

3 回答 3

4

是的,查询执行的顺序是:

  • 在哪里
  • 团体
  • 拥有
  • 种类
  • 选择
  • 限制

LIMIT 是最后计算出来的,所以你的分组会很好。

现在,看看你改写的问题,那么你不是每组只有一行,而是很多:在stackoverflow的情况下,每行只有一个用户,但有很多徽章 - 即

(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-14T13:50:11.087 回答
1

如果您要分组的字段已编入索引,则不应执行全表扫描。

于 2009-04-14T14:04:20.427 回答
1

LIMIT确实在之后应用GROUP BY

是否创建临时表取决于索引的构建方式。

如果您在分组字段上有一个索引并且不按聚合结果排序,则INDEX SCAN FOR GROUP BY应用 an,并且每个聚合都会即时计数。

这意味着如果您由于 不选择聚合LIMIT,则永远不会计算它。

但是,如果您按聚合排序,那么当然,所有这些都需要在排序之前进行计算。

这就是为什么先计算它们然后再filesort应用它们的原因。

更新:

至于你的查询,看看EXPLAIN EXTENDED它说了什么。

最有可能question_id的是PRIMARY 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 回答