【问题标题】:MySQL: Return grouped fields where the group is not empty, efficientlyMySQL:有效地返回组不为空的分组字段
【发布时间】:2010-05-26 13:44:13
【问题描述】:

在一个语句中,我试图通过加入另一个表来对一个表的行进行分组。我只想获取分组结果不为空的分组行。

例如。项目和类别

SELECT Category.id
FROM Item, Category
WHERE Category.id = Item.categoryId
GROUP BY Category.id
HAVING COUNT(Item.id) > 0

上面的查询给出了我想要的结果,但这很慢,因为它必须计算按 Category.id 分组的所有行。

有什么更有效的方法?

我试图按限制进行分组,以便每组只检索一行。但是我的尝试失败了。知道我该怎么做吗?

谢谢

【问题讨论】:

  • 我是否理解您要返回所有至少包含一项的类别?
  • 是的,但效率很高。这就是问题所在。

标签: mysql performance limit group-by


【解决方案1】:

试试这个:

SELECT  item.categoryid
FROM    Item
JOIN    Category
ON      Category.id = Item.categoryId
GROUP BY
        item.categoryid
HAVING  COUNT(*) > 0

这类似于您的原始查询,但不会执行您想要的操作。

如果要选择非空类别,请执行以下操作:

SELECT  category.id
FROM    category
WHERE   id IN
        (
        SELECT  category_id
        FROM    item
        )

为了快速工作,请在 item (category_id) 上创建一个索引。

【讨论】:

  • 我很清楚选择非空类别的各种方法。但我需要一些有效的东西。潜在的 Item 可能有数千行。
  • 您可以添加 DISTINCT 关键字以避免在 item 表中出现所有这些 category_id 重复项。
  • @Ryan:是什么让您认为这样做效率低下?
  • 好吧,你还在选择每一行项目,难道没有办法只为每个类别选择一行吗? @SorcyCat 添加 DISTINCT 会加快查询速度吗?谢谢
  • @Ryan:如果您在item (category_id) 上创建索引,引擎将使用该索引仅选择一个项目并在第一个匹配项时返回。 DISTINCT 在这里是多余的。
【解决方案2】:

如果您不需要 Category 表,如何消除它?

SELECT Item.categoryId 
FROM Item
GROUP BY Item.categoryId

我不确定您是否需要 HAVING 子句,因为如果类别中没有项目,则不会创建组。

【讨论】:

  • 这将返回没有分类记录的项目。
  • 您的原始查询并没有表明需要整个类别记录,只是在 Item 表中已经提供了 id。如果您愿意,请查看 Quassnoi 的答案。
  • 哦,它是必需的,这只是一个例子来展示我正在尝试做的事情。
  • 好的,谢谢大家,你们的解决方案都有效。 (夸斯诺伊和唐尼)
【解决方案3】:

我认为这在功能上是等效的(返回至少包含一个项目的每个类别),并且应该更快。

SELECT 
  c.id
FROM 
  Category c
WHERE
  EXISTS (
    select 1 from Item i where i.categoryid = c.categoryID
  )

【讨论】:

  • 这看起来非常接近我想要的。我打算使用 EXISTS,但我不记得名字了,谢谢。如果您在该内部查询的末尾做了“LIMIT 1”,那是否有助于加快速度?因为您仍在选择所有项目。
  • 这不会选择所有项目。 Exists 找到匹配后立即返回,它不会找到所有匹配的行。
  • 你确定吗?我以前认为 LIMIT 是一样的。但后来我读到 LIMIT 只过滤最终结果。您有多确定 EXISTS 会以一个结果停止?不管怎样,我会在大约一个小时内测试它。
  • 我很肯定。这就是为什么exists 可以如此强大的优化。 (请注意,您仍然需要好的索引才能获得真正好的性能)
【解决方案4】:

我认为,这只是我的观点,正确的方法是计算所有的东西。也许问题出在其他地方。

这是我用来计数的方法,它工作得非常快,即使有大量数据。

SELECT categoryid, COUNT(*) FROM Item GROUP By categoryid

它将按类别为您提供所有项目的哈希值。但它不会包含空类别。

然后,要检索类别信息,请执行以下操作:

SELECT category.* FROM category
INNER JOIN (SELECT categoryid, COUNT(*) AS n FROM Item GROUP By categoryid) AS item
ON category.id = item.categoryid

【讨论】:

  • 顺便说一下,此查询将为您提供每个类别的确切项目数。如果你不需要这个,你可以跳过它删除“COUNT(*) AS n”部分。
猜你喜欢
  • 2018-12-02
  • 2017-08-18
  • 2015-12-25
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多