PostgreSQL中random()函数为何无法始终生成随机值?
为什么PostgreSQL的random()函数有时无法生成不同的随机值?
PostgreSQL里的random()是不稳定(volatile)函数,理论上每次调用都应该返回不同的随机值,但查询结构和优化器的处理逻辑会影响它的调用次数,导致出现看似“不随机”的结果。我们逐个分析你给出的例子:
1. 生成两个不同值的情况
select random(), random();
在这个简单的SELECT列表中,每个random()都会被独立调用一次,因此返回两个不同的随机值。
2. 生成两个相等值的情况
例子一
select random(), random() order by random();
这里的问题出在ORDER BY的处理逻辑上:PostgreSQL执行带ORDER BY的查询时,会先计算SELECT列表中的表达式,再对结果排序。但因为random()是不稳定函数,优化器会将SELECT列表中的两个random()调用视为可复用的表达式,只计算一次后填充到两个列中,最终导致两个值相等。
例子二
select (select random()) as r from generate_series(1,2);
这里的子查询(select random())是不引用外部列的标量子查询,PostgreSQL优化器会将其视为常量,只执行一次这个子查询,再把结果重复返回两次(对应generate_series(1,2)生成的两行),因此得到两个相同的随机值。
3. 再次生成不同值的情况
select (select random() + g - g) as r from generate_series(1,2) as g;
这个例子里的子查询引用了外部的g列(哪怕+g -g不改变数值,也让子查询依赖于外部行的变量)。PostgreSQL会为generate_series生成的每一行独立执行一次子查询,因此random()会被调用两次,返回两个不同的随机值。
总结
random()本身是符合预期的随机函数,问题出在PostgreSQL的查询优化逻辑上:
- 当不稳定函数的调用不依赖外部行变量时,优化器可能会将其计算一次并复用结果;
- 当函数调用依赖外部行变量(哪怕是无意义的依赖),优化器会为每行独立调用一次函数。
内容的提问来源于stack exchange,提问作者Code4R7
相关产品推荐
相关产品推荐

