文章目录
- 一、查询执行策略
- 1.查询执行策略
- 二、数据定义语句执行
- 1.数据定义语句执行流程
- 2.执行eg
- 3.主要的功能处理器函数
- 三、可优化语句执行
- 1.物理代数与处理模型
- 2.物理操作符的数据结构
- 3.执行器的运行
- 4.执行eg
- 四、计划节点
- 1.控制节点
- 2.扫描节点
- 3.物化节点
- 4.连接节点
- 五、其他子功能介绍
- 1.元组操作TupleTableSlot
- 2.表达式计算
一、查询执行策略
查询执行器的框架如下:
- 查询执行器也是被函数exec_simple_query调用,只是调用的顺序上查询编译器在前,查询执行器在后。
- 总体上, 查询执行器实际就是按照执行计划的安排,有机调用通用存储、索引、并发等模块,按照各种执行计划中各种计划节点的实现算法来完成数据的读取或者修改
- 查询执行器有4个主要的子模块:Portal(PG中很多模块是以此核心数据结构命名)、ProcessUtility、Executor和特定功能子模块部分
- 查询执行器将查询分为两大类别,分别由子模块ProcessUtility和Executor负责执行
(1)查询执行器会首先在Protal模块根据输入执行计划选择相应的处理模块(Portal模块也称为策略选择模块)
(2)Executor输入包含了一个查询计划树(Plan Tree),用于针对于数据表汇总元组的增删改查
(3)ProcessUtility处理游标、表的模块创建、事务相关操作等
(4)执行过程中涉及的表达式计算、投影计算以及元组操作等,在整个查询执行过程中会被重复调用
1.查询执行策略
查询语句处理流程如下:
- SQL语句会被查询编译器转换成2种基本类型的数据结构(执行计划树和非计划树操作),分别在Executor和ProcessUtility中进行
- DL语句(CRUD)由于执行过程相近,所以会被转换成执行计划树,其他语句被规为非计划树类型
- 有些负责sql不能简单地归类为一种基本处理类型,在PG中会将其解析成2种基本类型数据结构的序列(实际是按顺序构成一个链表),并将其顺序执行来完成用于的请求操作
- 从查询编译器输出到执行计划,到执行计划被具体的执行部件处理这一过程,被称作执行测流的选择 - 负责完成执行策略选择的模块成为执行策略选择器:完成对查询编译器输出怇的解析,选择预先设定好的执行流程
可优化语句和数据定义语句
二、数据定义语句执行
1.数据定义语句执行流程
2.执行eg
3.主要的功能处理器函数
三、可优化语句执行
可优化语句的共同特点是他们被查询编译器处理后都会生成查询计划树,这一类语句由执行器Executor处理
- 该模块对外提供了三个接口:ExecutorStart、ExecutorRun和ExecutorEnd,其输入是包含查询计划树的数据结构QueryDesc,输出则是相关执行信息或结果数据
- 若希望执行某个计划树,仅需构造包含此计划树的QueryDesc,并依次调用ExecutorStart、ExecutorRun和ExecutorEnd
执行器对查询计划树的处理流程
1.物理代数与处理模型
数据库的查询逻辑使用逻辑代数(eg:关系代数)来表示;
- PG中的查询计划,对于一个可优化的语句,PG在执行前会给出与之等价的用物理代数表示的查询计划, 然后按照查询计划进行执行。
- 查询计划实例
PG中的物理操作符被定义为有0-2个输入和1个输出,这是为了在实现中能够对应二叉树结构:所有的物理操作符被组织为一个二叉树。每一个物理操作符对应于树中的一个节点,下层节点的输出作为上层节点输入 - PG中每一个物理操作符节点都需要调用的三个函数:ExecInitNode、ExecProcNode、ExecEndNode,其执行流程如下
PG一次一元组的执行模式
- 物化节点:必须首先计算出所有结果,并将其缓存起来,实现上采取执行时每次从缓存中获取一条元组。
- eg:排序节点就属于物化节点
2.物理操作符的数据结构
查询计划树是由各种物理操作符构成(简称为计划节点)
- HashJoin类型节点的数据结构表示
PG中将所有的计划节点按照功能分为4类:控制节点(control node)、扫描节点(scan node)、连接节点(join node)和物化节点(materialization node),并分别定义了公共父类Scan、Join。
- Hash连接属于连接节点,so:Hash连接继承于Join节点
执行器的输入结构体QueryDesc
- 执行器初始化时,ExecutorStart会根据查询计划树构造执行器全局状态estate以及计划节点执行状态planstate
- 在查询计划树的执行过程中,执行器将使用planstate来记录计划节点执行状态和数据,并使用全局状态记录中的ex_tupleTable字段在节点间传递结果元组。
- 执行器的清理函数ExecutorEnd将回收执行器全局状态和计划节点执行状态
计划节点与节点执行状态
- 执行器的输入是QueryDesc,它包含了查询执行计划树根节点指针的PlannedStmt结构
- 执行器执行时,首先构造全局状态记录Estate结构,并为每个计划节点Plan,构造对应的状态节点PlanState;
- 然后再执行中使用相关结构存储执行状态,执行完毕后释放相关的数据结构
3.执行器的运行
PG中提供了三个接口函数用于调用执行器,分别为ExecutorStart、ExecutorRun和ExecutorEnd。
- 当需要使用执行器来处理查询计划时,仅需一次调用三个函数即可完成执行器的整个执行过程
- (1)初始化查询计划树,构造完整的PlanState树
(2)查询计划执行
每一次循环都通过ExecProcNode函数从计划节点状态树中获取一个元组,然后对该元组进行相应的处理(CRUD),然后返回处理的结果;
当ExecProcNode从计划节点状态树中再也娶不到有效的元组时结束循环;- (3)执行器清理
从根节点开始递归调用ExecEndNode对每一个计划节点的执行状态节点(执行状态树就是PlanState)进行清理;
4.执行eg
可优化语句执行的核心内容是对于各种计划节点的处理
- 计划节点分为4类:控制节点、扫描节点、物化节点、连接节点
1.控制节点
control Node
- 是一类用于处理特殊情况的节点,用于实现特殊的执行流程。
- eg:Result节点可用来表示INSERT语句中VALUES子句指定的将要插入的元组
控制节点列表
eg:
Append节点
BitmapAnd/BitmapOr节点
- 位图Bitmap类型的节点,用于位图计算
RecursiveUnion节点
2.扫描节点
ScanNode
- 此类节点用于扫描表等对象以从中获取元组
- SeqScan节点用于顺序扫描一个表,每次扫描一个元组
SeqScan节点
IndexScan节点
BitmapIndexScan节点
BitmapHeapScan
TidScan
- ctid
SubqueryScan节点
FunctionScan节点
valuesScan节点
CteScan节点
workTableScan节点
3.物化节点
Materialization Node
- 能够缓存执行结果到辅助存储中
- 物化节点会在第一次被执行时生成其中的所有结果元组,然后将这些元组缓存起来,等待其上层节点取用;
- 非物化节点则是每次被执行时生成一个结果元组并返回给上层节点
- eg:Sort节点能获取下层节点返回的所有元组并根据指定的属性进行排序,并将排序结果全部缓存起来,每次上层节点从Sort节点取元组时就从缓存中按顺序返回下一个元组
sort节点
group节点
Agg节点
Unique节点
Hash节点
- skew方法
SetOp节点
Limit节点
返回空元组WindowAgg节点
4.连接节点
Join Node
- 对应于关系代数中的连接操作,可以实现多种连接方式(条件连接、左连接、右连接、全连接、自然连接)
- 每种节点实现一种连接算法,eg:HashJoin实现了基于Hash的连接算法
- PG提供的连接节点
PG提供了三种连接操作,嵌套循环连接Nest Loop、归并连接Merge Join和哈希连接Hash Join
(1)归并连接算法可以实现上述6种连接,
(2)嵌套循环连接和Hash连接只能实现Inner Join、Left Outer Join、Semi Join和Anti Join4种连接- 连接节点的公共数据结构
连接节点有公共父类Join,Join继承了Plan的所有属性,并扩展定义了jointype用以存储连接的类型,joinqual用于存储连接的条件。
对应的执行状态节点JoinState中定义了jointype存储连接类型,joinqual存储连接条件初始化后的状态链表。
NestLoop节点
MergeJoin节点
- MergeJoin实现了对排序关系的归并连接算法,归并连接的输入都是已经排序好的
HashJoin节点
1.元组操作TupleTableSlot
PG中使用元组存储所有信息,把偶偶各种系统信息、数据等
- 存储模块提供了很好的元组HeapTuple定义和操作结构,但是该接口是面向物理元组的,结构解析和构造开销较大,不能满足执行器高效处理元组的需求
- 为了能够统计地表示和处理各种形式的元组,执行器定义了数据结构TupleTableSlot结构和相关的处理函数,以便执行过程中按照需要,使用相应形式的元组进行处理,并支持各种形式之间的转换
- 执行器将物理元组存储于TupleTableSlot组成的数组中,该数组称为元组表Tuple Table
(1)在初始过程中,统计所有计划节点的需求,为期分配足够数量的TupleTableSlot,建立Tuple Table,并存储于Estate结构的es_tupleTable字段中;
(2)在初始化每个节点时,节点会根据自身需求申请分配TupleTableSlot结构,用于存储节点的输出元组、扫描到的元组等
TupleTableSlot数据结构
结构体成员解释:
TupleTableData结构体解释
TupleTableSlot处理了以下四种元组:
TupleTableSlot的构造与清理
2.表达式计算