MySQL技巧:利用窗口函数高效去重,告别嵌套子查询
日常开发中,数据去重是一个高频需求。很多同学第一时间想到 GROUP BY 或 DISTINCT,但遇到“保留每组中最新一条记录”这类场景时,往往会写出多层嵌套子查询,性能差且可读性低。
其实,MySQL 8.0 引入的窗口函数可以优雅解决这个问题。
典型场景:保留每个用户的最新订单
假设有一张订单表 user_orders,包含 user_id、order_amount、create_time。现在需要为每个用户保留最新的一条订单记录。
低效写法(传统子查询):
SELECT uo.*
FROM user_orders uo
INNER JOIN (
SELECT user_id, MAX(create_time) AS max_time
FROM user_orders
GROUP BY user_id
) t ON uo.user_id = t.user_id AND uo.create_time = t.max_time;
高效写法(窗口函数):
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY create_time DESC) AS rn
FROM user_orders
)
SELECT * FROM ranked WHERE rn = 1;
优点解析
- 简洁清晰:一条
ROW_NUMBER()直接表达“分组排序取第一”的意图。 - 性能更好:窗口函数只需扫描一次表,而传统自连接或子查询往往需要多次扫描。
- 灵活扩展:将
rn = 1改为rn <= 3即可获取每个用户最新的3条订单,无需改写复杂逻辑。
小提示
如果 MySQL 版本低于 8.0,可以使用用户变量模拟窗口函数,但升级到 8.0 以上才是长久之计。窗口函数还能轻松实现累计和、移动平均等高级分析,值得深入学习。
下次遇到“每组取Top N”的需求,试试窗口函数,让你的SQL更优雅。