您的位置:首页 > 数据库

PostgresQL FDW 源码分析之 postgresGetForeignPaths()

2016-07-02 14:57 543 查看
进入 postgresGetForeignPaths()

在 postgresGetForeignRelSize() 中已经对最基本的外部表扫描做了成本估算,所以就用这些信息,直接生成一个 plan path:

/*
* Create simplest ForeignScan path node and add it to baserel.  This path
* corresponds to SeqScan path of regular tables (though depending on what
* baserestrict conditions we were able to send to remote, there might
* actually be an indexscan happening there).  We already did all the work
* to estimate cost and size of this path.
*/
path = create_foreignscan_path(root, baserel,
fpinfo->rows,
fpinfo->startup_cost,
fpinfo->total_cost,
NIL, /* no pathkeys */
NULL,		/* no outer rel either */
NULL,		/* no extra plan */
NIL);		/* no fdw_private list */


然后将这个 path 加入 RelOptInfo *baserel 中的 pathlist 中,接下来可能会生成其他的 plan path,但每个 path 中的 parent 都指向这个 RelOptInfo *baserel :

add_path(baserel, (Path *) path);
只有当外部表设定了 remote estimates,才会接着计算 parameterized join 相关的 plan path:

/*
* If we're not using remote estimates, stop here.  We have no way to
* estimate whether any join clauses would be worth sending across, so
* don't bother building parameterized paths.
*/
if (!fpinfo->use_remote_estimate)
return;
关于 join path 的实际计算过程暂不研究,其中值得注意的是:

join path 的计算结果存放在 param_info 中,并挂在 ppi_list 的链表上。

/* Get the ParamPathInfo */
param_info = get_baserel_parampathinfo(root, baserel,
required_outer);
Assert(param_info != NULL);

/*
* Add it to list unless we already have it.  Testing pointer equality
* is OK since get_baserel_parampathinfo won't make duplicates.
*/
ppi_list = list_append_unique_ptr(ppi_list, param_info);


每一种 join 的情况,都对应一个挂在 ppi_list 上的 param_info,对于每一个 param_info 都生成一个 path,与上面的基本扫描相比,它们都带上了 param_info->ppi_req_outer。

foreach(lc, ppi_list)
{
ParamPathInfo *param_info = (ParamPathInfo *) lfirst(lc);
double		rows;
int			width;
Cost		startup_cost;
Cost		total_cost;

/* Get a cost estimate from the remote */
estimate_path_cost_size(root, baserel,
param_info->ppi_clauses,
&rows, &width,
&startup_cost, &total_cost);

/*
* ppi_rows currently won't get looked at by anything, but still we
* may as well ensure that it matches our idea of the rowcount.
*/
param_info->ppi_rows = rows;

/* Make the path */
path = create_foreignscan_path(root, baserel,
rows,
startup_cost,
total_cost,
NIL,		/* no pathkeys */
param_info->ppi_req_outer,
NULL,
NIL);	/* no fdw_private list */
add_path(baserel, (Path *) path);
}
最后,在系统根据选出的最佳 path 生成 plan 的函数 create_scan_plan() (createplan.c)中,

scan_clauses 是准备发送给执行器执行语句的限制条件,这里如果存在 best_path->param_info 的话,就会将其中带有的 join 限制条件也加入 scan_clauses。

/*
* Extract the relevant restriction clauses from the parent relation. The
* executor must apply all these restrictions during the scan, except for
* pseudoconstants which we'll take care of below.
*/
scan_clauses = rel->baserestrictinfo;

/*
* If this is a parameterized scan, we also need to enforce all the join
* clauses available from the outer relation(s).
*
* For paranoia's sake, don't modify the stored baserestrictinfo list.
*/
if (best_path->param_info)
scan_clauses = list_concat(list_copy(scan_clauses),
best_path->param_info->ppi_clauses);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息