PostgreSQL查询代价估算(四)

本文介绍数据库中两表使用归并连接的成本估算过程,包括初步估计与最终计算两个阶段,通过分析内外表元组数量及可连接性确定CPU成本,并探讨了物化操作优化的条件。

1.1.1        两表连接的代价估算

1.1.1.1     归并连接的代价:final_cost_mergejoin

函数功能:

计算两个关系使用归并连接算法的花费。有些操作被缓存便于后续使用。内外表的可连接[1]的元组数决定着CPU的花费。

 

函数功能:

计算两个关系使用归并连接连接算法的花费。

对于mergejoin花费的计算,分为两个函数:

1.         一是initial_cost_mergejoin函数,初步估计mergejoin算法的花费,形成的结果会作为final_cost_mergejoin的入口参数(JoinCostWorkspace *workspace)传入final_cost_mergehjoin函数;

2.         二是final_cost_mergejoin函数,对mergejoin算法的花费进行计算,并决定是否选用物化操作优化mergejoin连接。

 

代码分析:

void

final_cost_mergejoin(PlannerInfo *root, MergePath *path,

                                    JoinCostWorkspace *workspace,

                                    SpecialJoinInfo *sjinfo)

{......

       //计算mergequalsqpquals(other restriction clauses)的花费(mergequalsjoinrestrictinfo的子部分)

       cost_qual_eval(&merge_qual_cost, mergeclauses, root);

       cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);

       qp_qual_cost.startup -= merge_qual_cost.startup;

       qp_qual_cost.per_tuple -= merge_qual_cost.per_tuple;

 

       //获取mergequals子句涉及的元组数,计算CPU花费的重要依据

       //每个子句都有不同的选择率(clause_selectivity函数计算子句的选择率)

       //approx_tuple_count函数计算归并子句(mergeclauses)中的各子句的选择率,这些选择率的积就是归并条件的总的选择率,总的选择率乘以内关系的元组数再乘以外关系的元组数,由此可以得到归并后的总的元组数(mergejointuples),将来要依据mergejointuples得出这些元组归并连接时的CPU花费

       mergejointuples = approx_tuple_count(root, &path->jpath, mergeclauses);

 

       //mergejoin算法,读入外表的一条元组,然后与内表的每个元组比较;如果外表有相等的元组,则内表需要多次读入,所以,重新扫描率总可能比1

      

       //如果外表键值是唯一的,则不存在内表需要重复读入的问题

       if (IsA(outer_path, UniquePath))

              rescannedtuples = 0;

       else//否则,要考虑内表需要重复读入

       {

              rescannedtuples = mergejointuples - inner_path_rows;

              if (rescannedtuples < 0)

                     rescannedtuples = 0;

       }

       rescanratio = 1.0 + (rescannedtuples / inner_path_rows);

 

       //计算内表在考虑了重复读入的问题后的全部花费

       bare_inner_cost = inner_run_cost * rescanratio;

 

       //物化内表的花费

       mat_inner_cost = inner_run_cost +

              cpu_operator_cost * inner_path_rows * rescanratio;

 

       //内表物化比内表重读花费小,则选择物化方式的优化

       if (enable_material && mat_inner_cost < bare_inner_cost)

              path->materialize_inner = true;

       else if (innersortkeys == NIL &&//内表无序且不支持mark/restore,选用物化

                      !ExecSupportsMarkRestore(inner_path->pathtype))

              path->materialize_inner = true;

       else if (enable_material && innersortkeys != NIL &&//内表有序但排序空间不够,选用物化

                      relation_byte_size(inner_path_rows, inner_path->parent->width) >

                      (work_mem * 1024L))

              path->materialize_inner = true;

       else

              path->materialize_inner = false;

 

       if (path->materialize_inner)

              run_cost += mat_inner_cost;

       else

              run_cost += bare_inner_cost;

 

//知道了选择率、元组数等,则可以计算CPU花费:

//1 归并的CPU的花费---进行比较的花费

       startup_cost += merge_qual_cost.startup;

       startup_cost += merge_qual_cost.per_tuple *

              (outer_skip_rows + inner_skip_rows * rescanratio);

       run_cost += merge_qual_cost.per_tuple *  //进行比较的花费

              ((outer_rows - outer_skip_rows) +

               (inner_rows - inner_skip_rows) * rescanratio);

 

//2 归并的CPU的花费进行连接的花费

       startup_cost += qp_qual_cost.startup;

       cpu_per_tuple = cpu_tuple_cost + qp_qual_cost.per_tuple;

       run_cost += cpu_per_tuple * mergejointuples;  //进行连接的花费

 

       path->jpath.path.startup_cost = startup_cost;

       path->jpath.path.total_cost = startup_cost + run_cost;

}

 

调用关系图解:

PostgreSQL查询代价估算(四) - 那海蓝蓝 - 那海蓝蓝的博客
 

1.         final_cost_mergejoin函数被create_mergejoin_path函数调用,直至被add_paths_to_joinrel函数调用,完成两表连接的mergejoin连接算法的花费估算;

2.         final_cost_mergejoin函数被sort_inner_and_outermatch_unsorted_outer这两个函数分别调用,用以应对多种情况(内外表是否有序)的连接操作。

 



[1] 比较是否可连接有CPU花费,比较的元组数目较多;进行连接也有CPU花费,连接的元组数通常少于比较时的数目

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值