我有一个表来计算不同用户对不同对象的一个特定操作的出现次数:
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让我失望......这种问题使得这个问题毫无意义。遗憾!
答案 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;