postgresql源码(十)——Executor(Scan节点(下))

本文详细解析了PostgreSQL中各种Scan节点的功能与实现原理,包括SubqueryScan、FunctionScan、ValuesScan、CteScan等,深入探讨了这些节点的数据结构、初始化过程、执行流程及清理操作。

剩下的七个Scan节点

    T_SubqueryScanState,
    T_FunctionScanState,
    T_ValuesScanState,
    T_CteScanState,
    T_WorkTableScanState,
    T_ForeignScanState,
    T_CustomScanState,

8.SubqueryScan 节点

SubqueryScan节点的作用是以另一个査询计划树(子计划)为扫描对象进行元组的扫描,其扫描过程最终被转换为子计划的执行。

Postgres子查询主要包含如下几个关键字: EXISTS, IN, NOT IN, ANY/SOME, ALL,详细介绍可以看看:子查询表达式

举例子:

postgres=# explain select id  from test_new where exists (select id from test_dm);
                               QUERY PLAN
-------------------------------------------------------------------------
 Result  (cost=0.02..35.52 rows=2550 width=4)
   One-Time Filter: $0
   InitPlan 1 (returns $0)
     ->  Seq Scan on test_dm  (cost=0.00..22346.00 rows=1000000 width=0)
   ->  Seq Scan on test_new  (cost=0.00..35.50 rows=2550 width=4)
(5 行)

下面这个查询虽然也是子查询,但是在查询编译阶段被优化了(提升子连接,主要是把ANY和EXIST子句转换为半连接)

postgres=# explain select id  from test_new where exists (select id from test_dm where id = test_new.id);
                                 QUERY PLAN
-----------------------------------------------------------------------------
 Hash Semi Join  (cost=38753.00..42736.38 rows=1275 width=4)
   Hash Cond: (test_new.id = test_dm.id)
   ->  Seq Scan on test_new  (cost=0.00..35.50 rows=2550 width=4)
   ->  Hash  (cost=22346.00..22346.00 rows=1000000 width=4)
         ->  Seq Scan on test_dm  (cost=0.00..22346.00 rows=1000000 width=4)
(5 行)

有关内容,这里有一篇讲得很好:PostgreSQL查询优化之子查询优化

SubqueryScan节点在Scan节点之上扩展定义了子计划的根节点指针(subplan字段),而subrtable字段是査询编译器使用的结构,执行器运行时其值为空。

typedef struct SubqueryScan
{
	Scan		scan;
	Plan	   *subplan;
} SubqueryScan;

显然,SubqueryScan节点的初始化过程(ExecInitSubqueryScan函数)会使用ExecInitNode处理SubqueryScan的subplan字段指向的子计划树,并将子计划的PlanStale树根节点指针賦值给SubqueryScanState 的subplan字段。

typedef struct SubqueryScanState
{
	ScanState	ss;				/* its first field is NodeTag */
	PlanState  *subplan;
} SubqueryScanState;

我认为SubqueryScan节点其实就是一个壳子,为什么这么说呢?因为SubqueryScan节点的执行(ExecSubqueryScan 函数)通过将SubqueryNext 传递给 ExecScan函数处理来实现的。SubqueryNext实际则是调用ExecProcNode处理subplan来获得元组。也就是说,这里SubqueryScan是运行了一个独立的查询计划,然后获取它的结果,而不是自己去扫描表。因此recheck工作就在独立的查询计划里做过了,SubqueryScan节点不必再做。

所以我们可以看到:

static bool
SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
{
	/* nothing to check */
	return true;
}

上面说了在执行时调用了ExecProcNode处理subplan,那么在清理过程中,很显然需要额外调用ExecEndNode来清理子计划。

9.FunctionScan 节点

例子:

postgres=# CREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)
postgres-#     AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
postgres-#     LANGUAGE SQL;
CREATE FUNCTION
postgres=# explain SELECT * FROM dup(42);
                         QUERY PLAN
-------------------------------------------------------------
 Function Scan on dup  (cost=0.25..10.25 rows=1000 width=36)
(1 行)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值