GROUPBY与ORDERBY同时使用时,需注意执行顺序问题:ORDERBY字段必须在GROUPBY列表或聚合函数中,否则语法报错。此外,GROUPBY后ORDERBY无法取每组最新记录,需用窗口函数或关联子查询实现。ORDERBY字段无索引会导致性能下降。
GROUP BY 和 ORDER BY 这俩兄弟,千万别随便凑一起用——尤其是你心里想的是“每组取最新/最高的一条”时,翻车的概率极高。很多同学都踩过这个坑,以为先排序再分组就万事大吉,结果查出来的数据跟预期完全对不上。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
一言以蔽之:GROUP BY 和 ORDER BY 之间有一个非常隐蔽的执行顺序问题,一旦搞错,逻辑全乱。
先说一个常见的语法坑。MySQL 5.7 及以上版本,默认开启了 ONLY_FULL_GROUP_BY 模式。在这个模式下,只要 ORDER BY 后面的字段既没出现在 GROUP BY 子句中,也没被 MAX()、COUNT() 这些聚合函数包裹,数据库就会直接报错:Expression #1 of ORDER BY clause is not in GROUP BY clause。
举个例子,错误写法是这样:
SELECT examId, score FROM ko_monthly_exam_history GROUP BY examId ORDER BY score DESC —— 这里 score 既没分组也没聚合,通不过。怎么改?有两种思路:
SELECT examId, MAX(score) AS score FROM ko_monthly_exam_history GROUP BY examId ORDER BY score DESCscore 也加入分组列表:SELECT examId, score FROM ko_monthly_exam_history GROUP BY examId, score ORDER BY score DESC —— 不过这样语义就变了,不再是“每组一条”,而是变成了去重组合。好,就算语法通过了,逻辑上还有一个更隐蔽的陷阱。很多人以为 GROUP BY 之后再加个 ORDER BY,就能把每组里最大的那条记录挑出来。可惜,这是错觉。
真实情况是:GROUP BY 先执行,它只保留每组的第一行——这个第一行取决于物理顺序或引擎的默认行为,跟你想要的“最大/最新”毫无关系。然后 ORDER BY 再对这“一行”的字段排序,组内其他数据它根本看不到。
比如这句:SELECT id, examId, score FROM t GROUP BY examId ORDER BY score DESC,返回的 id 很可能对应的是该组里最低分那条记录,而不是最高分那条。
根本原因在于执行顺序:FROM → WHERE → GROUP BY → SELECT → ORDER BY。ORDER BY 执行时,组内全量数据早就被 GROUP BY 压缩掉了。
还有一个常见的错误做法:有人想用“子查询先 ORDER BY 再 GROUP BY”来绕过这个问题。但 MySQL 5.7+ 的优化器会直接丢弃子查询里的 ORDER BY,除非你加上 LIMIT 999999999 这种强制保留的写法——但这么做既不优雅也不推荐。
如果你真的需要按 examId 分组,并且从每组里取出 score 最高、time 最新的那条完整记录,那就必须跳出 GROUP BY 的限制。这里是两个靠谱的方案:
SELECT * FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY examId ORDER BY score DESC, time DESC) AS rn FROM ko_monthly_exam_history) t WHERE t.rn = 1SELECT t1.* FROM ko_monthly_exam_history t1 WHERE t1.id = (SELECT id FROM ko_monthly_exam_history t2 WHERE t2.examId = t1.examId ORDER BY score DESC, time DESC LIMIT 1)使用子查询时还有一个容易踩的坑:SELECT * FROM (SELECT * FROM t ORDER BY score DESC LIMIT 1000) s GROUP BY examId 这种写法,如果某个 examId 的最高分没进前 1000 名,它就会被漏掉。LIMIT 必须放到最外层才安全。
最后补充一个性能相关的点。即使语法合法、逻辑正确,如果 ORDER BY 字段没有索引,MySQL 就会走 Using filesort。结果顺序看着像随机,性能也惨不忍睹。
检查方法很简单:用 EXPLAIN 看 Extra 列,如果有 Using filesort,说明没走索引排序。
几个实用建议:
ORDER BY 字段尽量落在驱动表上——也就是 FROM 后面第一张表。examId 分组,再按 MAX(time) 排序,那么建一个 INDEX idx_exam_time (examId, time) 会非常高效。ORDER BY 2 这种位置引用——字段一增减,排序可能就全乱了。最容易被忽略的,其实是这一点:你以为 GROUP BY + ORDER BY 能取到每组最优记录,其实它只负责把组排个序。真正筛选组内数据,还得靠窗口函数、子查询,或者在业务层做二次处理。别让 ONLY_FULL_GROUP_BY 报错把你骗过去——报错只是表象,逻辑错才是根因。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述