PostgreSQL易变函数引起的错误执行计划
如果在索引上使用易变函数作为条件,PG不会选择索引扫描,本文分析一下原因和规避方法。
1、建演示表
CREATE TABLE t2(
c1 int PRIMARY KEY,
c2 float,
c3 text
);
随便造点数据
INSERT INTO t2 SELECT a,random()*500000000,random()*500000000 FROM generate_series(1, 50000) a;
2、主键条件查询
使用常数作为条件
postgres=# EXPLAIN SELECT * FROM t2 WHERE c1 = 100;
QUERY PLAN
Index Scan using t2_pkey on t2 (cost=0.29..8.31 rows=1 width=30)
Index Cond: (c1 = 100)
(2 rows)
使用易变函数作为条件
postgres=# EXPLAIN SELECT * FROM t2 WHERE c1 = (random()*50000)::int;
QUERY PLAN
Seq Scan on t2 (cost=0.00..1417.00 rows=1 width=30)
Filter: (c1 = ((random() * '50000'::double precision))::integer)
(2 rows)
按理,这里是个唯一索引,无论如何也应该使用索引扫描才对。
3、原因
在生成路径的时候
函数 match_opclause_to_indexcol 中
if (match_index_to_operand(rightop, indexcol, index) &&
!bms_is_member(index_relid, rinfo->left_relids) &&
!contain_volatile_functions(leftop))
如果发现条件中含有易变函数,不生成索引扫描路径,也就根本不会生成索引扫描计划。
4、解决办法
使用子查询
postgres=# EXPLAIN SELECT * FROM t2 WHERE c1 = (SELECT (random()*50000)::int);
QUERY PLAN
Index Scan using t2_pkey on t2 (cost=0.31..8.32 rows=1 width=30)
Index Cond: (c1 = 0)
InitPlan 1 (returns 0)
-> Result (cost=0.00..0.02 rows=1 width=4)
(4 rows)
因为在 contain_volatile_functions 时使用 expression_tree_walker 遍历表达式,对于子查询,它对应的节点类型是 Param。这个在 expression_tree_walker 函数注释中有说明,它无法定位子查询,也就无从判断是否含有易变函数。
可以说,这是一个错误(不合理)行为带来的正确结果。
免责声明:
1、本站资源由自动抓取工具收集整理于网络。
2、本站不承担由于内容的合法性及真实性所引起的一切争议和法律责任。
3、电子书、小说等仅供网友预览使用,书籍版权归作者或出版社所有。
4、如作者、出版社认为资源涉及侵权,请联系本站,本站将在收到通知书后尽快删除您认为侵权的作品。
5、如果您喜欢本资源,请您支持作者,购买正版内容。
6、资源失效,请下方留言,欢迎分享资源链接
文章评论