iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL 源码解读(37)- 查询语句#22(查询优化-grouping_plan...
  • 749
分享到

PostgreSQL 源码解读(37)- 查询语句#22(查询优化-grouping_plan...

2024-04-02 19:04:59 749人浏览 泡泡鱼
摘要

在主函数subquery_planner完成外连接消除后,接下来调用grouping_planner函数,本节简单介绍了此函数的主体逻辑。 一、源码解读 grouping_plan

在主函数subquery_planner完成外连接消除后,接下来调用grouping_planner函数,本节简单介绍了此函数的主体逻辑。

一、源码解读

grouping_planner函数源码:


 static void
 grouping_planner(PlannerInfo *root, bool inheritance_update,
                  double tuple_fraction)
 {
     Query      *parse = root->parse;
     List       *tlist;
     int64       offset_est = 0;
     int64       count_est = 0;
     double      limit_tuples = -1.0;
     bool        have_postponed_srfs = false;
     PathTarget *final_target;
     List       *final_targets;
     List       *final_targets_contain_srfs;
     bool        final_target_parallel_safe;
     RelOptInfo *current_rel;
     RelOptInfo *final_rel;
     ListCell   *lc;
 
     
     if (parse->limitCount || parse->limitOffset)//存在LIMIT/OFFSET语句
     {
         tuple_fraction = preprocess_limit(root, tuple_fraction,
                                           &offset_est, &count_est);//获取元组数量
 
         
         if (count_est > 0 && offset_est >= 0)
             limit_tuples = (double) count_est + (double) offset_est;//
     }
 
     
     root->tuple_fraction = tuple_fraction;//设置值
 
     if (parse->setOperations)//集合操作,如UNION等
     {
         
         if (parse->sortClause)
             root->tuple_fraction = 0.0;//存在排序操作,需扫描所有的元组
 
         
         current_rel = plan_set_operations(root);//调用集合操作的"规划"函数
 
         
         Assert(parse->commandType == CMD_SELECT);
 
         tlist = root->processed_tlist;  
 
         
         tlist = postprocess_setop_tlist(copyObject(tlist), parse->targetList);
 
         
         root->processed_tlist = tlist;
 
         
         final_target = current_rel->cheapest_total_path->pathtarget;
 
         
         final_target_parallel_safe =
             is_parallel_safe(root, (node *) final_target->exprs);
 
         
         Assert(!parse->hasTargetSRFs);
         final_targets = final_targets_contain_srfs = NIL;
 
         
         if (parse->rowMarks)
             ereport(ERROR,
                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             
                      errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
                             LCS_asString(linitial_node(RowMarkClause,
                                                        parse->rowMarks)->strength))));
 
         
         Assert(parse->distinctClause == NIL);
         root->sort_pathkeys = make_pathkeys_for_sortclauses(root,
                                                             parse->sortClause,
                                                             tlist);
     }
     else//非集合操作
     {
         
         PathTarget *sort_input_target;
         List       *sort_input_targets;
         List       *sort_input_targets_contain_srfs;
         bool        sort_input_target_parallel_safe;
         PathTarget *grouping_target;
         List       *grouping_targets;
         List       *grouping_targets_contain_srfs;
         bool        grouping_target_parallel_safe;
         PathTarget *scanjoin_target;
         List       *scanjoin_targets;
         List       *scanjoin_targets_contain_srfs;
         bool        scanjoin_target_parallel_safe;
         bool        scanjoin_target_same_exprs;
         bool        have_grouping;
         AgGClauseCosts agg_costs;
         WindowFuncLists *wflists = NULL;
         List       *activewindows = NIL;
         grouping_sets_data *gset_data = NULL;
         standard_qp_extra qp_extra;
 
         
         Assert(!root->hasRecursion);//检查
 
         
         if (parse->groupingSets)//
         {
             gset_data = preprocess_grouping_sets(root);//预处理grouping sets语句
         }
         else
         {
             
             if (parse->groupClause)
                 parse->groupClause = preprocess_groupclause(root, NIL);//处理普通的Group By语句
         }
 
         
         tlist = preprocess_targetlist(root);//处理投影列
 
         
         root->processed_tlist = tlist;//赋值
 
         
         MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
         if (parse->hasAggs)//存在聚合函数
         {
             get_agg_clause_costs(root, (Node *) tlist, AGGSPLIT_SIMPLE,
                                  &agg_costs);//收集用于估算成本的统计信息
             get_agg_clause_costs(root, parse->havingQual, AGGSPLIT_SIMPLE,
                                  &agg_costs);//收集用于估算成本的统计信息
         }
 
         
         if (parse->hasWindowFuncs)//窗口函数
         {
             wflists = find_window_functions((Node *) tlist,
                                             list_length(parse->windowClause));
             if (wflists->numWindowFuncs > 0)
                 activeWindows = select_active_windows(root, wflists);
             else
                 parse->hasWindowFuncs = false;
         }
 
         
         if (parse->hasAggs)//预处理最大最小聚合
             preprocess_minmax_aggregates(root, tlist);
 
         
         if (parse->groupClause ||
             parse->groupingSets ||
             parse->distinctClause ||
             parse->hasAggs ||
             parse->hasWindowFuncs ||
             parse->hasTargetSRFs ||
             root->hasHavingQual)//存在Group By/Grouping Set等语句,则limit_tuples设置为-1
             root->limit_tuples = -1.0;
         else
             root->limit_tuples = limit_tuples;//否则,正常赋值
 
         
         qp_extra.tlist = tlist;//赋值
         qp_extra.activeWindows = activeWindows;
         qp_extra.groupClause = (gset_data
                                 ? (gset_data->rollups ? linitial_node(RollupData, gset_data->rollups)->groupClause : NIL)
                                 : parse->groupClause);
 
         
     //为查询中的扫描/连接部分生成最优的未排序/预排序路径(如FROM/WHERE语句表示的处理过程)
         current_rel = query_planner(root, tlist,
                                     standard_qp_callback, &qp_extra);
 
         
         final_target = create_pathtarget(root, tlist);
         final_target_parallel_safe =
             is_parallel_safe(root, (Node *) final_target->exprs);
 
         
         if (parse->sortClause)//存在sort语句?
         {
             sort_input_target = make_sort_input_target(root,
                                                        final_target,
                                                        &have_postponed_srfs);
             sort_input_target_parallel_safe =
                 is_parallel_safe(root, (Node *) sort_input_target->exprs);
         }
         else
         {
             sort_input_target = final_target;//不存在,则直接赋值
             sort_input_target_parallel_safe = final_target_parallel_safe;
         }
 
         
         if (activeWindows)//存在窗口函数?
         {
             grouping_target = make_window_input_target(root,
                                                        final_target,
                                                        activeWindows);
             grouping_target_parallel_safe =
                 is_parallel_safe(root, (Node *) grouping_target->exprs);
         }
         else
         {
             grouping_target = sort_input_target;
             grouping_target_parallel_safe = sort_input_target_parallel_safe;
         }
 
         
         have_grouping = (parse->groupClause || parse->groupingSets ||
                          parse->hasAggs || root->hasHavingQual);
         if (have_grouping)
         {//存在group等分组语句
             scanjoin_target = make_group_input_target(root, final_target);
             scanjoin_target_parallel_safe =
                 is_parallel_safe(root, (Node *) grouping_target->exprs);
         }
         else
         {
             scanjoin_target = grouping_target;
             scanjoin_target_parallel_safe = grouping_target_parallel_safe;
         }
 
         
         if (parse->hasTargetSRFs)//存在SRFs
         {
             
             split_pathtarget_at_srfs(root, final_target, sort_input_target,
                                      &final_targets,
                                      &final_targets_contain_srfs);
             final_target = linitial_node(PathTarget, final_targets);
             Assert(!linitial_int(final_targets_contain_srfs));
             
             split_pathtarget_at_srfs(root, sort_input_target, grouping_target,
                                      &sort_input_targets,
                                      &sort_input_targets_contain_srfs);
             sort_input_target = linitial_node(PathTarget, sort_input_targets);
             Assert(!linitial_int(sort_input_targets_contain_srfs));
             
             split_pathtarget_at_srfs(root, grouping_target, scanjoin_target,
                                      &grouping_targets,
                                      &grouping_targets_contain_srfs);
             grouping_target = linitial_node(PathTarget, grouping_targets);
             Assert(!linitial_int(grouping_targets_contain_srfs));
             
             split_pathtarget_at_srfs(root, scanjoin_target, NULL,
                                      &scanjoin_targets,
                                      &scanjoin_targets_contain_srfs);
             scanjoin_target = linitial_node(PathTarget, scanjoin_targets);
             Assert(!linitial_int(scanjoin_targets_contain_srfs));
         }
         else
         {
             
             final_targets = final_targets_contain_srfs = NIL;
             sort_input_targets = sort_input_targets_contain_srfs = NIL;
             grouping_targets = grouping_targets_contain_srfs = NIL;
             scanjoin_targets = list_make1(scanjoin_target);
             scanjoin_targets_contain_srfs = NIL;
         }
 
         
     //应用扫描/连接target
         scanjoin_target_same_exprs = list_length(scanjoin_targets) == 1
             && equal(scanjoin_target->exprs, current_rel->reltarget->exprs);
         apply_scanjoin_target_to_paths(root, current_rel, scanjoin_targets,
                                        scanjoin_targets_contain_srfs,
                                        scanjoin_target_parallel_safe,
                                        scanjoin_target_same_exprs);
 
         
     //赋值
         root->upper_targets[UPPERREL_FINAL] = final_target;
         root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
         root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;
 
         
         if (have_grouping)//存在分组操作
         {
             current_rel = create_grouping_paths(root,
                                                 current_rel,
                                                 grouping_target,
                                                 grouping_target_parallel_safe,
                                                 &agg_costs,
                                                 gset_data);//创建分组访问路径
             
             if (parse->hasTargetSRFs)
                 adjust_paths_for_srfs(root, current_rel,
                                       grouping_targets,
                                       grouping_targets_contain_srfs);
         }
 
         
         if (activeWindows)//存在窗口函数
         {
             current_rel = create_window_paths(root,
                                               current_rel,
                                               grouping_target,
                                               sort_input_target,
                                               sort_input_target_parallel_safe,
                                               tlist,
                                               wflists,
                                               activeWindows);
             
             if (parse->hasTargetSRFs)
                 adjust_paths_for_srfs(root, current_rel,
                                       sort_input_targets,
                                       sort_input_targets_contain_srfs);
         }
 
         
         if (parse->distinctClause)//存在distinct?
         {
             current_rel = create_distinct_paths(root,
                                                 current_rel);
         }
     }                           
 
     
     if (parse->sortClause)//存在sort语句?
     {
         current_rel = create_ordered_paths(root,
                                            current_rel,
                                            final_target,
                                            final_target_parallel_safe,
                                            have_postponed_srfs ? -1.0 :
                                            limit_tuples);
         
         if (parse->hasTargetSRFs)
             adjust_paths_for_srfs(root, current_rel,
                                   final_targets,
                                   final_targets_contain_srfs);
     }
 
     
     final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);//获取最终的RelOptInfo(用于替换RTE)
 
     
     if (current_rel->consider_parallel &&
         is_parallel_safe(root, parse->limitOffset) &&
         is_parallel_safe(root, parse->limitCount))
         final_rel->consider_parallel = true;//并行
 
     
     final_rel->serverid = current_rel->serverid;
     final_rel->userid = current_rel->userid;
     final_rel->useridiscurrent = current_rel->useridiscurrent;
     final_rel->fdwroutine = current_rel->fdwroutine;
 
     
     foreach(lc, current_rel->pathlist)//逐一遍历访问路径
     {
         Path       *path = (Path *) lfirst(lc);
 
         
         if (parse->rowMarks)
         {
             path = (Path *) create_lockrows_path(root, final_rel, path,
                                                  root->rowMarks,
                                                  SS_assign_special_param(root));
         }
 
         
         if (limit_needed(parse))
         {
             path = (Path *) create_limit_path(root, final_rel, path,
                                               parse->limitOffset,
                                               parse->limitCount,
                                               offset_est, count_est);
         }
 
         
         if (parse->commandType != CMD_SELECT && !inheritance_update)//非查询语句
         {
             List       *withCheckOptionLists;
             List       *returningLists;
             List       *rowMarks;
 
             
             if (parse->withCheckOptions)
                 withCheckOptionLists = list_make1(parse->withCheckOptions);
             else
                 withCheckOptionLists = NIL;
 
             if (parse->returningList)
                 returningLists = list_make1(parse->returningList);
             else
                 returningLists = NIL;
 
             
             if (parse->rowMarks)
                 rowMarks = NIL;
             else
                 rowMarks = root->rowMarks;
 
             path = (Path *)
                 create_modifytable_path(root, final_rel,
                                         parse->commandType,
                                         parse->canSetTag,
                                         parse->resultRelation,
                                         NIL,
                                         false,
                                         list_make1_int(parse->resultRelation),
                                         list_make1(path),
                                         list_make1(root),
                                         withCheckOptionLists,
                                         returningLists,
                                         rowMarks,
                                         parse->onConflict,
                                         SS_assign_special_param(root));
         }
 
         
         add_path(final_rel, path);
     }
 
     
     if (final_rel->consider_parallel && root->query_level > 1 &&
         !limit_needed(parse))
     {
         Assert(!parse->rowMarks && parse->commandType == CMD_SELECT);
         foreach(lc, current_rel->partial_pathlist)
         {
             Path       *partial_path = (Path *) lfirst(lc);
 
             add_partial_path(final_rel, partial_path);
         }
     }
 
     
     if (final_rel->fdwroutine &&
         final_rel->fdwroutine->GetForeignUpperPaths)
         final_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_FINAL,
                                                     current_rel, final_rel,
                                                     NULL);
 
     
     if (create_upper_paths_hook)
         (*create_upper_paths_hook) (root, UPPERREL_FINAL,
                                     current_rel, final_rel, NULL);
 
     
 }

