巴拉巴

 找回密码
 立即注册

站内搜索

搜索
热搜: 活动 交友 discuz
查看: 62|回复: 0

PostgreSQL 技术内幕(四)执行引擎之Portal

[复制链接]

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2023-1-2 07:57:15 | 显示全部楼层 |阅读模式
序言:
在Postgre数据库中,执行引擎作为一个连接查询引擎与存储引擎的中间部件,其主要的作用就是根据查询引擎传递的计划进行执行,获取数据。
Portal(门户),相当于执行引擎的入口。当一条SQL在经过查询引擎处理的词法、语法、查询优化、访问路径的创建后,都要经过Portal来决定执行器的路径,并将结果返回给用户,来完成数据的存取工作。
导语:
Portal,也称为策略选择模块,这也代表了Portal最核心的功能。通常,Portal会根据SQL语句的类型,选择不同的执行模块(Processutility、Executor等)。
SQL语句类型包括:可优化语句、数据定义语句。

  • 可优化语句
包括DML(insert/update/select)等语句,这类语句特点是查询满足条件的元组,返回给用户或者元组操作后写入磁盘。之所以称其为可优化语句,是因为这类语句通常会被优化器进行重写与优化,从而加快查询速度。

  • 数据定义语句
主要是功能性语句,例如:DDL(Create、Alter、Drop)、DCL(Grant、COMMIT、ROLLBACK)等。
下图为Portal在整个SQL执行过程中所承担的职责。图中上面SQL为可优化语句,下面为数据定义语句。
1.Portal内核揭秘:
简单来说,Portal负责驱动执行器,是执行器中的一部分。
1.1入口层
如上图所示,Portal通常分为两类:
QD执行会从exec_simple_query进入;
QE执行从exec_mpp_query进入;
然后统一由 portal 来根据语句类型进行决策,调用不同的执行器结构。
•ProcessUtilitySlow(事件触发类语句)
•ExecutorStart
初始化Estate、QueryDesc,调用InitPlan
•ExecutorRun
执行各个节点获取数据
•ExecutorFinish
执行ModifyTable节点
1.2 Portal层
首先初识Portal内部数据结构:
通过上面的整体结构图可以看出,Portal在执行引擎中起到了承上启下的作用:向上,它存储了优化器的相关信息;向下,它存储了执行引擎相关的一些结构。同时,Portal自身也存储了一些比较基础的结构,以及对应游标的结构。
•作为Portal的核心功能,Portal策略通常有五类:
1.PORTAL_ONE_SELECT
只包含一个SELECT查询。
SQL
select * from t1;
2.PORTAL_ONE_RETURNING
包含一个INSERT/UPDATE/DELETE查询,且带RETURNING条件。
SQL
INSERT INTO ret_tbl (id) VALUES (3) RETURNING id INTO tableId;
3.PORTAL_ONE_MOD_WITH
包含一个SELECT查询并且有修改的CTE。
SQL
WITH ins AS (
INSERT INTO t1 (t1_id) VALUES(1) RETURNING t1_id
)
SELECT * from ins;
需要注意,例如下面这个查询:
SQL
WITH ins AS (
SELECT * from t1
) INSERT INTO t2
(t2_id, col2)
SELECT * from ins;
这个并不是PORTAL_ONE_MOD_WITH查询,而是PORTAL_MULTI_QUERY。
4.PORTAL_UTIL_SELECT
包含一个utility语句,且该语句执行会返回像SELECT那样有输出结果。
SQL
postgres=# explain select * from t1;
QUERY PLAN

Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..431.00 rows=1 width=12)
-> Seq Scan on t1 (cost=0.00..431.00 rows=1 width=12)
Optimizer: Pivotal Optimizer (GPORCA)
(3 rows)
postgres=# EXECUTE t1_fn_ret(2, 'helloworld');
t1_id | col1
-------+
2 | helloworld
(1 row)
INSERT 0 1
5.其他情况
例如:
PORTAL_MULTI_QUERY + PORTAL_MULTI_QUERY
SQL
PREPARE t1_fn (int, text) AS INSERT INTO t1 VALUES($1, $2);
•状态
○PORTAL_NEW
○PORTAL_defineD
○PORTAL_READY
○PORTAL_QUEUE
○PORTAL_ACTIVE
○PORTAL_DONE
○PORTAL_FAILED
这几个状态会在下面依次引入。
1.3 CreatePortal
创建一个新的Portal,传入参数均为: CreatePortal("", true, true),表示创建一个匿名的Portal,允许重复且重复后保持沉默。
CreatePortal逻辑:
Plain Text
Portal
CreatePortal(const char *name, bool allowDup, bool dupSilent)
1.根据传入的第一个参数name从哈希表中查找。
2.根据传入的第二个参数allowDup,如果第一步查找到,从哈希表中决定是否删除。如果true,则删除,否则报错。在哈希表中查找到Portal且允许重复的情况下,在QD节点上会根据第三个参数dupSilent决定是否输出告警信息。
3.创建一个新的Portal,并初始化相应参数。
执行完毕后,便创建好了一个状态为PORTAL_NEW的Portal。
1.4 PortalDefineQuery
定义Portal数据,包含了:查询语句sourceText、PlannedStmts、查询完成标记qc。
注意:QD上根据传递进来的stmt来设置nodeTag,但是QE上为T_Query,因为QE上不是parsed statement,所以不是 T_SelectStmt。
最终设置Portal状态为PORTAL_DEFINED。
1.5 PortalStart
准备好portal,主要有如下几步:
1.设置ddesc,该信息为QD到QE上的额外信息,QD上为NULL,QE上不为NULL。
2.设置全局参数,例如:当前活跃的Portal、resourceOwner、context。
3.设置Portal参数字段:PortalParams,同样QD上为NULL,QE上不为NULL。
4.设置Portal策略(ChoosePortalStrategy)。
如下图所示:输入为查询计划链表,针对以下情况:

  • PORTAL_ONE_SELECT
  • PORTAL_ONE_MOD_WITH
  • PORTAL_UTIL_SELECT
  • PORTAL_ONE_RETURNING
