Postgresql逻辑优化学习

news2024/11/25 22:47:59

张树杰优化器原理学习

0 用例

drop table student;
create table student(sno int primary key, sname varchar(10), ssex int);
insert into student values(1, 'stu1', 0);
insert into student values(2, 'stu2', 1);
insert into student values(3, 'stu3', 1);
insert into student values(4, 'stu4', 0);

drop table course;
create table course(cno int primary key, cname varchar(10), tno int);
insert into course values(10, 'meth', 1);
insert into course values(11, 'english', 2);

drop table teacher;
create table teacher(tno int primary key, tname varchar(10), tsex int);
insert into teacher values(1, 'te1', 1);
insert into teacher values(2, 'te2', 0);

drop table score;
create table score (sno int, cno int, degree int);
insert into score values (1, 10, 100);
insert into score values (1, 11, 89);
insert into score values (2, 10, 99);
insert into score values (2, 11, 90);
insert into score values (3, 10, 87);
insert into score values (3, 11, 20);
insert into score values (4, 10, 60);
insert into score values (4, 11, 70);

SELECT st.sname, c.cname, sc.degree
FROM STUDENT st ,COURSE c
INNER JOIN SCORE sc
ON c.cno = sc.cno
WHERE st.sno = sc.sno;

1 优化器基础

SQL是描述性语言,对于执行过程没有要求。所以SQL的执行过程是可以充分发挥想象力的:

  1. 规则优化、逻辑优化:把SQL对应到逻辑代数的公式,应用一些逻辑代数的等价规则做转换。例如选择下推,子查询提升、外连接消除,都是基于规则的优化,大部分有理论证明优化后的效果更好或至少不会更差,也有一些经验规则。
  2. 物理优化:主要是两方面,一个是连接顺序的选择,一个是连接方式的选择。也就是在众多可能得连接路径上,选择一个最优的。
    • 例如客户写出了join a join b join c(a 1MB,b 10GB,c 100GB),那么先连接ab比较好还是bc比较好?显然内连接先连小的比较好,因为结果集会不会超过小表,可以降低后续的连接数量;那么如果join a join b join c where c = 1(a 1MB,b 10GB,c 100GB(c过滤后就剩1kB)),显然应该先执行过滤,过滤后c就变成小表了,应该优先连接c,不但不影响语义,而且会显著降低连接数量。
    • 例如join a join b如果ab表的数据都是有序的,应该选择merge join,如果a表比b表小很多,且b表的连接建选择性非常好,那么使用nestloop会得到性能非常好的执行计划。

2 优化器的输入:查询树

优化器的输入是语义分析的输出:查询树

  • 语义分析会严格按照SQL的编写来对应,不会调整任何执行路径。
  • 语义分析会检查对象是否存在,并顺便将对象赋予数据库的一些含义,例如将表名对象赋予表的OID等等。

在这里插入图片描述

3 逻辑优化

在这里插入图片描述

3.1 子查询&子连接提升

Postgresql中通过子句所处的位置来区分子连接和子查询,出现在FROM关键字后的子句是子查询语句,出现在WHERE/ON等约束条件中或投影中的子句是子连接语句:

Postgresql子查询

postgres=# explain SELECT * FROM STUDENT, (SELECT * FROM SCORE) as sc;  
                               QUERY PLAN                               
------------------------------------------------------------------------
 Nested Loop  (cost=0.00..28104.15 rows=2244000 width=58)
   ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=12)
   ->  Materialize  (cost=0.00..26.50 rows=1100 width=46)
         ->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=46)

Postgresql子连接

postgres=# explain SELECT (SELECT AVG(degree) FROM SCORE), sname FROM STUDENT;  
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Seq Scan on student  (cost=35.51..56.51 rows=1100 width=70)
   InitPlan 1 (returns $0)
     ->  Aggregate  (cost=35.50..35.51 rows=1 width=32)
           ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=4)

postgres=# explain SELECT * FROM STUDENT WHERE EXISTS (SELECT * FROM SCORE WHERE SCORE.sno = STUDENT.sno); 
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Hash Join  (cost=40.00..70.01 rows=550 width=46)
   Hash Cond: (student.sno = score.sno)
   ->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=46)
   ->  Hash  (cost=37.50..37.50 rows=200 width=4)
         ->  HashAggregate  (cost=35.50..37.50 rows=200 width=4)
               Group Key: score.sno
               ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=4)

