接前面,从 cheapeast_path 的角度,关注 query_planner 函数,对其进行简化:

void
query_planner(PlannerInfo *root, List *tlist,double tuple_fraction, double limit_tuples,Path **cheapest_path, Path **sorted_path,double *num_groups)
{Query       *parse = root->parse;List       *joinlist;RelOptInfo *final_rel;Path       *cheapestpath;Path       *sortedpath;Index        rti;double        total_pages;    ...*cheapest_path = cheapestpath;*sorted_path = sortedpath;
}

再关注 cheapestpath:

Path       *cheapestpath;.../** Pick out the cheapest-total path and the cheapest presorted path for* the requested pathkeys (if there is one).  We should take the tuple* fraction into account when selecting the cheapest presorted path, but* not when selecting the cheapest-total path, since if we have to sort* then we'll have to fetch all the tuples.  (But there's a special case:* if query_pathkeys is NIL, meaning order doesn't matter, then the* "cheapest presorted" path will be the cheapest overall for the tuple* fraction.)** The cheapest-total path is also the one to use if grouping_planner* decides to use hashed aggregation, so we return it separately even if* this routine thinks the presorted path is the winner.*/cheapestpath = final_rel->cheapest_total_path;

再看 final_rel: 从final_rel的观点,对 query_planner 进行简化:

RelOptInfo *final_rel;.../** Ready to do the primary planning.*/final_rel = make_one_rel(root, joinlist);...cheapestpath = final_rel->cheapest_total_path;

接着,对 make_one_rel里如何返回 cheapest_total_path 进行深入分析:

/** make_one_rel*      Finds all possible access paths for executing a query, returning a*      single rel that represents the join of all base rels in the query.*/
RelOptInfo *
make_one_rel(PlannerInfo *root, List *joinlist)
{RelOptInfo *rel;Index        rti;/** Construct the all_baserels Relids set.*/root->all_baserels = NULL;for (rti = 1; rti < root->simple_rel_array_size; rti++){RelOptInfo *brel = root->simple_rel_array[rti];/* there may be empty slots corresponding to non-baserel RTEs */if (brel == NULL)continue;Assert(brel->relid == rti);        /* sanity check on array *//* ignore RTEs that are "other rels" */if (brel->reloptkind != RELOPT_BASEREL)continue;root->all_baserels = bms_add_member(root->all_baserels, brel->relid);}/** Generate access paths for the base rels.*/set_base_rel_sizes(root);set_base_rel_pathlists(root);/** Generate access paths for the entire join tree.*/rel = make_rel_from_joinlist(root, joinlist);/** The result should join all and only the query's base rels.*/Assert(bms_equal(rel->relids, root->all_baserels));return rel;
}

若要进一步分析,就是这个  make_rel_from_joinlist 了:

/** make_rel_from_joinlist*      Build access paths using a "joinlist" to guide the join path search.** See comments for deconstruct_jointree() for definition of the joinlist* data structure.*/
static RelOptInfo *
make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
{int            levels_needed;List       *initial_rels;ListCell   *jl;/** Count the number of child joinlist nodes.  This is the depth of the* dynamic-programming algorithm we must employ to consider all ways of* joining the child nodes.*/levels_needed = list_length(joinlist);if (levels_needed <= 0)return NULL;            /* nothing to do? *//** Construct a list of rels corresponding to the child joinlist nodes.* This may contain both base rels and rels constructed according to* sub-joinlists.*/initial_rels = NIL;foreach(jl, joinlist){Node       *jlnode = (Node *) lfirst(jl);RelOptInfo *thisrel;if (IsA(jlnode, RangeTblRef)){int            varno = ((RangeTblRef *) jlnode)->rtindex;thisrel = find_base_rel(root, varno);}else if (IsA(jlnode, List)){/* Recurse to handle subproblem */thisrel = make_rel_from_joinlist(root, (List *) jlnode);}else{elog(ERROR, "unrecognized joinlist node type: %d",(int) nodeTag(jlnode));thisrel = NULL;        /* keep compiler quiet */}initial_rels = lappend(initial_rels, thisrel);}if (levels_needed == 1){/** Single joinlist node, so we're done.*/return (RelOptInfo *) linitial(initial_rels);}else{/** Consider the different orders in which we could join the rels,* using a plugin, GEQO, or the regular join search code.** We put the initial_rels list into a PlannerInfo field because* has_legal_joinclause() needs to look at it (ugly :-().*/root->initial_rels = initial_rels;if (join_search_hook)return (*join_search_hook) (root, levels_needed, initial_rels);else if (enable_geqo && levels_needed >= geqo_threshold)return geqo(root, levels_needed, initial_rels);elsereturn standard_join_search(root, levels_needed, initial_rels);}
}

对于我的简单查询,以上这个  (levels_needed == 1) 条件得到满足,所以就直接  return (RelOptInfo *) linitial(initial_rels);

按照这个视点,简化上述的程序:

