PostgreSQL中STABLE函数在单查询内是否保证返回相同结果?
结论
两个子查询返回的COUNT结果不一定一致。
待分析SQL
SELECT * FROM (SELECT COUNT(1) FROM tbl) tbl1, (SELECT COUNT(1) FROM tbl) tbl2
PostgreSQL函数稳定性分类的执行规则
PostgreSQL通过函数稳定性标记决定优化器的执行策略,三类标记的核心逻辑如下:
IMMUTABLE:入参固定时永远返回相同结果,不依赖数据库状态、外部环境变化。优化器会在查询规划阶段直接对同入参的该类函数做常量折叠,不会在执行阶段重复计算,同一条语句内任意位置调用结果完全一致。VOLATILE:不对结果一致性做任何保证,哪怕入参完全相同,两次调用也可能返回不同结果。优化器不会对这类函数做任何跨调用的结果复用,每到调用点就会重新执行,典型代表为random()、clock_timestamp()。STABLE:一致性保证有严格的范围边界:仅保证在单条语句的同一调用上下文中,相同入参的调用返回一致结果。优化器可以对符合范围要求的STABLE函数单次计算后复用结果,但不会主动识别不同位置、逻辑等价的STABLE表达式或子查询的等价性,也不会跨独立执行节点强制复用结果。
本场景结果可能不一致的原因
- 语句中的
COUNT(1)属于STABLE类聚合,结果依赖表内符合可见性规则的元组总量,不属于IMMUTABLE范畴,优化器不会提前将其计算为常量。 - 两个子查询是FROM子句中的独立非相关派生表,PostgreSQL默认不会对这类逻辑等价的独立子查询做公共子表达式消除,也不会强制将两个子查询扁平化合并为单次扫描,二者会作为独立执行节点被分别调度,执行存在明确的时间差。
- 按题设场景,查询总耗时10秒,期间目标表平均会写入约16.7万条新数据。在默认读已提交隔离级别下,独立调度的子查询节点如果没有被优化器合并,会在自身执行开始时获取独立的一致性快照,后执行的子查询会看到两次执行间隙中已提交的新增数据,最终返回和第一个子查询不同的COUNT结果。
- 只有当两个子查询被优化器识别为等价公共表达式、或被扁平化合并为单次扫描时,二者才会共享同一个快照返回一致结果,这种情况无法保证必然出现。
内容的提问来源于stack exchange,提问作者David542
相关产品推荐
相关产品推荐

