一、前言

对于含有union , group by 等的视图,我们称之为复杂视图。 这类的视图会影响优化器对于视图的提升,也就是视图无法与父查询进行合并,从而影响访问路径、连接方法、连接顺序等。本文通过例子,给大家展示PostgreSQL这类问题及针对该问题的优化方法。

二、Union 视图的优化

1、构建例子:

create table t1(id1 integer);
insert into t1 select generate_series(1,10); create table t2(id2 integer,name char(500));
insert into t2 select generate_series(1,1000000),repeat('a',400);
create index ind_t2 on t2(id2); create table t3(id3 integer,name char(500));
insert into t3 select generate_series(1,1000000),repeat('a',400);
create index ind_t3 on t3(id3); create or replace view v_t2_t3 as
select id2 as id from t2
union
select id3 as id from t3;

2、分析执行计划

执行计划如下:

testdb=# explain analyze select * from t1,v_t2_t3 where id1=id;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Merge Join (cost=447340.31..483340.14 rows=99999 width=8) (actual time=1313.700..1313.711 rows=10 loops=1)
Merge Cond: (t1.id1 = t2.id2)
-> Sort (cost=1.27..1.29 rows=10 width=4) (actual time=0.019..0.021 rows=10 loops=1)
Sort Key: t1.id1
Sort Method: quicksort Memory: 25kB
-> Seq Scan on t1 (cost=0.00..1.10 rows=10 width=4) (actual time=0.009..0.011 rows=10 loops=1)
-> Unique (cost=447339.04..457338.98 rows=1999988 width=4) (actual time=1313.674..1313.681 rows=10 loops=1)
-> Sort (cost=447339.04..452339.01 rows=1999988 width=4) (actual time=1313.673..1313.676 rows=19 loops=1)
Sort Key: t2.id2
Sort Method: external merge Disk: 27488kB
-> Append (cost=0.00..183333.70 rows=1999988 width=4) (actual time=0.017..923.420 rows=2000000 loops=1)
-> Seq Scan on t2 (cost=0.00..76666.94 rows=999994 width=4) (actual time=0.016..547.533 rows=1000000 loops=1)
-> Seq Scan on t3 (cost=0.00..76666.94 rows=999994 width=4) (actual time=0.014..261.595 rows=1000000 loops=1)
Planning Time: 3.124 ms
Execution Time: 1316.691 ms
(15 rows)

问题分析:视图 v_t2_t3 并没有与 t1进行合并(Unique部分),而是 t1 与 结果进行连接。这个执行计划的问题在于 t1 表的数据量很少,如果能把 t1.id1 传入到视图,视图内部访问 t2 , t3 时就可以走索引,效率上要更高。

3、修改SQL

