PostgreSQL在何处处理 sql查询之五十二
开始
/** Ready to do the primary planning.*/final_rel = make_one_rel(root, joinlist);
展开:
/** 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; }
其中,
root->all_baserels = bms_add_member(root->all_baserels, brel->relid);
这个展开后可以看到,因为 root->all_baserels 是NULL,所以什么也没执行。
/** bms_add_member - add a specified member to set** Input set is modified or recycled!*/ Bitmapset * bms_add_member(Bitmapset *a, int x) {int wordnum,bitnum;if (x < 0)elog(ERROR, "negative bitmapset member not allowed");if (a == NULL)return bms_make_singleton(x);wordnum = WORDNUM(x);bitnum = BITNUM(x);if (wordnum >= a->nwords){/* Slow path: make a larger set and union the input set into it */Bitmapset *result;int nwords;int i;result = bms_make_singleton(x);nwords = a->nwords;for (i = 0; i < nwords; i++)result->words[i] |= a->words[i];pfree(a);return result;}/* Fast path: x fits in existing set */a->words[wordnum] |= ((bitmapword) 1 << bitnum);return a; }
接着分析下一个:
set_base_rel_sizes(root);
/** set_base_rel_sizes* Set the size estimates (rows and widths) for each base-relation entry.** We do this in a separate pass over the base rels so that rowcount* estimates are available for parameterized path generation.*/ static void set_base_rel_sizes(PlannerInfo *root) {Index rti;for (rti = 1; rti < root->simple_rel_array_size; rti++){RelOptInfo *rel = root->simple_rel_array[rti];/* there may be empty slots corresponding to non-baserel RTEs */if (rel == NULL)continue;Assert(rel->relid == rti); /* sanity check on array *//* ignore RTEs that are "other rels" */if (rel->reloptkind != RELOPT_BASEREL)continue;set_rel_size(root, rel, rti, root->simple_rte_array[rti]);} }
这是成本评估的非常重要的依据。
再展开 set_rel_size 函数:
/** set_rel_size* Set size estimates for a base relation*/ static void set_rel_size(PlannerInfo *root, RelOptInfo *rel,Index rti, RangeTblEntry *rte) {if (rel->reloptkind == RELOPT_BASEREL &&relation_excluded_by_constraints(root, rel, rte)){/** We proved we don't need to scan the rel via constraint exclusion,* so set up a single dummy path for it. Here we only check this for* regular baserels; if it's an otherrel, CE was already checked in* set_append_rel_pathlist().** In this case, we go ahead and set up the relation's path right away* instead of leaving it for set_rel_pathlist to do. This is because* we don't have a convention for marking a rel as dummy except by* assigning a dummy path to it.*/set_dummy_rel_pathlist(rel);}else if (rte->inh){/* It's an "append relation", process accordingly */set_append_rel_size(root, rel, rti, rte);}else{switch (rel->rtekind){case RTE_RELATION:if (rte->relkind == RELKIND_FOREIGN_TABLE){/* Foreign table */set_foreign_size(root, rel, rte);}else{/* Plain relation */set_plain_rel_size(root, rel, rte);}break;case RTE_SUBQUERY:/** Subqueries don't support parameterized paths, so just go* ahead and build their paths immediately.*/set_subquery_pathlist(root, rel, rti, rte);break;case RTE_FUNCTION:set_function_size_estimates(root, rel);break;case RTE_VALUES:set_values_size_estimates(root, rel);break;case RTE_CTE:/** CTEs don't support parameterized paths, so just go ahead* and build their paths immediately.*/if (rte->self_reference)set_worktable_pathlist(root, rel, rte);elseset_cte_pathlist(root, rel, rte);break;default:elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);break;}} }
因为我的是简单查询,所以会走到:
/* Plain relation */set_plain_rel_size(root, rel, rte);
展开 set_plain_rel_size :
/** set_plain_rel_size* Set size estimates for a plain relation (no subquery, no inheritance)*/ static void set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) {/** Test any partial indexes of rel for applicability. We must do this* first since partial unique indexes can affect size estimates.*/check_partial_indexes(root, rel);/* Mark rel with estimated output rows, width, etc */set_baserel_size_estimates(root, rel);/** Check to see if we can extract any restriction conditions from join* quals that are OR-of-AND structures. If so, add them to the rel's* restriction list, and redo the above steps.*/if (create_or_index_quals(root, rel)){check_partial_indexes(root, rel);set_baserel_size_estimates(root, rel);} }
再对 set_baserel_size_estimates 展开一层:
/** set_baserel_size_estimates* Set the size estimates for the given base relation.** The rel's targetlist and restrictinfo list must have been constructed* already, and rel->tuples must be set.** We set the following fields of the rel node:* rows: the estimated number of output tuples (after applying* restriction clauses).* width: the estimated average output tuple width in bytes.* baserestrictcost: estimated cost of evaluating baserestrictinfo clauses.*/ void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel) {double nrows;/* Should only be applied to base relations */Assert(rel->relid > 0);nrows = rel->tuples *clauselist_selectivity(root,rel->baserestrictinfo,0,JOIN_INNER,NULL);rel->rows = clamp_row_est(nrows);cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);set_rel_width(root, rel); }
rel->tuples 值是如何算得?1条记录第表,tuples 是2400, 4条的却是 2140。
得仔细研究。
PostgreSQL在何处处理 sql查询之五十二相关推荐
- PostgreSQL在何处处理 sql查询之五十四
接前面,从 cheapeast_path 的角度,关注 query_planner 函数,对其进行简化: void query_planner(PlannerInfo *root, List *tli ...
- PostgreSQL在何处处理 sql查询之十二
接前面,对 subquery_planner,进行进一步的分析: /*--------------------* subquery_planner* Invokes the planner on a ...
- PostgreSQL在何处处理 sql查询之六十二
对 RelOptInfo * make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) 函数进行研究: 看看 inner ...
- PostgreSQL在何处处理 sql查询之五十一
继续分析 query_planner: /** query_planner* Generate a path (that is, a simplified plan) for a basic quer ...
- PostgreSQL在何处处理 sql查询之四十六
接前面,再上溯:set_base_rel_pathlists --> set_rel_pathlist /** set_base_rel_pathlists* Finds all paths a ...
- PostgreSQL在何处处理 sql查询之三十九
接前面,这次重点分析 ExecScan: 其for 循环内部: for (;;){ TupleTableSlot *slot;CHECK_FOR_INTERRUPTS(); slot = ExecSc ...
- PostgreSQL在何处处理 sql查询之三十八
这里又遇到了函数指针: executor.h头文件中,定义了 ExecScanAccessMtd 指针,或者定义了一个ExecScanAccessMtd 函数原型的指针 /** prototypes ...
- PostgreSQL在何处处理 sql查询之六十六
继续分析 /** final_cost_hashjoin* Final estimate of the cost and result size of a hashjoin path.** Note: ...
- 第九章 SQL查询数据库(二)
文章目录 第九章 SQL查询数据库(二) 调用用户定义函数的查询 查询串行对象属性 查询集合 使用说明和限制 调用文本搜索的查询 伪字段 查询元数据 快速查询 查询和企业缓存协议Enterprise ...
最新文章
- linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架
- SAP评估控制 Valuation control
- 及时沟通的重要性_沟通与代码同样重要
- 第六十二期:腾讯云发布“小程序·云开发十大优秀实践”:猫眼、唯品会等入选
- 掌控谈话~谈价格的秘诀
- python爬取百度文库_利用Python语言轻松爬取数据
- java后端简历项目经历_为了面试字节跳动后端开发岗(Java)鬼知道我经历了什么.....
- php autoload 性能,PHP __autoload()方法真的影响性能吗?
- Barrage 弹幕实现原理
- Access2016学习2
- 软件著作权申请文档模版
- matlab随机线性微分方程,基于MATLAB的随机线性微分方程的求解
- 运行caffe代码 SegNet
- java .getbytes_java中String的getBytes方法使用
- wangEditor富文本实现导入word功能
- JETT(五)-支持Excel公式
- 为什么别人可以年薪百万?
- 开手游要选用怎么样的服务器
- android加密、签名相关
- linux C读取字库文件
热门文章
- doe报告模板_技术漫谈|关于制剂研发过程中的实验设计(DOE)误区讨论
- drcom linux怎么运行,drcom for linux
- java gui 选项_【Java-GUI】04 菜单
- java线程能做什么_java中的多线程能做什么 ?基本作用能说下吗?
- 你知道吗?脑机接口训练会对大脑物质结构和功能产生影响
- 脑源(brainsourcing)技术可以自动识别人类的偏好
- 量子信息之父辞世,开山论文写完14年才被发表,晚年去当建筑工人
- 用GAN创造新蛋白只需几周,大幅缩短制药周期 | Nature子刊
- 谷歌甲骨文Java专利大战终审判决:安卓使用Java不构成侵权
- MIT喊你来上课,深度学习课程,免费的那种 | 资源