openGauss - 内核原理 - BatchStore和Batchsortstate为什么仅ForwardScanDirection取数据
openGauss的普通执行引起从Tuplestorestate(物化)和Tuplesortstate(排序)取数据时,会有方向,即ForwardScanDirection:从前向后依次取;BackwardScanDirection:从后向前依次取。但是,在向量化执行引擎中却仅支持ForwardScanDirection。难道向量化执行引擎不支持向后取batch,还是有bug?
1、扫描方向
扫描方向支持以下三种:
typedef enum ScanDirection {
BackwardScanDirection = -1,//从后向前
NoMovementScanDirection = 0,//不执行扫描操作
ForwardScanDirection = 1//从前向后
} ScanDirection;
standard_ExecutorRun函数中:当然这里仅展示普通查询的函数
2、执行器三步曲
查询执行器执行一个SQL时会以一个Portal作为输出数据,存放了与执行该SQL语句相关的所有信息,包括查询树、计划树、执行状态等。作为执行器的门户,所有的SQL语句执行都从一个选择好执行策略的Portal开始,经历Portal Start、PortalRun、PortalDrop三个过程。
PortalStart遍历整个计划树,挖出Portal的初始化。算子的初始化函数命名为“ExecInit+算子名”。初始化函数会先根据对应的Plan结构初始化一个对应的PlanState结构。整个结构是执行过程中的核心数据结构,包含了执行过程中需要的一些数据存储空间和执行信息:
1)调用ChoosePortalStrategy选择执行策略
2)PORTAL_ONE_SELECT:创建查询描述符,还需要ExecutorStart调用ExecInitXXX初始化算子。节点是CMD_SELECT类型操作,utilityStmt字段和intoClause字段为空
3)PORTAL_ONE_RETURNING、PORTAL_ONE_MOD_WITH、PORTAL_UTIL_SELECT创建返回元组的描述符。需要将执行后的结果缓存,然后将缓存结果按照要求返回。其中PORTAL_UTIL_SELECT策略:节点是CMD_UTILITY类型操作,utilityStmt字段保持的是FETCH语句(游标使用)、EXECUTE语句、EXPLAIN语句或者SHOW;PORTAL_ONE_RETURNING:适用于stmts链表中只有一个包含RETURNING子句的原子操作;PORTAL_ONE_MOD_WITH:包含一个SELECT查询,有一个data-modifying CTEs;其他场景使用PORTAL_MULTI_QUERY
4)查询描述符的创建,包括planstate
5)最后将Portal状态设置为PORTAL_READY,表示已初始化好,准备执行
PortalRun执行Portal,根据选择的策略调用相关部件进行执行。执行相关DML查询,对数据进行计算和处理。算子分为两类:行执行算子和向量化执行算子。行执行器执行入口ExecutorRun,向量化执行引擎执行入口是ExecuteVectorizedPlan。向量化算子执行函数命名为“ExecVec+算子名”。
PortalDrop清理Portal,对Portal相关资源进行释放。各个算子的清理函数命名规则“ExecEnd+算子名”或“ExecEndVec+算子名”
3、向量化执行引擎的执行
排序Batchsortstate或者物化BatchStore进行取数据时,比如排序后从排序缓存取数据时,仅当forward为true时才拿数据:
但是,我们在前文可以看到对于standard_ExecutorRun执行时,对于forward向前或者向后都会进入执行。那么就需要继续分析,哪些场景支持哪些扫描方向。
3、扫描方向的确定
pg_plan_queries函数中生成执行计划,可以看到分为两个分支:CMD_UTILITY和pg_pan_query。
向量化执行计划的转换仅在pg_plan_query函数中进行。CMD_UTILITY分支是不会转换向量化执行计划的。CMD_UTILITY分支比如从游标中获取数据,就分为向前或向后的方向执行;而其他条件,则总是向前扫描的方向。
向量化执行的方向来自ExecutorRun的入参:
CMD_UTILITY分支是哪种场景?
从选择策略上看,仅PORTAL_UTIL_SELECT或者PORTAL_MULTI_QUERY分支。
PORTAL_MULTI_QUERY:
PortalRun->PortalRunMulti->ProcessQuery->
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
PORTAL_UTIL_SELECT:
PortalRunUtility->ProcessUtility->standard_ProcessUtility:比如T_FetchStmt
PerformPortalFetch:cursor的操作
|-- ....
|-- |-- PortalRunSelect->ExecutorRun:有扫描方向,向前或向后
由于没有转换成向量化执行计划,所以走行执行引擎执行。行执行引擎从Tuplestorestate(物化)和Tuplesortstate(排序)取数据时有各个方向的分支处理流程。
向量化执行引擎执行时,ExecutorRun的方向一定是ForwardScanDirection, 所以BatchStore和Batchsortstate仅实现ForwardScanDirection取数据是正确的!