testdb=# explain analyze select * from t1,v_t2_t3 where id1=id and id=any(array(select id1 from t1));
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=98.95..100.08 rows=10 width=8) (actual time=0.126..0.129 rows=10 loops=1)
Hash Cond: (t1.id1 = t2.id2)
InitPlan 1 (returns $0)
-> Seq Scan on t1 t1_1 (cost=0.00..1.10 rows=10 width=4) (actual time=0.001..0.002 rows=10 loops=1)
-> Seq Scan on t1 (cost=0.00..1.10 rows=10 width=4) (actual time=0.005..0.006 rows=10 loops=1)
-> Hash (cost=97.60..97.60 rows=20 width=4) (actual time=0.115..0.116 rows=10 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> HashAggregate (cost=97.20..97.40 rows=20 width=4) (actual time=0.112..0.114 rows=10 loops=1)
Group Key: t2.id2
-> Append (cost=0.42..97.15 rows=20 width=4) (actual time=0.060..0.105 rows=20 loops=1)
-> Index Only Scan using ind_t2 on t2 (cost=0.42..48.43 rows=10 width=4) (actual time=0.060..0.072 rows=10 loops=1)
Index Cond: (id2 = ANY ($0))
Heap Fetches: 10
-> Index Only Scan using ind_t3 on t3 (cost=0.42..48.43 rows=10 width=4) (actual time=0.022..0.032 rows=10 loops=1)
Index Cond: (id3 = ANY ($0))
Heap Fetches: 10
Planning Time: 0.171 ms
Execution Time: 0.163 ms
(18 rows)

  

分析:通过增加条件 id=any(array(select id1 from t1)) , 可以看到该条件可以传入到视图内部。视图内部对于 t2 , t3 的访问是走索引的。

4、问题分析结论

对于类似 v_t2_t3 这种含有 union 的复杂视图,除非是指定明确的值,如 v_t2_t3.id=xxx , 才可以传入的视图内部。 而对于连接条件,如: id1=id,则无法将 id1 传入到视图内部,这时视图只能走全表访问。

三、KingbaseES 提升了优化器能力

KingbaseES 通过修改优化器算法,实现了在RBO 层面对于该类SQL 的改写,避免了该问题。

PostgreSQL 涉及复杂视图查询的优化案例的更多相关文章

  1. 【PostgreSQL】 前缀模糊查询级优化

    前匹配模糊 使用B-Tree来加速优化前匹配模糊查询 构造数据 新建一张商品表,插入一千万条数据. create table goods(id int, name varchar); insert i ...

  2. 记一次mysql多表查询(left jion)优化案例

    一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...

  3. 数据库优化案例——————某知名零售企业ERP系统

    写在前面 记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也分享自己做的优化案例. 之前分享过OA系统.H ...

  4. 数据库优化案例——————某市中心医院HIS系统

    记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也开始分享自己做的优化案例. 最近一直很忙,博客产出也少的 ...

  5. mysql笔记03 查询性能优化

    查询性能优化 1. 为什么查询速度会慢? 1). 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减 ...

  6. MySQL查询性能优化(精)

    MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下 ...

  7. 170727、MySQL查询性能优化

    MySQL查询性能优化 MySQL查询性能的优化涉及多个方面,其中包括库表结构.建立合理的索引.设计合理的查询.库表结构包括如何设计表之间的关联.表字段的数据类型等.这需要依据具体的场景进行设计.如下 ...

  8. MySQL/MariaDB数据库的查询缓存优化

    MySQL/MariaDB数据库的查询缓存优化 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL架构 Connectors(MySQL对外提供的交互接口,API): ...

  9. 《高性能MySQL》之MySQL查询性能优化

    为什么查询会慢? 响应时间过长.如果把查询看做是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化查询,实际上优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数, ...

随机推荐

  1. linux-基于tensorflow2.x的手写数字识别-基于MNIST数据集

    数据集 数据集下载MNIST 首先读取数据集, 并打印相关信息 包括 图像的数量, 形状 像素的最大, 最小值 以及看一下第一张图片 path = 'MNIST/mnist.npz' with np. ...

  2. UiPath循环活动Do While的介绍和使用

    一.Do While的介绍 先执行循环体, 再判断条件是否满足, 如果满足, 则再次执行循环体, 直到判断条件不满足, 则跳出循环 二.Do While在UiPath中的使用 1. 打开设计器,在设计 ...

  3. Pytorch Dataloader加速

    在进行多卡训练的时候,经常会出现GPU利用率上不来的情况,无法发挥硬件的最大实力. 造成这种现象最有可能的原因是,CPU生成数据的能力,已经跟不上GPU处理数据的能力. 方法一 常见的方法为修改Dat ...

  4. Bash脚本debug攻略

    初学Bash时, 我从未想过想过bash也能debug, 也从未想过去debug Bash脚本. 随着技术的增长, 写的脚本越来越复杂, 使用echo打印日志来调试脚本的方式越来越捉襟见肘了. 直到某 ...

  5. esp8266模拟输入(ADC)检测问题

    今天使用esp12f读取A0数据时一直出现错误; Serial.println(analogRead(A0));读取值一直为1024 因为前段时间一直用的是开发板,读取电压值正常 而从昨天换为了esp ...

  6. Cube Stacking 来源:洛谷

    题目 题目oj(洛谷) Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes ...

  7. DFS序和7种模型

    DFS序就是将树的节点按照先根的顺序遍历得到的节点顺序 性质:一个子树全在一个连续的区间内,可以与线段树和树状数组搭配使用 很好写,只需在dfs中加几行代码即可. 代码: void dfs(ll u, ...

  8. 记一次删除k8s namespace无法删除的问题

    在用longhorn工具做k8s存储卷动态预配的时候,需要修改longhorn.yaml的一个默认参数,修改完成需要重新加载longhorn.yaml,结果重新加载出错了,修改的参数没有生效,于是执行 ...

  9. 第一天python3 封装和解构

    封装 将多个值使用逗号分割,组合在一起:本质上,返回一个元组,只是省略了小括号:python特有语法,被很多语言学习和借鉴;比如javascript:t1=(1,2) 定义为元组:t2=1,2 将1和 ...

  10. angular里forwardRef的原理

    一段会报错的angular代码 @Injectable() class Socket { constructor(private buffer: Buffer) { } } console.log(B ...