LAG和LEAD是逐行计算的窗口函数,每行返回一个标量值(当前行上下第N行对应字段值),不改变结果集行数;必须配合ORDER BY使用,推荐显式指定default_value以防NULL引发计算错误。
LAG 和 LEAD 不是“获取前N行数据”,而是取相邻行的值
很多人看到
就以为它能像
那样返回多行结果——不是的。
和
是**逐行计算型窗口函数**,每调用一次只返回一个标量值(当前行的上/下第 N 行对应字段的值),不会改变结果集行数。想“取前N行记录”该用
;而这里的目标其实是:**在每一行上,快速拿到它前后偏移位置上的某个字段值**。
正确写法:必须带 ORDER BY,推荐显式指定 default_value
这两个函数语法看似简单,但漏掉关键子句就会出问题:
是强制要求的——没有排序就没有“前后”概念,MySQL 会直接报错
不设
时,首行调用
返回
,末行调用
也返回
;如果业务逻辑不允许空值(比如做减法或除法),得补上第三参数,例如
偏移量
必须是非负整数,MySQL 8.0.22+ 要求必须明确写出(不能省略),且范围是 1 到 2^63−1
按业务维度分组计算:用 PARTITION BY 隔离逻辑边界
比如分析每个产品的日销售额环比,就不能让 A 产品最后一天和 B 产品第一天连起来算——必须按产品切分窗口:
注意点:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
后的字段必须是查询中出现的列(或其表达式),否则报错
若同时对多个字段分组(如
),分区粒度变细,各组合内独立排序计算
不要在
中混用无序字段(如未索引的时间戳字段),否则排序开销剧增
性能陷阱:ORDER BY 字段没索引,查询可能慢十倍
窗口函数执行前,MySQL 必须先完成全量排序。如果
字段没索引,尤其是大表,会触发
,IO 拉满:
用
检查执行计划,看到
就要警惕
给常用排序字段建索引,例如
或复合索引
避免在子查询里嵌套窗口函数再加
过滤——旧版本 MySQL 会先算完全部窗口再过滤,浪费资源
确认 MySQL 版本 ≥ 8.0.2,低于这个版本直接不支持,报错
最常被忽略的其实是
的存在本身,以及默认值缺失导致后续计算崩掉——尤其当差值用于报表展示或告警阈值判断时,
可能悄无声息地让整个指标失效。
LAG()LIMITLAG()LEAD()ORDER BY ... LIMIT NORDER BYERROR 3589 (HY000): Window '' requires an ORDER BY clause default_valueLAG(col, 1)NULLLEAD(col, 1)NULLLAG(amount, 1, 0)offsetSELECT
product_id,
sale_date,
amount,
LAG(amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) AS prev_day_amount,
amount - LAG(amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) AS daily_diff
FROM sales;PARTITION BYUnknown columnPARTITION BY category_id, regionPARTITION BYORDER BYUsing filesortEXPLAINExtra: Using filesortCREATE INDEX idx_sale_date ON sales(sale_date)CREATE INDEX idx_prod_date ON sales(product_id, sale_date)WHEREERROR 1064ORDER BYNULL