SQL 优化的过程可以分为逻辑优化和物理优化两个部分。逻辑优化主要是基于规则的优化,简称 RBO(Rule-Based Optimization)。物理优化会为逻辑查询计划中的算子选择某个具体的实现,需要用到一些统计信息,决定哪一种方式代价最低,所以是基于代价的优化 CBO(Cost-Based Optimization)。

本文将主要介绍Kingbase数据库的逻辑优化规则。

准备数据:

create table big(id int , bname varchar(20)); 

create table middle(id int , bname varchar(20)); 

create table small(id int , sname varchar(20)); 

insert into big  select  generate_series(1 , 1000), dbms_random.string('l',5) ; 

insert into middle  select  generate_series(501 , 1000), dbms_random.string('l',5) ; 

insert into small  select  generate_series(951 , 1050), dbms_random.string('l',5) ;

逻辑优化分类

[逻辑优化分类]
|选择下推
|谓词下推
|逻辑分解优化 ⇒ |连接顺序交换
| |等价类推理
逻辑优化 ⇒
| |子查询提升
|逻辑重写优化 ⇒ |子连接提升
|表达式预处理
|外连接消除

逻辑分解优化

选择下推

连接条件直接下推到自己所涉及的基表上。

demo=# explain analyze select * from big b left join small s on b.id = s.id and s.id = 1000;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Hash Left Join (cost=2.26..22.02 rows=1000 width=20) (actual time=0.027..0.228 rows=1000 loops=1)
Hash Cond: (b.id = s.id)
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.010..0.079 rows=1000 loops=1)
-> Hash (cost=2.25..2.25 rows=1 width=10) (actual time=0.012..0.013 rows=1 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Seq Scan on small s (cost=0.00..2.25 rows=1 width=10) (actual time=0.008..0.010 rows=1 loops=1)
Filter: (id = 1000)
Rows Removed by Filter: 99
Planning Time: 0.077 ms
Execution Time: 0.276 ms
(10 行记录)

谓词下推

谓词下推 Predicate Pushdown(PPD):简而言之,就是在不影响结果的情况下,尽量将过滤条件提前执行。

demo=# explain analyze select * from big b left join small s on b.id = s.id and b.id = 1000;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Hash Left Join (cost=3.25..24.25 rows=1000 width=20) (actual time=0.035..0.304 rows=1000 loops=1)
Hash Cond: (b.id = s.id)
Join Filter: (b.id = 1000)
Rows Removed by Join Filter: 49
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.010..0.091 rows=1000 loops=1)
-> Hash (cost=2.00..2.00 rows=100 width=10) (actual time=0.020..0.020 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Seq Scan on small s (cost=0.00..2.00 rows=100 width=10) (actual time=0.004..0.009 rows=100 loops=1)
Planning Time: 0.078 ms
Execution Time: 0.365 ms
(10 行记录)

规则:

1:连接条件下推之后会变成过滤条件,过滤条件下推之后仍然是过滤条件。

2:如果连接条件引用了 Nonnullable-side 的表,那么连接条件不能下推;如果连接条件只引用了 Nullable-side 的表,那么连接条件可以下推。

3:如果过滤条件只引用了 Nonnullable-side 的表,那么这个过滤条件能够下推到表上;如果过滤条件引用了 Nullable-side的表且过滤条件是严格的,那么会导致外连接消除,外连接消除之后变成内连接,过滤条件也是能下推的。

连接顺序交换

优化器对表的连接顺序进行重新排列。


demo=# explain analyze select * from big b left join middle m on true left join small s on m.id = s.id ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Nested Loop Left Join (cost=3.25..6281.38 rows=500000 width=30) (actual time=0.043..84.884 rows=500000 loops=1)
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.009..0.200 rows=1000 loops=1)
-> Materialize (cost=3.25..16.62 rows=500 width=20) (actual time=0.000..0.020 rows=500 loops=1000)
-> Hash Left Join (cost=3.25..14.12 rows=500 width=20) (actual time=0.029..0.135 rows=500 loops=1)
Hash Cond: (m.id = s.id)
-> Seq Scan on middle m (cost=0.00..8.00 rows=500 width=10) (actual time=0.004..0.036 rows=500 loops=1)
-> Hash (cost=2.00..2.00 rows=100 width=10) (actual time=0.020..0.020 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Seq Scan on small s (cost=0.00..2.00 rows=100 width=10) (actual time=0.003..0.008 rows=100 loops=1)
Planning Time: 0.149 ms
Execution Time: 99.958 ms
(11 行记录)

规则:

假设 A、B、C 为参与连接的基表,Pab 代表引用了 A 表和 B 表上的列的谓词(连接条件)。

  1. LEFT JOIN 相关的连接顺序交换等式:

1.1 等式 1: ( A left join B on (Pab)) inner join C on (Pac) = ( A inner join C on (Pac)) left join b on (Pab)

1.2 等式 2: ( A left join B on (Pab)) left join C on (Pac) = ( A left join C on (Pac)) left join b on (Pab)

1.3 等式 3: ( A left join B on (Pab)) left join C on (Pbc) = A left join ( B left join C on (Pbc)) on (Pab)

&Pbc 必须是严格的筛选条件

  1. Semi Join 有关的连接顺序交换等式:

( A semi Join B on (Pab)) innerjoin/leftjoin/semijoin/antijoin C on (Pac) =

( A innerjoin/leftjoin/semijoin/antijoin C on (Pac)) semi Join B on (Pab)

  1. Anti Join 有关的连接顺序交换等式:

( A anti Join B on (Pab)) innerjoin/leftjoin/semijoin/antijoin C on (Pac) =

( A innerjoin/leftjoin/semijoin/antijoin C on (Pac)) anti Join B on (Pab)

等价类推理

等值查询时,检索条件a.id = b.id and a.id = 1 ,会将检索条进行推理为a.id = 1 and b.id = 1

demo=# explain analyze select * from big b ,small s where b.id = s.id and b.id = 100;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..20.76 rows=1 width=20) (actual time=0.271..0.272 rows=0 loops=1)
-> Seq Scan on big b (cost=0.00..18.50 rows=1 width=10) (actual time=0.046..0.261 rows=1 loops=1)
Filter: (id = 100)
Rows Removed by Filter: 999
-> Seq Scan on small s (cost=0.00..2.25 rows=1 width=10) (actual time=0.008..0.008 rows=0 loops=1)
Filter: (id = 100)
Rows Removed by Filter: 100
Planning Time: 0.123 ms
Execution Time: 0.330 ms
(9 行记录)

逻辑重写优化

Kingbase数据库基于子查询所在的位置和作用的不同,将子查询细分成了两类,一类称为子连接(SubLink),另一类称为子查询(SubQuery)。通常而言,

如果它是以“表”的方式存在的,那么就称为子查询,如果它以表达式的方式存在,那么就称为子连接。

子连接和子查询的区别:出现在 FROM 关键字后的子句是子查询语句,出现在 WHERE/ON 等约束条件中或投影中的子句是子连接语句。

相关子连接和非相关子连接:

相关子连接:指在子查询语句中引用了外层表的列属性,这就导致外层表每获得一个元组,子查询就需要重新执行一次。

非相关子连接:指子查询语句是独立的,和外层的表没有直接的关联,子查询可以单独执行一次,外层表可以重复利用子查询的执行结果。

子查询提升

demo=# explain analyze select * from big b ,(select * from small s where s.id > 100) s where b.id = s.id ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Hash Join (cost=3.50..24.25 rows=100 width=20) (actual time=0.203..0.220 rows=50 loops=1)
Hash Cond: (b.id = s.id)
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.011..0.089 rows=1000 loops=1)
-> Hash (cost=2.25..2.25 rows=100 width=10) (actual time=0.029..0.029 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Seq Scan on small s (cost=0.00..2.25 rows=100 width=10) (actual time=0.006..0.016 rows=100 loops=1)
Filter: (id > 100)
Planning Time: 0.091 ms
Execution Time: 0.245 ms
(9 行记录)

子连接提升

将子连接提升为子查询。

demo=# explain analyze select * from big b where exists (select * from small s where b.id = s.id) ;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
Hash Semi Join (cost=3.25..22.99 rows=100 width=10) (actual time=0.168..0.180 rows=50 loops=1)
Hash Cond: (b.id = s.id)
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.010..0.073 rows=1000 loops=1)
-> Hash (cost=2.00..2.00 rows=100 width=4) (actual time=0.025..0.025 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 12kB
-> Seq Scan on small s (cost=0.00..2.00 rows=100 width=4) (actual time=0.005..0.012 rows=100 loops=1)
Planning Time: 0.078 ms
Execution Time: 0.200 ms
(8 行记录)

规则:

  1. EXISTS 类型的相关子连接会被提升(需要是“简单”的子连接 )
  2. EXISTS 非相关子连接会形成子执行计划单独求解
  3. ANY 类型的非相关子连接可以提升(需要是“简单”的子连接),且可以通过物化的方式进行优化
  4. ANY 类型的相关子连接目前还不能提升
  5. 相关子连接提升上来之后可以避免那种 O(N^2) 式的子计划的执行方式(参照上面的借助参数执行的情况),例如提升上来之后借助哈希表实现优化
  6. 不能提升的一种情况是非相关子连接,因为只需要执行一次就能反复利用它的执行结果
  7. 另一种不能提升的情况是对于外连接,它需要满足的是和 Nullable 端相关,而非和 Nonnullable 端相关

“简单”子连接:不包含通用表达式(CTE), 集合操作、聚集操作、HAVING 子句等的子连接叫作“简单”子连接。

注意:

子句中如果包含通用表达式(CTE),子连接不能提升。如果子句中包含集合操作、聚集操作、HAVING子句等,子连接不能提升,否则子连接中的子句进行简化。

表达式预处理

对表达式进行处理,简化约束条件

demo=# explain analyze select * from big b where b.id > 100 and 1 = 2;
QUERY PLAN
------------------------------------------------------------------------------------
Result (cost=0.00..0.00 rows=0 width=0) (actual time=0.001..0.001 rows=0 loops=1)
One-Time Filter: false
Planning Time: 0.040 ms
Execution Time: 0.011 ms
(4 行记录)

外连接消除

通过对连接条件限制,消除外连接,转换为内连接处理

demo=# explain analyze select * from big b left join small s on b.id = s.id where s.id is not null ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Hash Join (cost=3.25..24.00 rows=100 width=20) (actual time=0.278..0.292 rows=50 loops=1)
Hash Cond: (b.id = s.id)
-> Seq Scan on big b (cost=0.00..16.00 rows=1000 width=10) (actual time=0.010..0.134 rows=1000 loops=1)
-> Hash (cost=2.00..2.00 rows=100 width=10) (actual time=0.037..0.037 rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 13kB
-> Seq Scan on small s (cost=0.00..2.00 rows=100 width=10) (actual time=0.020..0.028 rows=100 loops=1)
Filter: (id IS NOT NULL)
Planning Time: 0.148 ms
Execution Time: 0.339 ms
(9 行记录)

总结:

Kingbase数据库逻辑优化方式,通过找出SQL等价的变换形式让 SQL 执行效率更高效。这些规则背后的原理就是关系代数的等价变换,其中典型的规则包括:列剪裁,谓词下推等,对查询进行重写。SQL 的查询重写包括了子查询优化、等价谓词重写、视图重写、条件简化、连接消除和嵌套连接消除等。各种逻辑优化技术依据关系代数和启发式规则进行。

KingbaseES 数据库逻辑优化规则的更多相关文章

  1. KingbaseES 数据库参数优化

    一.数据库应用类型 针对不同的应用模型,需要对数据库配置进行优化: 1.网络应用程序(WEB) ​通常受 CPU 限制 DB比RAM小得多 90% 或更多的简单查询 2.在线事务处理 (OLTP) ​ ...

  2. MYSQL数据库的优化

    我们究竟应该如何对MySQL数据库进行优化?下面我就从MySQL对硬件的选择.MySQL的安装.my.cnf的优化.MySQL如何进行架构设计及数据切分等方面来说明这个问题. 服务器物理硬件的优化 在 ...

  3. 转载:SqlServer数据库性能优化详解

    本文转载自:http://blog.csdn.net/andylaudotnet/article/details/1763573 性能调节的目的是通过将网络流通.磁盘 I/O 和 CPU 时间减到最小 ...

  4. [转]MySQL数据库的优化-运维架构师必会高薪技能,笔者近六年来一线城市工作实战经验

    本文转自:http://liangweilinux.blog.51cto.com/8340258/1728131 年,嘿,废话不多说,下面开启MySQL优化之旅! 我们究竟应该如何对MySQL数据库进 ...

  5. 总结sqlserver数据库性能优化相关的注意事项

    一.分析阶段一般来说,在系统分析阶段往往有太多需要关注的地方,系统各种功能性.可用性.可靠性.安全性需求往往吸引了我们大部分的注意力,但是,我们必须注意,性能是很重要的非功能性需求,必须根据系统的特点 ...

  6. MySQL数据库的优化-运维架构师必会高薪技能,笔者近六年来一线城市工作实战经验

    原文地址:http://liangweilinux.blog.51cto.com/8340258/1728131 首先在此感谢下我的老师年一线实战经验,我当然不能和我的老师平起平坐,得到老师三分之一的 ...

  7. 我的mysql数据库sql优化原则

    原文 我的mysql数据库sql优化原则 一.前提 这里的原则 只是针对mysql数据库,其他的数据库 某些是殊途同归,某些还是存在差异.我总结的也是mysql普遍的规则,对于某些特殊情况得特殊对待. ...

  8. SQL Server 数据库性能优化

    分析比较执行时间计划读取情况 1. 查看执行时间和cpu set statistics time on select * from Bus_DevHistoryData set statistics ...

  9. 数据库SQL优化大总结之 百万级数据库优化方案(转载)

    网上关于SQL优化的教程很多,但是比较杂乱.近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充. 这篇文章我花费了大量的时间查找资料.修改.排版,希望大家阅读之后,感觉 ...

  10. 关于数据库SQL优化

    1.数据库访问优化   要正确的优化SQL,我们需要快速定位能性的瓶颈点,也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢的设备会是瓶颈点,如下载时网络速度可能会是瓶颈点,本地复制文件 ...

随机推荐

  1. Java中的POJO是什么?

    1.介绍 在这个简短的教程中,我们将研究"普通Java对象"(Plain Old Java Object)的定义,简称POJO.我们将看看POJO与JavaBean的比较,以及如何 ...

  2. ORACLE SEQUENCE 详解

    1.    About Sequences(关于序列) 序列是数据库对象一种.多个用户可以通过序列生成连续的数字以此来实现主键字段的自动.唯一增长,并且一个序列可为多列.多表同时使用. 序列消除了串行 ...

  3. Jsp+Servlet实现文件上传下载(三)--删除上传文件

    接着上一篇讲: Jsp+Servlet实现文件上传下载(二)--文件列表展示点击打开链接 本章来实现一下删除已上传文件,同时优化了一下第一章中的代码. 废话少说,上代码 --------------- ...

  4. 【LeetCode排序专题02】最小k个数,关于快速排序的讨论

    最小k个数 https://leetcode.cn/problems/smallest-k-lcci/ 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个 ...

  5. 以解析csv数据为例,讨论string、char[]、stream 不同类型来源是否能进行高性能读取解析封装可能性

    篇幅较长,所以首先列举结果,也就是我们的目的 核心目的为探索特定场景对不同类型数据进行统一抽象,并达到足够高性能,也就是一份代码实现,对不同类型数据依然高性能 以下为结果,也就是我们的目的: 对1w行 ...

  6. 【Azure 应用服务】Java ODBC代码中,启用 Managed Identity 登录 SQL Server 报错 Managed Identity authentication is not available

    问题描述 在App Service中启用Identity后,使用系统自动生成 Identity. 使用如下代码连接数据库 SQL Server: SQLServerDataSource dataSou ...

  7. 【Azure 应用服务】能否通过 Authentication 模块配置 Azure AD 保护 API 应用?

    问题描述 在App Service Authentication 中配置 Azure AD 注册的应用信息后,根据官方文档,可以让前端应用实现用户 AAD 登录,然后通过前端应用获取的Token,来访 ...

  8. 【Azure 事件中心】在Windows系统中使用 kafka-consumer-groups.bat 查看Event Hub中kafka的consumer groups信息

    问题描述 使用 Apache Flink 连接支持 Apache Kafka的Azure Event Hub后,由于消费端的Consumer Group是动态创建,在门户页面和Service Bus ...

  9. 如何扩展Spark Catalyst,抓取spark sql 语句,通过listenerBus发送sql event以及编写自定义的Spark SQL引擎

    1.Spark Catalyst扩展点 Spark catalyst的扩展点在SPARK-18127中被引入,Spark用户可以在SQL处理的各个阶段扩展自定义实现,非常强大高效,是SparkSQL的 ...

  10. 虚拟机安装Mac操作系统

    参考博客https://www.bilibili.com/read/cv25662180/?spm_id_from=333.1007.0.0