按相关性可以分为相关子连接和非相关子连接:
在这里插入图片描述

例如:sno实际上产生了一个天然的相关性,这个天然的相关性就会产生嵌套循环,因此是需要提升的

postgres=# explain SELECT * FROM STUDENT WHERE sno > ANY (SELECT sno from STUDENT); 
                                            QUERY PLAN                                             
---------------------------------------------------------------------------------------------------
 Nested Loop Semi Join  (cost=0.15..208.42 rows=367 width=46)
   ->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=46)
   ->  Index Only Scan using student_pkey on student student_1  (cost=0.15..6.62 rows=367 width=4)
         Index Cond: (sno < student.sno)

子连接是否提升取决于相关性,而这个相关性不只是体现在子句里,也体现在表达式里,也就是说只要能产生嵌套循环,那就有提升的必要。

下面的例子中ANY子查是无法提升的,因为里面的cno和外面的ssex没有相关性,所以会产生subplan。

postgres=# explain SELECT * FROM student WHERE ssex < ANY (SELECT cno FROM score WHERE student.sno = student.sno);  
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Seq Scan on student  (cost=0.00..19551.50 rows=550 width=46)
   Filter: (SubPlan 1)
   SubPlan 1
     ->  Result  (cost=0.00..30.40 rows=2040 width=4)
           One-Time Filter: (student.sno = student.sno)
           ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=4)

3.1.1 子连接提升源码分析

explain SELECT sname FROM STUDENT WHERE sno > ANY (SELECT sno FROM SCORE);
                             QUERY PLAN                              
---------------------------------------------------------------------
 Nested Loop Semi Join  (cost=0.00..22497.30 rows=367 width=38)
   Join Filter: (student.sno > score.sno)
   ->  Seq Scan on student  (cost=0.00..21.00 rows=1100 width=42)
   ->  Materialize  (cost=0.00..40.60 rows=2040 width=4)
         ->  Seq Scan on score  (cost=0.00..30.40 rows=2040 width=4)

pull_up_sublinks函数位置

exec_simple_query
  pg_plan_queries
    pg_plan_query                  postgres.c
      planner                      planner.c
        standard_planner           planner.c
          	subquery_planner       planner.c
          	  pull_up_sublinks     prepjointree.c   

GDB挂到函数上,先打印下当前的查询树
在这里插入图片描述
执行p elog_node_display(LOG, "parse tree", root->parse, true)

从日志中查看查询树,可以看到from的第二个子表是sublink。
在这里插入图片描述

注意pull_up_sublinks_jointree_recurse函数需要的入参只有join tree就够了,从上图中可以看到根节点中的jointree。

void
pull_up_sublinks(PlannerInfo *root)
{
	Node	   *jtnode;
	Relids		relids;

	/* Begin recursion through the jointree */
	jtnode = pull_up_sublinks_jointree_recurse(root,
											   (Node *) root->parse->jointree,
											   &relids);

	/*
	 * root->parse->jointree must always be a FromExpr, so insert a dummy one
	 * if we got a bare RangeTblRef or JoinExpr out of the recursion.
	 */
	if (IsA(jtnode, FromExpr))
		root->parse->jointree = (FromExpr *) jtnode;
	else
		root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
}

pull_up_sublinks_jointree_recurse会对join树进行递归分析,内部关键流程:convert_ANY_sublink_to_join

3.2 谓词下推&等价类推理

下推是为了尽早地过滤数据,这样就能在上层结点降低计算量。

选择 (σ)
投影 (π)
自然连接 (⋈)
笛卡尔积 (x)
逻辑算子:∧(与)、∨ (或)、 ¬(非)

例如下面关系式:

Πcname,tname (σTEACHER.tno=5∧TEACHER.tno=COURSE.tno (TEACHER×COURSE))

翻译成SQL:
select cname,tname from teacher, course where teacher.tno=5 and teacher.tno=course.tno;

第一次优化:下推选择

Πcname,tname (
  TEACHER.tno=COURSE.tno (
    σTEACHER.tno=5(TEACHER)×COURSE
  )
)

第二次优化:下推投影

Πcname,tname (
  σTEACHER.tno=COURSE.tno 
    (Πtname,tno(σTEACHER.tno=5(TEACHER)) × Πcname,tno(COURSE)
  )
)

