如何用单条MySQL查询高效获取多分类多用户的最新25条数据
多分组取最新数据的单查询优化方案
先搞定索引(最关键的一步)
你当前的单字段索引(datetime、category、name)无法高效支撑多条件过滤+排序的需求——MySQL一次只能使用一个索引,查询时要么扫描name索引后再过滤category和datetime,要么扫描datetime索引后再过滤其他字段,效率极低。
必须创建复合索引来匹配你的查询逻辑:
CREATE INDEX idx_name_category_datetime ON `table` (name, category, datetime DESC);
索引顺序不能乱:先按name和category分组,再按datetime降序排列,完美匹配「按分组取最新数据」的需求,数据库能直接定位到目标数据,无需额外排序操作。
两种单查询实现方式
1. UNION ALL 合并查询(兼容所有MySQL版本)
将四个独立查询用UNION ALL合并为单条查询,减少三次连接解析、优化的开销,同时能复用上面的复合索引:
SELECT * FROM `table` WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat1' ORDER BY datetime DESC LIMIT 25 UNION ALL SELECT * FROM `table` WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat1' ORDER BY datetime DESC LIMIT 25 UNION ALL SELECT * FROM `table` WHERE datetime <= 'xxx' AND name = 'john' AND category = 'cat2' ORDER BY datetime DESC LIMIT 25 UNION ALL SELECT * FROM `table` WHERE datetime <= 'xxx' AND name = 'doe' AND category = 'cat2' ORDER BY datetime DESC LIMIT 25;
注意:使用
UNION ALL而非UNION——UNION会自动去重,而你这四个分组的数据无重复,没必要额外消耗性能。
2. 窗口函数实现(MySQL 8.0+优先选用)
如果你的MySQL版本为8.0及以上,用ROW_NUMBER()窗口函数能实现更简洁、逻辑更清晰的查询:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY name, category ORDER BY datetime DESC) AS rn FROM `table` WHERE datetime <= 'xxx' AND (name, category) IN (('john', 'cat1'), ('doe', 'cat1'), ('john', 'cat2'), ('doe', 'cat2')) ) AS t WHERE rn <= 25;
内层查询先过滤出目标分组的数据,再按name+category分组,给每组记录按时间从新到旧编号;外层直接筛选每组编号≤25的记录,即可得到每组最新25条数据。
效果说明
不管选用哪种单查询方式,复合索引都是性能提升的前提——没有该索引,单查询的性能优化效果会很有限。有了索引后,两种方案都比原有的四个独立查询速度快很多:UNION ALL减少了连接开销,窗口函数逻辑更易维护,二者性能表现相近,可根据你的MySQL版本选择。
内容的提问来源于stack exchange,提问作者ipel
相关产品推荐
相关产品推荐

