如何为每个foreign_key_1和foreign_key_2唯一对查询最新5条数据?
问题描述
我有一张超过100万行的大表,结构如下:
| ID | foreign_key_1 | foreign_key_2 | clicks | installs | created_at |
|---|---|---|---|---|---|
| 1 | 01 | 01 | 2 | 0 | 2022-11-10 |
| 2 | 01 | 02 | 54 | 12 | 2022-11-10 |
| 3 | 01 | 01 | 9 | 0 | 2022-11-11 |
| 4 | 01 | 02 | 85 | 20 | 2022-11-11 |
| 5 | 01 | 01 | 3 | 1 | 2022-11-12 |
| 6 | 01 | 02 | 8 | 0 | 2022-11-12 |
| 7 | 01 | 01 | 6 | 0 | 2022-11-13 |
| 8 | 01 | 02 | 221 | 60 | 2022-11-13 |
| 9 | 01 | 01 | 61 | 10 | 2022-11-14 |
| 10 | 01 | 02 | 75 | 17 | 2022-11-14 |
| 11 | 01 | 01 | 58 | 8 | 2022-11-15 |
| 12 | 01 | 02 | 9 | 0 | 2022-11-15 |
| 13 | 01 | 01 | 10 | 1 | 2022-11-16 |
| 14 | 01 | 02 | 25 | 0 | 2022-11-16 |
需要基于created_at日期,获取每个foreign_key_1和foreign_key_2唯一对的最新5条数据,请问如何实现?
解决方案
一、MySQL 8.0+ 推荐方案:窗口函数(高效简洁)
MySQL 8.0及以上版本支持ROW_NUMBER()窗口函数,这是处理分组取Top N场景的最优方案,对百万级大表性能友好。
SELECT ID, foreign_key_1, foreign_key_2, clicks, installs, created_at FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY foreign_key_1, foreign_key_2 ORDER BY created_at DESC ) AS row_num FROM your_table_name ) AS ranked_data WHERE row_num <= 5;
核心逻辑:
PARTITION BY foreign_key_1, foreign_key_2:按两个外键的组合分组ORDER BY created_at DESC:每组内按创建时间倒序排列,最新数据排在首位row_num <=5:筛选出每组的前5条最新数据
二、MySQL 5.x 兼容方案:关联子查询
如果使用MySQL 5.x版本,可通过关联子查询实现,但必须创建复合索引,否则百万级数据查询会异常缓慢。
SELECT t1.ID, t1.foreign_key_1, t1.foreign_key_2, t1.clicks, t1.installs, t1.created_at FROM your_table_name t1 WHERE ( SELECT COUNT(*) FROM your_table_name t2 WHERE t2.foreign_key_1 = t1.foreign_key_1 AND t2.foreign_key_2 = t1.foreign_key_2 AND t2.created_at >= t1.created_at ) <= 5 ORDER BY t1.foreign_key_1, t1.foreign_key_2, t1.created_at DESC;
核心逻辑:
- 子查询统计当前行对应的
foreign_key_1+foreign_key_2组内,创建时间晚于等于当前行的记录数 - 当计数≤5时,说明当前行属于该组的最新5条数据
三、百万级大表性能优化关键
无论采用哪种方案,都必须创建以下复合索引来减少数据扫描量,提升查询速度:
CREATE INDEX idx_fk1_fk2_created ON your_table_name (foreign_key_1, foreign_key_2, created_at DESC);
内容的提问来源于stack exchange,提问作者Erikas
相关产品推荐
相关产品推荐