翻译成SQL

-- 下推前
SELECT cname,tname FROM 
  TEACHER t, COURSE c 
WHERE t.tno = 1 AND t.tno = c.tno;
 
-- 下推后
SELECT cname,tname FROM 
  (SELECT tname,tno FROM TEACHER WHERE tno = 1) tt, 
  (SELECT cname,tno FROM COURSE) cc 
WHERE tt.tno = cc.tno;

在PG中已经做过了优化,回得到相同的执行计划:
在这里插入图片描述
注意这里的course并没有选择条件,但seq scan course的计划中存在tno=1,这就是等价推理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/471850.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPSS岭回归报错问题 第 8 列中的 错误号 34+乱码问题

1首先第一个问题&#xff0c;先找到Ridge Regression.sps文件 注意各国语言都有这个文件&#xff0c;选择English下的 得到位置&#xff0c;一般是安装路径\Samples\English\Ridge Regression.sps 仍然报错&#xff0c;将第二行变成大写&#xff1a;RIDGEREG ENTER&#xff0…

笔记本电脑没有声音了怎么恢复

笔记本电脑 在使用的过程中&#xff0c;突然没有声音的话&#xff0c;对于人们来说会很麻烦。那么笔记本电脑没有声音了怎么恢复呢?下面小编为大家整理了笔记本电脑没有声音的恢复方法&#xff0c;一起来看看吧。 方法/步骤&#xff1a; 方法一&#xff1a;网络适配器检查音频…

物联网工程有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是一些物联网工程领域的SCI期刊推荐&#xff1a; IEEE Internet of Things Journal&#xff1a; 该期刊由IEEE出版&#xff0c;致力于物联网技术领域的研究&#xff0c;包括物联网的基础理论、通信、算法、应用、系统等方面。 Sensors&#xff1a; 该期刊由MDPI出版&…

基于el-input的数字范围输入框

数字范围组件 在做筛选时可能会出现数字范围的筛选&#xff0c;例如&#xff1a;价格、面积&#xff0c;但是elementUI本身没有自带的数字范围组件&#xff0c;于是进行了简单的封装&#xff0c;不足可自行进行优化 满足功能&#xff1a; 最小值与最大值的相关约束&#xff0…

C++默认成员函数 日期类运算符重载

赋值重载 赋值重载&#xff0c;首先我们先说一个运算符重载&#xff0c;什么是运算符重载呢&#xff1f; 当我们有一个日期类的话&#xff0c;我们想要对&#xff0c; 一个日期类进行比较&#xff0c;那么我们怎么比较呢&#xff1f; 我们是不是先得比较年的大小&#xff0c;…

day6 socket套接字及TCP的实现框架

socket套接字 Berkeley UNIX 操作系统定义了一种API它又称为套接字接口&#xff08;socket interface); socket作用&#xff1a; socket常见API介绍 /*创建套接字*/ int socket(int domain, int type, int protocol); /*绑定通信结构体*/ int bind(int sockfd, const, struc…

【数据库】MVCC原理详解

文章目录 前言1. 相关数据库知识点回顾1.1 什么是数据库事务&#xff0c;为什么要有事务1.2 事务包括哪几个特性&#xff1f;1.3 事务并发存在的问题1.3.1 脏读1.3.2 不可重复读1.3.3 幻读 1.4 四大隔离级别1.4.1 读未提交1.4.2 读已提交1.4 3 可重复读1.4.4 串行化1.4.5 四大隔…

chatgpt模拟机器人软件开发

ChatGPT的参数取决于具体的模型和实现方式&#xff0c;但以下是一些常见的ChatGPT参数&#xff1a; 模型深度&#xff1a;指模型中神经网络的层数。通常情况下&#xff0c;层数越多&#xff0c;模型的表达能力也就越强。 隐藏单元大小&#xff1a;指在模型中每个隐藏层…

局域网 - CSMA/CD(载波侦听多路访问 / 冲突检测)

文章目录 1 概述1.1 局域网的拓扑结构 2 CSMA/CD2.1 三种监听算法2.2 冲突检测原理2.3 二进制指数后退算法 3 扩展3.1 网工软考真题 1 概述 1.1 局域网的拓扑结构 2 CSMA/CD CSMA/CD&#xff1a;Carrier Sense Multiple Access/ Collision Detection&#xff0c;载波侦听多路…

