代码之家  ›  专栏  ›  技术社区  ›  Itay Moav -Malimovka

Group By on Unique键在应用限制子句之前是否计算所有组?

  •  3
  • Itay Moav -Malimovka  · 技术社区  · 15 年前

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

    如果我在表中有一百条记录(每个都有一个唯一的键),我会有吗 100 在临时表中创建的记录(用于 小组通过 ) 极限 应用吗?

    一个案例研究为什么我需要这个:

    采取 Stack Overflow 例如。

    您运行的每个查询都会显示一个问题列表,也会显示提出此问题的用户以及他拥有的徽章数量。

    因此,虽然用户问题是一对一的,但用户徽章是一对多的。

    在一个查询(而不是一个关于问题,另一个关于用户,然后合并结果)中执行此操作的唯一方法是按主键(question_id)对查询进行分组,并将+group_concat连接到用户徽章表。

    问题标签也是如此。

    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 回复  |  直到 15 年前
        1
  •  1
  •   Quassnoi    15 年前

    LIMIT 之后是否应用 GROUP BY .

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

    如果在分组字段上有索引,并且没有按聚合结果排序,那么 INDEX SCAN FOR GROUP BY 应用,并对每个聚合进行即时计数。

    这意味着如果由于 极限 它永远不会被计算出来。

    但是,如果您按照一个集合排序,那么,当然,在排序之前,需要计算所有这些集合。

    这就是为什么首先计算它们,然后 filesort 应用。

    更新:

    关于您的查询,请参阅 EXPLAIN EXTENDED 对它说。

    最有可能的是, question_id 是一个 PRIMARY KEY 对于您的桌子,最可能的是,它将用于扫描。

    这意味着不 文件服务器 将被应用,并且在 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
    
    • 首先,它更具可读性,
    • 第二,效率更高,而且
    • 第三,它将返回甚至没有标记的问题(您当前的查询没有)。
        2
  •  4
  •   Seb    15 年前

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

    • 哪里
    • 排序
    • 选择
    • 极限

    限制是最后计算出来的,所以您的分组就可以了。

    现在,看看你的重新措辞的问题,那么你不是每组只有一行,而是很多:在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
    
        3
  •  1
  •   GoatRider    15 年前

    如果您正在分组的字段被编入索引,那么它不应该进行全表扫描。