首先判断是Query还是PlannedStmt,一般情况下的查询语句基本都是PlannedStmt。
对于像PREPARE st(int) as select * from t1之类utility语句,第一次调用ChoosePortalStrategy,返回PORTAL_MULTI_QUERY(命中PlannedStmt),第二次调用返回PORTAL_ONE_SELECT(命中Query)。
根据Portal策略初始化Portal,最重要的是初始化tupDesc与Cursor postion。
例如:"QUERY PLAN"、"t1_id、col1"就是tupDesc。
INSERT 0 1
•不同tupleDesc函数区别
○ExecTypeFromTL
▪with resjunk column
○ExecCleanTypeFromTL
▪skip resjunk column
1.在执行Portal过程中发生异常,设置Portal的状态为PORTAL_FAILED;否则,下一步。
2.设置Portal状态为PORTAL_READY。
1.6 PortalRun
根据SQL的语句类型选择不同的执行路径,获取元组数据,完成Portal工作,运行完之后执行完毕,或者进行下一轮(READY,而非ACTIVE)。
Portal策略执行路径如下:
•PORTAL_ONE_SELECT
○set result = Portal->atEnd
•PORTAL_ONE_RETURNING|PORTAL_ONE_MOD_WITH|PORTAL_UTIL_SELECT
○填充holdStore(见下方)
○调用PortalRunSelect返回n行数据
▪获取时数据方向包含前进/后退
▪可以从holdStore中获取,也可以从ExectorRun中获取
○设置状态为PORTAL_READY
○设置是否完成运行标记为Portal->atEnd
•PORTAL_MULTI_QUERY
○调用PortalRunMulti
○设置状态为PORTAL_Done
○设置是否完成运行标记为true
此外,上述图中填充holdStore逻辑如下:
•调用PortalCreateHoldStore,填充portal->holdStore,然后通过工厂函数CreateDestReceiver构造DestReceiver(子类:TStoreState);
•根据Portal策略执行查询:
PORTAL_ONE_RETURNING
PORTAL_ONE_MOD_WITH
这两个策略调用PortalRunMulti
PORTAL_UTIL_SELECT调用PortalRunUtility。
○PORTAL_ONE_RETURNING
○PORTAL_ONE_MOD_WITH
▪PortalRunMulti
•utilityStmt
○PortalRunUtility
•not utilityStmt
○ProcessQuery
○PORTAL_UTIL_SELECT
▪PortalRunUtility
2.游标Cursor
2.1 打开游标
如果不想一次执行整个命令,可以设置一个封装该命令的游标(Cursor), 然后每次读取几行命令结果。
SQL
name [ [ NO ] SCROLL ] CURSOR [ ( arguments ) ] FOR query;
例如:
SQL
DECLARE liahona SCROLL CURSOR FOR SELECT * FROM t1;
该命令运行机制为:
首先识别到是一个数据定义语句,便会调用ProcessUtility,随后解析从PlannedStmt中的utilityStmt识别出是一个T_DeclareCursorStmt节点,调用PerformCursorOpen执行Declare cursor命令。
PerformCursorOpen处理逻辑如下:
•query重写
•优化器优化,生成PlannedStmt
•创建Portal(名字为游标名),仅调用PortalStart
2.2 关闭游标
关闭游标,实际就是关闭Portal,调用PerformPortalClose。
如下两个操作:
SQL
CLOSE cursor_name;
CLOSE ALL;
如果传入的名字为空,则是CLOSE ALL关闭所有非活跃Portal,否则,只关闭指定的Portal(Cursor)。
2.3 FETCH or MOVE
FETCH与MOVE语法分别如下:
SQL
FETCH [ direction { FROM | IN } ] cursor INTO target;
MOVE [ direction { FROM | IN } ] cursor;
FETCH从游标中检索n行到目标中, 目标可以是一个行变量、记录变量、逗号分隔的普通变量列表, 就像SELECT INTO一样, 如果没有获取到数据,目标会设为NULL。
MOVE重新定位一个游标,而不需要检索任何数据,例如:一旦游标位置确定,则可以删除或更新行。
SQL
MOVE cursor_variable;
UPDATE table_name
SET column = value, ...
WHERE CURRENT OF cursor_variable;
从实现层面两者都会进入到PerformPortalFetch,都被解析为FetchStmt,内部有个成员ismove决定是MOVE还是FETCH。
不管是哪个,都会指定Cursor的名字,有了这个名字,便知道了Portal,随后调用PortalRunFetch来获取结果。
PortalRunFetch内部会像PortalRun运行一样,首先设置Portal状态为Active,随后根据策略选择不同的调用链。
•PORTAL_ONE_SELECT
○调用DoPortalRunFetch
•PORTAL_ONE_RETURNING|PORTAL_ONE_MOD_WITH|PORTAL_UTIL_SELECT
○首先判断portal内部是否有holdStore,如果没有会调用FillPortalStore,随后调用DoPortalRunFetch。
DoPortalRunFetch内部实现,会考虑传入的direction,决定是前向还是后向等不同方向的扫描,最后调用PortalRunSelect获取数据。注意:gpdb不支持backward scan,但是pg支持。
3.Portal内存管理
限制每个用户最大打开的Portal数量为16。
Plain Text
#define PORTALS_PER_USER 16
Portal内部封装了三个宏,分别是:

  • PortalHashTableLookup
  • PortalHashTableInsert
  • PortalHashTableDelete
下图左侧是这三个宏的功能,右边是对外核心接口。
结语:
Portal作为执行引擎最基础的部分,其核心功能包括策略选择、启动执行器、设置游标。根据不同的SQL语句类型,Portal会选择不同的执行路径完成数据的存取工作。

来源:http://www.yidianzixun.com/article/0lLBFElx
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 返回顶部