从功能测试转型测试开发,薪资涨了20K,1000字讲述转型必经之路...

身处职场之中&#xff0c;犹如逆水行舟不进则退&#xff0c;想要不被后浪拍死在沙滩上&#xff0c;就要不断学习新知识&#xff0c;接受新事物。 要得到更好的发展&#xff0c;就要紧跟发展趋势&#xff0c;不断转型才能保持竞争力&#xff0c;在职场中占有一席之地。 转型不…

如何理解自动化测试数据驱动与关键字驱动的区别?

一、关键字驱动KDT(Keyword-driven testing) 1、自动化测试框架发展的第三个阶段是关键字驱动测试框架阶段&#xff0c;它是当前比较流行的一种框架之一&#xff0c;并且现在的自动化测试工具已经将关键字驱动框架融入到工具中。在录制过程中自动化测试工具会将对象及操作属性保…

如何提高倾斜摄影超大场景的三维模型轻量化处理速度和效率?

如何提高倾斜摄影超大场景的三维模型轻量化处理速度和效率&#xff1f; 倾斜摄影超大场景的三维模型轻量化处理是将高精度的三维模型进行降采样、简化等处理&#xff0c;以达到减少数据大小和提高渲染性能的目的。为了提高轻量化处理速度&#xff0c;可以从以下方面入手&#x…

【Java 】Java 类加载和类加载器

文章目录 前言一、加载二、链接验证准备解析 三、初始化发生的时机不会触发类的初始化 四、类加载器双亲委派模式 前言 Java 的类加载阶段分为&#xff1a;加载、链接、初始化&#xff0c;而链接的过程中包括&#xff1a;验证、准备、解析。 一、加载 将类的字节码载入方法区…

vue3新拟态组件库开发流程——table组件源码

基础表格 首先开发table组件之前&#xff0c;先想好要用什么样式的api&#xff0c;因为笔者在生产工作中用的都是element&#xff0c;所以前面几个组件风格和element类似&#xff0c;但是这次不打算用element的风格了&#xff0c;打算换一种&#xff0c;直接展示&#xff1a; …

LinkedHashMap顺序迭代原理与LRU算法实现

一、LinkedHashMap与HashMap的结构区别 HashMap LinkedHashMap 结构区别&#xff1a;LinkedHashMap的元素Entry中多两个用于维护双向链表的指针before、after&#xff0c;并且在LinkedHashMap中有两个head、tail指针用于记录双向链表的头结点和尾结点。 二、LinkedHashMa…

2.3 定点乘法运算

学习目标&#xff1a; 如果我要学习定点乘法运算&#xff0c;我会按照以下步骤进行学习&#xff1a; 确定学习目标&#xff1a;明确学习定点乘法运算的目的和重点&#xff0c;以便有针对性地进行学习。 掌握基础知识&#xff1a;首先需要了解定点数和定点乘法的基础知识&…

【halcon】半透明和棋盘格(未完成)

背景 想实现一个这样的效果&#xff1a; 但是发现设置HSmartWindowControlWPF 的Background 根本就没有反应。 探索过程 于是就换个思路&#xff0c;把棋盘格画到Border里面。 <Border Grid.Row"1" Grid.ColumnSpan"2" Panel.ZIndex"0" >…

MySQL:数据库的基本操作

MySQL是一个客户端服务器结构的程序, 一.关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 主流的关系型数据库包括 Oracle、MySQL、SQL Server、Microsoft Access、DB2 等. …

mitmproxy抓包

0.mitmproxy功能简介 实时拦截、修改 HTTP/HTTPS 请求和响应可保存完整的 http 会话&#xff0c;方便后续分析和重放支持反向代理模式将流量转发到指定服务器支持 macOS 和 Linux上的透明代理模式支持用 Python 脚本对 HTTP 通信进行修改 1. 安装mitmproxy pip3 install mit…

wow.js scrollReveal.js 动画库 使用详解以及优劣

wow.js 1.简介 有的页面在向下滚动的时候&#xff0c;有些元素会产生细小的动画效果。比如需要做到滚动条滑到某个位置时&#xff0c;才能显示动画。wow.js 依赖 animate.css&#xff0c;所以它支持 animate.css 多达 60 多种的动画效果&#xff0c;能满足您的各种需求。 IE6、…