MySQL窗口函数使用自定义变量时sum结果不一致的原因
为什么使用自定义变量时窗口函数sum结果与直接sum列不一致?
问题场景
现有foo表结构及数据如下:
select * from foo; +---+---+ | a | b | +---+---+ | 1 | 2 | | 4 | 5 | | 6 | 8 | +---+---+
执行以下SQL时,b_accum是b列按a排序的累加值,结果符合预期:
select a, b, sum(b) over (order by a) as b_accum from foo order by a ASC;
返回结果:
+---+---+---------+ | a | b | b_accum | +---+---+---------+ | 1 | 2 | 2 | | 4 | 5 | 7 | | 6 | 8 | 15 | +---+---+---------+
但当引入自定义变量@b2后,sum(@b2)得到的b2_accum与b_accum结果完全不符:
select a, b, @b2 := b as b2, sum(b) over (order by a) as b_accum, sum(@b2) over (order by a) as b2_accum from foo order by a ASC;
返回结果:
+---+---+----+---------+----------+ | a | b | b2 | b_accum | b2_accum | +---+---+----+---------+----------+ | 1 | 2 | 2 | 2 | 8 | | 4 | 5 | 5 | 7 | 10 | | 6 | 8 | 8 | 15 | 15 | +---+---+----+---------+----------+
核心原因
这是由于MySQL中窗口函数的执行逻辑与自定义变量的赋值顺序不匹配,具体来说:
- 窗口函数
sum(b) over (order by a)的执行逻辑是:先将整个数据集按a排序,然后针对排序后的每一行,计算从第一行到当前行的b值累加——全程基于原始列的固定值,结果稳定。 - 自定义变量
@b2 := b是在SELECT阶段逐行执行赋值,但MySQL不保证窗口函数与SELECT列的执行顺序。实际执行中,窗口函数sum(@b2)的计算会先于变量的逐行赋值完成,或者在所有行的变量赋值完成后才计算,导致窗口函数使用的是变量的最终值(最后一行的8)而非当前行的实时赋值。 - 从结果可以验证:第一行的
b2_accum为8,正好是最后一行的b值,说明计算窗口函数时@b2已经被设置为8;更本质的是,MySQL官方明确不支持在窗口函数中使用用户变量,这类用法的行为是未定义的,结果完全不可预测。
简言之:窗口函数依赖的是排序后数据集的原始列值,而自定义变量的赋值顺序与窗口函数的计算顺序无明确约定,因此两者的sum结果无法一致。
内容的提问来源于stack exchange,提问作者Greendrake
相关产品推荐
相关产品推荐

