PostgreSQL SQL OUTLINE插件sr_plan (保存、篡改、固定 执行计划)

本文介绍了PostgreSQL中的sr_plan插件,该插件类似Oracle的SQL Outline,允许用户保存和篡改查询的执行计划。通过示例展示了如何使用sr_plan收集、修改并应用执行计划,以优化查询性能。
摘要由CSDN通过智能技术生成

标签

PostgreSQL , sql plan outline , 执行计划篡改 , query rewrite , sr_plan , pg plan hint


背景

功能较为强大的数据库,通常都有query rewrite的功能,比如JOIN时提升或下推条件,调整JOIN顺序等。

例如

create table a(id int, info text);  
create table b(id int, info text);  
create index idx_a_info on a (info);  
create index idx_b_id on b(id);  

执行以下查询,我们看看query rewrite如何工作的

postgres=# explain select * from a left join (select id,count(info) from b group by id) b on (a.id=b.id) where a.id=1;  
                                      QUERY PLAN                                        
--------------------------------------------------------------------------------------  
 Nested Loop Left Join  (cost=13.24..180340.52 rows=934 width=27)  
   Join Filter: (a.id = b.id)  
   ->  Seq Scan on a  (cost=0.00..179054.03 rows=1 width=15)  
         Filter: (id = 1)  
   ->  GroupAggregate  (cost=13.24..1265.48 rows=934 width=12)  
         Group Key: b.id  
         ->  Bitmap Heap Scan on b  (cost=13.24..1251.24 rows=981 width=9)  
               Recheck Cond: (id = 1)  
               ->  Bitmap Index Scan on idx_b_id  (cost=0.00..12.99 rows=981 width=0)  
                     Index Cond: (id = 1)  
(10 rows)  

这里只提供了a.id=1的条件,这个查询条件被重写,推入子查询中,所以我们看到子查询实际上也过滤了b.id=1的条件。

通过以上例子,我们见识到了QUERY REWRITE的用途,那么是不是所有场景都能rewrite 呢?

例如我们把以上QUERY换一个条件,改写为如下

postgres=# explain select * from a left join (select id,count(info) from b group by id) b on (a.id=b.id) where a.info='test1';  
                                   QUERY PLAN                                      
---------------------------------------------------------------------------------  
 Hash Right Join  (cost=204060.69..204298.22 rows=1 width=27)  
   Hash Cond: (b.id = a.id)  
   ->  HashAggregate  (cost=204057.62..204157.64 rows=10001 width=12)  
         Group Key: b.id  
         ->  Seq Scan on b  (cost=0.00..154056.75 rows=10000175 width=9)  
   ->  Hash  (cost=3.05..3.05 rows=1 width=15)  
         ->  Index Scan using idx_a_info on a  (cost=0.43..3.05 rows=1 width=15)  
               Index Cond: (info = 'test1'::text)  
(8 rows)  

从以上执行计划,我们看到这个query rewrite并没有将a.info='test1'间接的推入子查询。

而实际上,PostgreSQL只是根据成本选择了一个执行计划,并不是说它不能推入a.info='test1'的条件,请继续看我在后面sr_plan中的测试,会看到PostgreSQL的CBO还是非常强大的。

另一方面,作为用户,以上QUERY可以改写为如下(或者说这是你期待的query rewrite对吧)

select * from a left join (select id,count(info) from b   
  where exists (select 1 from a where a.id=b.id and a.info='test')  -- 改写QUERY,得到同样结果,但是B的聚合量减少了  
  -- 或者 where id in (select id from a where a.info='test1')  
  -- 或者 还有其他改法,拆掉子查询  
group by id) b on (a.id=b.id) where a.info='test1';  

改写后的执行计划如下,b在聚合前,可以使用a的条件过滤掉一些记录,从而减少聚合的量

                                           QUERY PLAN                                             
------------------------------------------------------------------------------------------------  
 Hash Right Join  (cost=1295.06..1318.82 rows=1 width=27)  
   Hash Cond: (b.id = a.id)  
   ->  HashAggregate  (cost=1292.00..1302.00 rows=1000 width=12)  
         Group Key: b.id  
         ->  Nested Loop  (cost=16.44..1287.00 rows=1000 width=9)  
               ->  HashAggregate  (cost=3.05..3.06 rows=1 width=4)  
                     Group Key: a_1.id  
                     ->  Index Scan using idx_a_info on a a_1  (cost=0.43..3.05 rows=1 width=4)  
                           Index Cond: (info = 'test1'::text)  
               ->  Bitmap Heap Scan on b  (cost=13.38..1273.93 rows=1000 width=9)  
                     Recheck Cond: (id = a_1.id)  
                     ->  Bitmap Index Scan on idx_b_id  (cost=0.00..13.13 rows=1000 width=0)  
                           Index Cond: (id = a_1.id)  
   ->  Hash  (cost=3.05..3.05 rows=1 width=15)  
         ->  Index Scan using idx_a_info on a  (cost=0.43..3.05 rows=1 width=15)  
               Index Cond: (info = 'test1'::text)  
(16 rows)  

query rewrite是一个比较智能的工作,在某些情况下,可以起到很好的性能优化作用,query rewrite也是许多数据库产品比拼的技术之一。

PostgreSQL这方面还是非常有优势的,请看我在SR_PLAN中的例子,加油。

其实除了query rewrite,PostgreSQL的社区还提供了一个非常强大的插件,sr_plan。

类似于Oracle的sql outline。

sr_plan插件介绍

sr_plan插件,可以保存QUERY的执行计划,(支持绑定变量的QUERY),同时允许篡改执行计划,让篡改的执行计划生效。

针对每一条保存的执行计划,允许单独开启或关闭。

sr_plan实际上利用了PostgreSQL的钩子,通过post_parse_analyze_hook获取parser后的text并保存到sr_plan的query字段中,通过planner_hook保存、处理、返回保存的执行计划。

了解sr_plan的工作原理,我们来试用一下,看看以上query如何使用sr_plan来重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值