数据库内核分析之GPDB and PostgreSQL Portal

网站建设3年前发布
64 0 0

Portal(门户),也称为策略选择模块,根据sql语句类型选择不同的执行模块(ProcessUtility、Executor)。,SQL语句类型包括:可优化语句、数据定义语句。,可优化语句包括DML,像insert/update/select等语句,这类语句特点是查询满足条件的元组返回给用户或者元组操作后写入磁盘,之所以称之为可优化语句是因为这类语句通常会被优化器进行重写与优化,从而加快查询速度。,数据定义语句主要是功能性语句,例如:DDL(Create、Alter、Drop)、DCL(Grant、COMMIT、ROLLBACK)等。,202303061355359238ef226e77233a0da314d902c117817ac6b9546,QD执行会从exec_simple_query进入,QE执行从exec_mpp_query进入。,1.2.1 初识Portal,首先初识Portal内部数据结构:,20230306141435d2df70453d5ad1e4c1b9698e2e9a62e39c788c934,策略只包含一个SELECT查询。,包含一个INSERT/UPDATE/DELETE查询,且带RETURNING条件。,包含一个SELECT查询并且有修改的CTE。,例如:下面这个就不是PORTAL_ONE_MOD_WITH,而是PORTAL_MULTI_QUERY。,包含一个utility语句,且该语句执行会返回像SELECT那样有输出结果。,其他情况,例如:PORTAL_MULTI_QUERY + PORTAL_MULTI_QUERY,状态,这几个状态会在下面依次引入。,1.2.2 CreatePortal,创建一个新的Portal,传入参数均为: CreatePortal("", true, true),表示创建一个匿名的Portal,允许重复且重复后保持沉默。,CreatePortal逻辑:,执行完毕后,便创建好了一个状态为PORTAL_NEW的Portal。,1.2.3 PortalDefineQuery,定义portal数据,包含了:查询语句sourceText、PlannedStmts、查询完成标记qc。,注意:QD上根据传递进来的stmt来设置nodeTag,但是QE上为T_Query,因为QE上不是parsed statement,所以不是 T_SelectStmt。,最终设置Portal状态为PORTAL_DEFINED。,1.2.4 PortalStart,准备好portal,主要有如下几步:,如下图所示:输入为查询计划链表,针对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)。,20230306135416916920e990636952afa0983151fab958f52c25610,choose,5. 根据portal策略初始化portal,最重要的是初始化tupDesc与cursor postion。,20230306135416e765b0f2318677fff244063f1e53023522b4de871,例如:"QUERY PLAN"、"t1_id、col1"就是tupDesc。,不同tupleDesc函数区别,skip resjunk column,with resjunk column,6. 在执行Portal过程中发生异常,设置portal的状态为PORTAL_FAILED;否则,下一步。,7. 设置Portal状态为PORTAL_READY。,根据sql的语句类型选择不同的执行路径,获取元组数据,完成portal工作,运行完之后要么Done要么下一轮(READY,而非ACTIVE)。,portal策略执行路径如下:,set result = portal->atEnd,获取时数据方向包含前进/后退,可以从holdStore中获取,也可以从ExectorRun中获取,填充holdStore(见下方),调用PortalRunSelect返回n行数据,设置状态为PORTAL_READY,设置是否完成运行标记为portal->atEnd,调用PortalRunMulti,设置状态为PORTAL_Done,设置是否完成运行标记为true,2023030613553684d754176626ff0ed24058da01fb5e0bbba377130,此外,上述图中填充holdStore逻辑如下:,PortalRunUtility,PortalRunMulti,ProcessQuery,PortalRunUtility,utilityStmt,not utilityStmt,PORTAL_ONE_RETURNING、PORTAL_ONE_MOD_WITH,PORTAL_UTIL_SELECT,20230306135417b352fdc779d4fe5dd86452eba68f15bc276578220,如果不想一次执行整个命令,可以设置一个封装该命令的游标(cursor), 然后每次读取几行命令结果。,例如:,该命令运行机制为:首先识别到是一个数据定义语句,便会调用ProcessUtility,随后解析从PlannedStmt中的utilityStmt识别出是一个T_DeclareCursorStmt节点,调用PerformCursorOpen执行Declare cursor命令。,PerformCursorOpen处理逻辑如下:,关闭游标,实际就是关闭Portal,调用PerformPortalClose。,如下两个操作:,如果传入的名字为空,则是CLOSE ALL关闭所有非活跃portal,否则,只关闭指定的portal(cursor)。,FETCH与MOVE语法分别如下:,FETCH从游标中检索n行到目标中, 目标可以是一个行变量、记录变量、逗号分隔的普通变量列表, 就像SELECT INTO一样, 如果没有获取到数据,目标会设为NULL。,MOVE重新定位一个游标,而不需要检索任何数据,例如:一旦游标位置确定,则可以删除或更新行。,从实现层面两者都会进入到PerformPortalFetch,都被解析为FetchStmt,内部有个成员ismove决定是MOVE还是FETCH。,不管是哪个,都会指定cursor名,有了这个名字,便知道了portal,随后调用PortalRunFetch来获取结果。,PortalRunFetch内部会像PortalRun运行一样,首先设置portal状态为Active,随后根据策略选择不同的调用链。,调用DoPortalRunFetch,首先判断portal内部是否有holdStore,如果没有会调用FillPortalStore,随后调用DoPortalRunFetch。,DoPortalRunFetch内部实现,会考虑传入的direction,决定是前向还是后向等不同方向的扫描,最后调用PortalRunSelect获取数据,注意:gpdb不支持backward scan,但是pg支持。,
,2023030613541729743c3565e6a33407b4672c9bc60e03228578350,

© 版权声明

相关文章