Postgres 10:在不可变函数中伪造now()是否安全?
在Postgres 10的不可变函数中伪造
now()是否安全? 嘿,针对你的这个疑问,我来拆解下这里面的安全性和风险点——毕竟你做的是给皮划艇爱好者提供水位降雨信息的服务,数据准确性和查询稳定性肯定是核心对吧?
结论先行:这么做并不安全,而且对你的场景风险很大
为什么违背Postgres的设计逻辑?
Postgres对函数的稳定性有明确的分级规则:
IMMUTABLE(不可变)函数要求相同输入必须返回完全相同的结果,绝对不能依赖任何可变的外部状态(比如当前时间、数据库数据变化)。now()属于VOLATILE(易变)函数,每次调用结果都不同,把它塞进不可变函数里,直接打破了不可变函数的核心约定。
带来的直接风险有两个:
- 查询结果不准确:Postgres会缓存不可变函数的计算结果,一旦你伪造
now(),后续查询可能复用几小时甚至几天前的旧时间值,导致你查水位数据时漏掉最新的15分钟上报读数,这对依赖实时数据的皮划艇用户来说是致命的。 - 分区剪枝失效:你迁移到Linode自建服务器就是为了用范围分区提速,要是函数稳定性被破坏,Postgres规划器没法正确判断该扫描哪些2周分片,直接回到全表扫描的慢速度,分区的优势完全浪费。
有没有“相对安全”的例外?
说实话,几乎没有适合你场景的例外。如果是一次性的临时脚本查询,而且你明确知道不会复用查询规划,可能暂时不会出问题,但对你这种持续接收数据、需要稳定查询的服务来说,这种情况完全不适用。
针对你的水位数据场景,更安全的替代方案
既然你是按2周分片存储水位计读数,推荐这两种更稳妥的方式:
- 直接在查询中写时间逻辑:比如查最近2周的数据,直接用
WHERE reading_time >= now() - interval '2 weeks',这种写法清晰直白,Postgres能正确识别时间范围,正常触发分区剪枝,查询速度有保障。 - 用
STABLE函数封装逻辑:如果必须把时间判断封装成函数,把函数的稳定性设为STABLE而非IMMUTABLE。STABLE函数在同一个查询内结果不变,但不同查询会重新计算now(),既满足你封装逻辑的需求,又不会破坏规划器的判断,分区剪枝也能正常工作。
内容的提问来源于stack exchange,提问作者Debaser
相关产品推荐
相关产品推荐

