暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL - where x=round(random()*xx) 返回结果反常 - 背后的函数稳定性逻辑 (immutable stable volatile)

digoal 2020-11-20
313

作者

digoal

日期

2020-11-20

标签

PostgreSQL , 函数稳定性 , immutable , stable , volatile


背景

PostgreSQL 提供3种函数稳定性, 在执行过程中略有不同:

  • immutable, 入参不变, 结果永远不变. 在生成执行计划前被执行, 所以你看执行计划会发现immutable的函数已经被执行了, 所以它在整个运行过程中运算一次. 可用于表达式索引.
  • stable, 入参不变, 结果在一个事务中保证不变. 在sql语句开始时执行, 只调用一次. 不可用于索引表达式, 但是可被优化器用于索引条件过滤, where x = stable_func, 可以走索引.
  • volatile, 结果随时变化. 不可用于索引表达式, 也不可用于索引过滤. 所以需要逐条执行.

例如下面的例子, 感觉很奇怪, 其实不奇怪

```
postgres=> create table a (id int);
CREATE TABLE
postgres=> insert into a select generate_series(1,1000);
INSERT 0 1000
postgres=> select * from a where id=round(random()*100);
id


28
(1 row)

postgres=> select * from a where id=round(random()*1000);
id


355
440
(2 rows)
```

为什么id=round(random()\*1000); 返回多行? 原因是random()是volatile函数, 逐条执行, 所以有可能出现多次冲撞到相等值, 也有可能没有结果返回, 也可能返回一个, 都在预期内.

List of functions Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Source code | Description ------------+--------+------------------+---------------------+------+------------+------------+------------+----------+-------------------+----------+-------------+-------------- pg_catalog | random | double precision | | func | volatile | restricted | pg36694487 | invoker | | internal | drandom | random value (1 row)

当然以上约束只是概念上的, 如果你自定义的函数, 可以实际情况与定义不符, 那么优化器会傻掉, 那是优化器的错吗? 不是, 是你的错, 胡乱定义.

《函数稳定性讲解 - retalk PostgreSQL function's [ volatile|stable|immutable ]》

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论