grouping_planner主要做了3个工作:

  1. 对集合进行处理
  2. 对非SPJ函数进行优化
  3. 对SQL查询语句进行物理优化

grouping_planner实现代码如下:

static void
grouping_planner(PlannerInfo *root, bool inheritance_update,double tuple_fraction)
{/* 如果存在limit,offset,元组片段因子要改小 */if (parse->limitCount || parse->limitOffset){tuple_fraction = preprocess_limit(root, tuple_fraction,&offset_est, &count_est);}/* Make tuple_fraction accessible to lower-level routines */root->tuple_fraction = tuple_fraction;//判断是否存在集合操作,如何存在,则处理集合运算。if (parse->setOperations){//会把集合语句按照集合操作符(差,并,交)分割SQL语句,//然后调用为每一个独立的部分调用subquery_planner,//所以Postgresql几乎不支持集合优化//current_rel = plan_set_operations(root);//顺便求出路径排序root->sort_pathkeys = make_pathkeys_for_sortclauses(root,parse->sortClause,tlist);}else//非集合操作{/* ORDER BY和GROUP BY同时存在,先GROUP BY,在ORDER BY */if (parse->groupingSets){groupclause = preprocess_groupclause(root,linitial(current_sets));}/* 对目标列进行处理*/tlist = preprocess_targetlist(root, tlist);//提前执行带有max/min的聚合函数子句if (parse->hasAggs)preprocess_minmax_aggregates(root, tlist);}/*最优路径*/current_rel = query_planner(root, tlist,standard_qp_callback, &qp_extra);//为max/min生成执行计划if (parse->hasAggs)preprocess_minmax_aggregates(root, tlist);}
}

query_planner生成最优查询路径

产生两个最优查询路径,主要是cheatest_path(未排序)和sorted_path(排序)

RelOptInfo *
query_planner(PlannerInfo *root, List *tlist,query_pathkeys_callback qp_callback, void *qp_extra)
{/** If the query has an empty join tree, then it's something easy like* "SELECT 2+2;" or "INSERT ... VALUES()".  Fall through quickly.*/if (parse->jointree->fromlist == NIL){/** We still are required to call qp_callback, in case it's something* like "SELECT 2+2 ORDER BY 1".标准化其他排序键,例如ORDER BY,GROUP BY*/root->canon_pathkeys = NIL;(*qp_callback) (root, qp_extra);return final_rel;}//初始化ROOT成员/*找出所有基本表,放入simple_rte_array */setup_simple_rel_arrays(root);/*找出所有基本表,放入生成基本关系*/add_base_rels_to_query(root, (Node *) parse->jointree);//分解where和join中的约束条件,构建连接树joinlist = deconstruct_jointree(root);/*检查外连接子句,把外连接的约束条件分发到对应关系上* ,看源码好像没有推到join关系上,而是推到join关系的子关系上*/reconsider_outer_join_clauses(root);/*处理隐含约束条件*/generate_base_implied_equalities(root);/*去除无用连接*/joinlist = remove_useless_joins(root, joinlist);/*完成多表链接,采用动态规划和遗传算法 */final_rel = make_one_rel(root, joinlist);return final_rel;
}

deconstruct_jointree构造连接树函数

deconstruct_jointree用于分解树上的连接结构,分解方式为:把where和join中每个子句加入一个list中,然后把约束条件分配到每个关系上。一是把限制条件分配到基本关系上,二是把连接条件分配到连接关系上。这些本质上是逻辑优化阶段的“谓词下推操作”。但是由于此时还没有构造join关系,所以不能推到join关系上

static List *
deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,Relids *qualscope, Relids *inner_join_rels,List **postponed_qual_list)
{if (IsA(jtnode, RangeTblRef)){//构造只有一个节点的关系joinlist = list_make1(jtnode);}else if (IsA(jtnode, FromExpr)){//递归构造每一个From子句,然后把结果下推/** Now process the top-level quals.*/foreach(l, (List *) f->quals){ //还构建了RestrictInfodistribute_qual_to_rels(root, qual,false, below_outer_join, JOIN_INNER,*qualscope, NULL, NULL, NULL,postponed_qual_list);}}else if (IsA(jtnode, JoinExpr)){//递归构造join两边switch (j->jointype){case JOIN_INNER:case JOIN_ANTI:case JOIN_FULL:default:}/*处理join下推*/foreach(l, my_quals){Node       *qual = (Node *) lfirst(l);distribute_qual_to_rels(root, qual,false, below_outer_join, j->jointype,*qualscope,ojscope, nonnullable_rels, NULL,postponed_qual_list);}}return joinlist;
}

reconsider_outer_join_clauses

分发外连接子句的约束条件

generate_base_implied_equalites

找出隐含条件,进一步谓词下推

make_one_rel 构造多表连接路径并选择最优路径的函数

RelOptInfo *
make_one_rel(PlannerInfo *root, List *joinlist)
{/* Mark base rels as to whether we care about fast-start plans */set_base_rel_consider_startup(root);//为每个基本关系估计大小set_base_rel_sizes(root);//为每个基本关系生成RelOptInfo结构,并且生成访问路径放在path,这是单表/子查询的最佳扫描方式.set_base_rel_pathlists(root);/*返回一个最终的连接所有表的RelOptInfo */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

joinlist是从where和join on子句找出能做连接操作的对象

static RelOptInfo *
make_rel_from_joinlist(PlannerInfo *root, List *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){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);}initial_rels = lappend(initial_rels, thisrel);}if (levels_needed == 1){}else{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);//动态规划}
}

动态规划算法

例如:有一条SQL语句
SELECT * FROM A,B,C,D where A.a=B.a and ...

