ROWS和RANGE本质不同:ROWS按物理行位置计数,严格取“当前行及前N行”,不关心值是否重复或时间是否连续;RANGE按排序列的值范围匹配,同值所有行均被纳入,易致窗口扩大、结果失真。

ROWS 和 RANGE 不是可互换的选项,用错会导致统计结果完全偏离预期——尤其在 ORDER BY 列存在重复值时。
ROWS BETWEEN 是物理行数控制,必须配 ORDER BY 才有意义
ROWS 按实际行位置计数,比如 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 就是“当前行 + 它前面紧挨着的两行”,不看值是否相同、时间是否连续。但若没写 ORDER BY,MySQL 会按任意顺序取行,结果不可控。
- 必须显式声明
ORDER BY,否则ROWS的“前N行”无定义 - 分区(
PARTITION BY)内行序由ORDER BY决定,不是插入顺序或主键顺序 - 当
ORDER BY列有重复值(如多个 90 分),ROWS仍严格按物理位置算,可能把同分但不同学生的记录强行拆开
RANGE 默认按值范围匹配,容易在数值/日期场景误统计
RANGE 关注的是排序列的**值差异**,不是行位置。默认帧 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 实际含义是:“所有排序值 ≤ 当前行排序值的记录”。这在成绩、金额、时间等连续型字段上极易扩大窗口。
- 例如
ORDER BY score,当前行为 score=90,那所有 score≤90 的行(哪怕有几十个)都会被纳入计算 - 日期字段用
RANGE BETWEEN INTERVAL 7 DAY PRECEDING AND CURRENT ROW是合法的,但ROWS不支持INTERVAL语法 - 若排序列是主键 ID(自增),
RANGE和ROWS行为一致;但一旦 ID 不连续或有跳号,RANGE就会漏掉某些行
什么时候必须用 ROWS 而不是 RANGE?
需要严格限定参与计算的行数时,比如移动平均、滚动求和、最近 N 条记录对比——这些都依赖“数量”而非“值范围”。
- 计算近3天销量均值?不行,日期是连续值,该用
RANGE BETWEEN INTERVAL 2 DAY PRECEDING AND CURRENT ROW - 计算最近3笔订单的平均金额?必须用
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW,因为订单未必按天均匀发生 - 做环比(当前行 vs 上一行)?
LAG(amount, 1)底层依赖ROWS逻辑,不能靠RANGE模拟
GROUPS 是 MySQL 8.0.2 新增的第三种帧模式
GROUPS 面向 ORDER BY 后的**逻辑组**,把排序值相同的行视为一组。它填补了 ROWS(太细)和 RANGE(太粗)之间的空白。
- 例如成绩表按
score DESC排序,95 分有 2 人、90 分有 3 人、85 分有 1 人,则GROUPS BETWEEN 1 PRECEDING AND CURRENT GROUP表示“上一组 + 当前组” - 写法必须带
GROUPS关键字,不能省略;且仅在有ORDER BY时生效 - 注意:MySQL 8.0.1 及更早版本不支持
GROUPS,执行会报错Unknown window frame type GROUPS
最常被忽略的一点:即使你写了 ROWS 或 RANGE,只要没写 ORDER BY,MySQL 仍会回退到默认帧 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING——也就是整个分区,和你想要的滑动效果完全相反。


