static RelOptInfo *
make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
{int            levels_needed;List       *initial_rels;ListCell   *jl;/** Count the number of child joinlist nodes.  This is the depth of the* dynamic-programming algorithm we must employ to consider all ways of* joining the child nodes.*/levels_needed = list_length(joinlist);    .../** Construct a list of rels corresponding to the child joinlist nodes.* This may contain both base rels and rels constructed according to* sub-joinlists.*/initial_rels = NIL;foreach(jl, joinlist){       Node       *jlnode = (Node *) lfirst(jl);RelOptInfo *thisrel;if (IsA(jlnode, RangeTblRef)){
int   varno = ((RangeTblRef *) jlnode)->rtindex;thisrel = find_base_rel(root, varno);}else if (IsA(jlnode, List)){...}
        ...initial_rels = lappend(initial_rels, thisrel);}if (levels_needed == 1){
        /** Single joinlist node, so we're done.*/return (RelOptInfo *) linitial(initial_rels);}else{
       ...}
}

这句

int            varno = ((RangeTblRef *) jlnode)->rtindex;

是拿到 RangeTable 的 index。

thisrel = find_base_rel(root, varno);

是利用刚才的 index 从 root 中把这个 rel 找出来。

 initial_rels = lappend(initial_rels, thisrel);

是挂出一条链条。

return (RelOptInfo *) linitial(initial_rels);

是把第一个RelOptInfo对象取出来。

可以说,虽然是 在 make_rel_from_joinlist 中取出 rel 对象,但是其 cheapest_total_path ,在此之前早就准备好了。

转载于:https://www.cnblogs.com/gaojian/archive/2013/06/06/3121299.html

PostgreSQL在何处处理 sql查询之五十四相关推荐

  1. PostgreSQL在何处处理 sql查询之五十二

    开始 /** Ready to do the primary planning.*/final_rel = make_one_rel(root, joinlist); 展开: /** make_one ...

  2. PostgreSQL在何处处理 sql查询之五十一

    继续分析 query_planner: /** query_planner* Generate a path (that is, a simplified plan) for a basic quer ...

  3. PostgreSQL在何处处理 sql查询之四十六

    接前面,再上溯:set_base_rel_pathlists --> set_rel_pathlist /** set_base_rel_pathlists* Finds all paths a ...

  4. PostgreSQL在何处处理 sql查询之三十九

    接前面,这次重点分析 ExecScan: 其for 循环内部: for (;;){ TupleTableSlot *slot;CHECK_FOR_INTERRUPTS(); slot = ExecSc ...

  5. PostgreSQL在何处处理 sql查询之十二

    接前面,对 subquery_planner,进行进一步的分析: /*--------------------* subquery_planner* Invokes the planner on a ...

  6. PostgreSQL在何处处理 sql查询之三十八

    这里又遇到了函数指针: executor.h头文件中,定义了 ExecScanAccessMtd 指针,或者定义了一个ExecScanAccessMtd 函数原型的指针 /** prototypes ...

  7. PostgreSQL在何处处理 sql查询之六十六

    继续分析 /** final_cost_hashjoin* Final estimate of the cost and result size of a hashjoin path.** Note: ...

  8. PostgreSQL在何处处理 sql查询之六十二

    对 RelOptInfo * make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) 函数进行研究: 看看 inner ...

  9. SAP UI5 应用开发教程之五十四 - 如何将本地 SAP UI5 应用配置到本地 Fiori Launchpad 中的试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

最新文章

  1. 清除Solution中的vss信息
  2. MediaCodec 解码后数据对齐导致的绿边问题
  3. python无法识别vim中文代码
  4. android 阿里云 maven,Android SDK接入(Maven集成)
  5. php 常用的系统函数
  6. 谷歌浏览器服务器协议url,谷歌浏览器在地址栏输入URL到页面展示时中间发生了什么?...
  7. Skywalking-04:扩展Metric监控信息
  8. 一些简单的例子让你在Java中能更好的学习并理解循环结构(1)!
  9. springmvc往html设置变量,SpringMVC:@MatrixVariable矩阵变量
  10. android 获取屏幕的宽和高
  11. SylixOS中netdev_pbuf_alloc函数分析
  12. 西门子PLC1200的S7通讯(同一项目下)--通讯测试
  13. 干货丨让你更容易影响别人的 52 个小技巧
  14. PMP备考经典题库-敏捷专项练习题一(30道)
  15. 2017.11.21 软件工程概论第一节课
  16. 侍魂qq最新服务器,qq区怎么进不去了,说服务器未开启
  17. 马氏距离进行离群值检测
  18. sudo -i 和sudo -s
  19. Tableau 人言可畏:快速捕获客户对产品的关键评价
  20. Qt中重定义的解决方案

热门文章

  1. RN PickerView组件
  2. 前端—每天5道面试题(十)
  3. 输入5个整数,找出5个数中的两位数
  4. DLog-M什么意思
  5. “华为”和“荣耀”手机有什么区别?
  6. 很多人在网络上创业看不到本质
  7. 手机开启热点给其他设备上网和用插卡随身路由给其他设备上网有何区别呢?
  8. 华为鸿蒙HarmonyOS-面向全场景的分布式操作系统
  9. 怎样能让电脑干干净净的没有各种弹窗广告?
  10. android 返回键退出程序了吗?