每层的关系如下:

  1. 第四层:ABCD
  2. 第三层:ABC,ACD,BCD
  3. 第二层:AB,AC,AD,BC,BD...
  4. 第一层:A,B,C,D
RelOptInfo *
standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
{int         lev;RelOptInfo *rel;/* root->join_rel_level[j]存放的是第j层的连接路径,* 如果有n个关系,最大链接层数就是n。*/root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));root->join_rel_level[1] = initial_rels;//初始层数for (lev = 2; lev <= levels_needed; lev++){ListCell   *lc;/*使用动态规划求第lev层的所有关系,采用左深树和紧密熟的方式。N=N-1 +1;N=N-k + k */join_search_one_level(root, lev);/** Run generate_gather_paths() for each just-processed joinrel.  We* could not do this earlier because both regular and partial paths* can get added to a particular joinrel at multiple times within* join_search_one_level.  After that, we're done creating paths for* the joinrel, so run set_cheapest().*/foreach(lc, root->join_rel_level[lev]){rel = (RelOptInfo *) lfirst(lc);//为lev层每个关系求最优路径set_cheapest(rel);}}rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);root->join_rel_level = NULL;return rel;
}

转载于:https://www.cnblogs.com/biterror/p/7161671.html

PostgreSQL查询优化器之grouping_planner相关推荐

  1. 数据库服务器 之 PostgreSQL数据库的日常维护工作

    来自:LinuxSir.Org 摘要:为了保持所安装的 PostgreSQL 服务器平稳运行, 我们必须做一些日常性的维护工作.我们在这里讨论的这些工作都是经常重复的事情, 可以很容易地使用标准的 U ...

  2. 如何阅读《数据库查询优化器的艺术:原理解析与SQL性能优化》

    附录B 如何阅读本书 本书是一本数据库内核相关书籍,从数据库的查询优化器入手,对数据库的查询优化引擎进行了分析和对比,对查询优化的技术做了全面的总结和剖析.从不同角度看,可能有着不同的感受:不同角色的 ...

  3. PostgreSQL 自旋锁浅析

    获得技术资料内容,请访问Greenplum中文社区网站 什么是自旋锁 经过上次的<PostgreSQL查询优化器详解>中大明和牛二哥对PostgreSQL优化器的概要的讲解,小明感到自己已 ...

  4. 小明学PostgreSQL : 自旋锁浅析

    <小明学PostgreSQL : 自旋锁浅析> Table of Contents 什么是自旋锁 自旋锁的伪码 TAS VS CAS PostgreSQL的自旋锁 什么是自旋锁 自从小明学 ...

  5. 多租户saas 架构_[译/注] Force.com 多租户互联网应用开发平台的设计

    原文地址  http://cloud.pubs.dbs.uni-leipzig.de/sites/cloud.pubs.dbs.uni-leipzig.de/files/p889-weissman-1 ...

  6. magic feature_停止将PostgREST称为“ MAGIC”!

    magic feature by Ruslan Talpă 通过RuslanTalpă 停止将PostgREST称为" MAGIC"! (Stop calling PostgRES ...

  7. SQL(oracle)常用命令

    这部分包含那些 PostgreSQL 支持的 SQL 命令的信息.这里的 "SQL" 就是该语言通常的含义: 每条命令的与标准有关的兼容性的信息可以在相关的参考页中找到. Tabl ...

  8. vacuum 的描述(vacuum age )

    我觉得下面这段文字应该能够描述清楚 PostgreSQL 的 vacuum. 日常数据库维护工作 作者:小P 来自: LinuxSir.Org 摘要:为了保持所安装的 PostgreSQL 服务器平稳 ...

  9. greenplum架构介绍

    1 Greenplum 简介   GreenPlum是一款基于分布式架构的开源数据库:采用无共享(no shareing)的MPP架构(每个数据节点拥有独立的CPU.IO和内存等资源):其具有良好的线 ...

最新文章

  1. centos7 tomcat9
  2. bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
  3. php execute 更新不变,php – Doctrine executeUpdate数组参数
  4. 【大数据-Hadoop】dbeaver
  5. 男人必看,男性排毒同样重要 - 生活至上,美容至尚!
  6. BugKuCTF WEB 矛盾
  7. Windows下Faster R-CNN 配置/Matlab版本编译
  8. CSS实现checkbox radio 选中后文本颜色改变
  9. CSS选择器优先级排列
  10. MAC上编译OpenCV
  11. 设置android模拟器的ip地址,设置Android模拟器IP地址
  12. 川外计算机课什么时候截止,四川外国语大学留学生学习期限及课程设置
  13. 慎用windows EFS文件加密
  14. css相对图片加文字,html+css怎么在图片上添加文字
  15. 挪威科技大学计算机硕士,挪威科技大学硕士留学申请条件
  16. Leetcode Hot-100
  17. 你真的知道什么是三观吗?
  18. Logcat常见用法
  19. 普通母函数模板—hdu1028
  20. 最新kali之dbd

热门文章

  1. 预备作业01:你期望的师生关系是什么?
  2. Unity3D研究院之Editor下监听Transform变化
  3. @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  4. GWT笔记(Google Web Toolkit)1
  5. Castle ActiveRecord学习实践(1):快速入门指南
  6. SQL Azure(十) SQL Azure Data Sync数据同步功能(上)
  7. 关于Map迭代循环,key和value的顺序问题
  8. 大量POI点展示的一种解决方案
  9. 北海市卫生学校计算机教室,北海卫校2021年招生简章_北海市卫生学校
  10. c语言中自守数函数,【C语言训练】自守数问题 (C语言代码)