MySQL:查询前n个聚合

时间:2009-05-26 20:17:32

标签: mysql limit aggregation

我有一个表来计算不同用户对不同对象的一个​​特定操作的出现次数:

CREATE TABLE `Actions` (
    `object_id` int(10) unsigned NOT NULL,
    `user_id` int(10) unsigned NOT NULL,
    `actionTime` datetime
);

每次用户执行此操作时,都会插入一行。我可以计算对每个对象执行了多少操作,并按“活动”对对象进行排序:

SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count;

如何将结果限制在前n个对象? LIMIT子句在聚合之前应用,因此会导致错误的结果。该表可能很大(数百万行),我可能需要每分钟数十次,所以我希望尽可能高效。

编辑:实际上,机器是正确的,我在应用LIMIT的时候错了。我的查询返回了正确的结果,但是向我展示的GUI让我失望......这种问题使得这个问题毫无意义。遗憾!

4 个答案:

答案 0 :(得分:2)

实际上......在最终的HAVING子句之后,LIMIT最后应用。所以它不应该给你不正确的结果。但是,由于LIMIT最后应用,它不会提供任何更快的查询执行,因为在切断结果之前,必须按行动计数的顺序创建临时表并对其进行排序。另外,请记住按降序排序:

SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count DESC
LIMIT 10;

您可以尝试向object_id添加索引以进行优化。这样,只需要扫描索引而不是 Actions 表。

答案 1 :(得分:1)

怎么样:

SELECT * FROM
(
SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count
)
LIMIT 15

此外,如果你有一些必须包含的最小动作数量(例如前n个肯定超过1000),你可以通过增加一个HAVING子句来提高效率:

SELECT * FROM
(
SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
HAVING action_count > 1000
ORDER BY action_count
)
LIMIT 15

答案 2 :(得分:1)

我知道这个帖子已经有2年了,但是stackflow仍然发现它有用,所以这里的价格为0.02美元。 ORDER BY子句在计算上非常昂贵,因此在大型表中应避免使用它们。我使用的一个技巧(部分来自Joe Celko的SQL for Smarties)类似于:

SELECT COUNT(*) AS counter, t0.object_id FROM (SELECT COUNT(*), actions.object_id FROM actions GROUP BY id) AS t0, (SELECT COUNT(*), actions.object_id FROM actions GROUP BY id) AS t1 WHERE t0.object_id < t1.object_id  GROUP BY object_id HAVING counter < 15

将为您提供前15个已编辑的对象而不进行排序。请注意,从v5开始,mysql将仅缓存完全重复(空白包含)查询的结果集,因此嵌套查询不会被缓存。使用视图可以解决该问题。

是的,这是三个查询而不是两个,唯一的好处是不必对分组查询进行排序,但如果你有很多组,那么它会更快。

旁注:对于没有排序的中值函数,查询非常方便

答案 3 :(得分:0)

SELECT * FROM (SELECT object_id, count(object_id) AS action_count 
        FROM `Actions` 
        GROUP BY object_id 
        ORDER BY action_count) LIMIT 10;