二、参考资料

planner.c

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL 源码解读(37)- 查询语句#22(查询优化-grouping_plan...

本文链接: https://www.lsjlt.com/news/49981.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • oracle怎么查询当前用户所有的表
    要查询当前用户拥有的所有表,可以使用以下 sql 命令:select * from user_tables; 如何查询当前用户拥有的所有表 要查询当前用户拥有的所有表,可以使...
    99+
    2024-05-15
    oracle
  • oracle怎么备份表中数据
    oracle 表数据备份的方法包括:导出数据 (exp):将表数据导出到外部文件。导入数据 (imp):将导出文件中的数据导入表中。用户管理的备份 (umr):允许用户控制备份和恢复过程...
    99+
    2024-05-15
    oracle
  • oracle怎么做到数据实时备份
    oracle 实时备份通过持续保持数据库和事务日志的副本来实现数据保护,提供快速恢复。实现机制主要包括归档重做日志和 asm 卷管理系统。它最小化数据丢失、加快恢复时间、消除手动备份任务...
    99+
    2024-05-15
    oracle 数据丢失
  • oracle怎么查询所有的表空间
    要查询 oracle 中的所有表空间,可以使用 sql 语句 "select tablespace_name from dba_tablespaces",其中 dba_tabl...
    99+
    2024-05-15
    oracle
  • oracle怎么创建新用户并赋予权限设置
    答案:要创建 oracle 新用户,请执行以下步骤:以具有 create user 权限的用户身份登录;在 sql*plus 窗口中输入 create user identified ...
    99+
    2024-05-15
    oracle
  • oracle怎么建立新用户
    在 oracle 数据库中创建用户的方法:使用 sql*plus 连接数据库;使用 create user 语法创建新用户;根据用户需要授予权限;注销并重新登录以使更改生效。 如何在 ...
    99+
    2024-05-15
    oracle
  • oracle怎么创建新用户并赋予权限密码
    本教程详细介绍了如何使用 oracle 创建一个新用户并授予其权限:创建新用户并设置密码。授予对特定表的读写权限。授予创建序列的权限。根据需要授予其他权限。 如何使用 Oracle 创...
    99+
    2024-05-15
    oracle
  • oracle怎么查询时间段内的数据记录表
    在 oracle 数据库中查询指定时间段内的数据记录表,可以使用 between 操作符,用于比较日期或时间的范围。语法:select * from table_name wh...
    99+
    2024-05-15
    oracle
  • oracle怎么查看表的分区
    问题:如何查看 oracle 表的分区?步骤:查询数据字典视图 all_tab_partitions,指定表名。结果显示分区名称、上边界值和下边界值。 如何查看 Oracle 表的分区...
    99+
    2024-05-15
    oracle
  • oracle怎么导入dump文件
    要导入 dump 文件,请先停止 oracle 服务,然后使用 impdp 命令。步骤包括:停止 oracle 数据库服务。导航到 oracle 数据泵工具目录。使用 impdp 命令导...
    99+
    2024-05-15
    oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作