先按目标字段分组再统计每组行数,用count()而非count(列名)避免忽略null;取top 10需order by count() desc后limit 10;并列时可用dense_rank()确保同数量用户全部入选。

用 GROUP BY + COUNT() 统计分组数量
核心是先按目标字段分组,再算每组有多少行。比如查每个用户发了多少条订单,就得 GROUP BY user_id,然后用 COUNT(*) 或 COUNT(1)(二者在绝大多数场景下等价)。注意别误用 COUNT(column_name)——它会自动跳过 NULL 值,而你通常要的是“该组总行数”,不是“该组非空值个数”。
用 ORDER BY + LIMIT 取前10名
统计完必须排序才能取 Top 10。关键点:排序字段得是聚合结果,也就是 COUNT(*),不能写成 ORDER BY user_id 这类原始字段。常见错误是漏掉 ORDER BY 或写错方向——默认升序,得加 DESC 才是“数量最多”的排前面。
典型写法:
SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id ORDER BY cnt DESC LIMIT 10;
遇到并列时怎么处理?
LIMIT 10 是硬截断,如果第10名和第11名数量相同,后者会被直接砍掉,可能漏掉业务上认为“应该并列入围”的数据。MySQL 8.0+、PostgreSQL、SQL Server 支持窗口函数,可用 DENSE_RANK() 更合理地处理并列:
SELECT user_id, cnt
FROM (
SELECT user_id, COUNT(*) AS cnt,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS rk
FROM orders
GROUP BY user_id
) t
WHERE rk
<p>这样即使有 5 个用户都发了 99 条订单且刚好卡在第10名位置,它们全会被包含。</p>
<h3>性能和兼容性提醒</h3>
<p>大表上跑这类查询容易慢,尤其没索引时:<code>GROUP BY</code> 字段最好有索引;<code>ORDER BY COUNT(*)</code> 无法走索引,数据库必须先完成全部分组再排序,内存压力大。</p>
- MySQL 中临时表可能落到磁盘,观察
Created_tmp_disk_tables状态值 - SQLite 不支持窗口函数,
DENSE_RANK()写法直接报错 - 旧版 MySQL(GROUP BY 严格,若
SELECT列不在GROUP BY中且没聚合,会报错
真正卡住的往往不是语法,而是数据量上来后分组排序的资源消耗——先确认数据规模,再决定要不要加索引或改用近似算法。











