PostgreSQL查询代价估算(四)

来源:互联网 发布:有线电视有网络吗 编辑:程序博客网 时间:2024/06/15 11:45

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(otherrestriction 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;

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

                      !ExecSupportsMarkRestore(inner_path->pathtype))

              path->materialize_inner= true;

       elseif (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花费,连接的元组数通常少于比较时的数目

0 0
原创粉丝点击