日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

PostgreSQL查询优化器之grouping_planner

發(fā)布時間:2025/6/17 数据库 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PostgreSQL查询优化器之grouping_planner 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

grouping_planner主要做了3個工作:

  • 對集合進行處理
  • 對非SPJ函數(shù)進行優(yōu)化
  • 對SQL查詢語句進行物理優(yōu)化
  • grouping_planner實現(xiàn)代碼如下:

    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語句,//然后調(diào)用為每一個獨立的部分調(diào)用subquery_planner,//所以Postgresql幾乎不支持集合優(yōu)化//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);//提前執(zhí)行帶有max/min的聚合函數(shù)子句if (parse->hasAggs)preprocess_minmax_aggregates(root, tlist);}/*最優(yōu)路徑*/current_rel = query_planner(root, tlist,standard_qp_callback, &qp_extra);//為max/min生成執(zhí)行計劃if (parse->hasAggs)preprocess_minmax_aggregates(root, tlist);} }

    query_planner生成最優(yōu)查詢路徑

    產(chǎn)生兩個最優(yōu)查詢路徑,主要是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);/*找出所有基本表,放入生成基本關(guān)系*/add_base_rels_to_query(root, (Node *) parse->jointree);//分解where和join中的約束條件,構(gòu)建連接樹joinlist = deconstruct_jointree(root);/*檢查外連接子句,把外連接的約束條件分發(fā)到對應關(guān)系上* ,看源碼好像沒有推到join關(guān)系上,而是推到join關(guān)系的子關(guān)系上*/reconsider_outer_join_clauses(root);/*處理隱含約束條件*/generate_base_implied_equalities(root);/*去除無用連接*/joinlist = remove_useless_joins(root, joinlist);/*完成多表鏈接,采用動態(tài)規(guī)劃和遺傳算法 */final_rel = make_one_rel(root, joinlist);return final_rel; }

    deconstruct_jointree構(gòu)造連接樹函數(shù)

    deconstruct_jointree用于分解樹上的連接結(jié)構(gòu),分解方式為:把where和join中每個子句加入一個list中,然后把約束條件分配到每個關(guān)系上。一是把限制條件分配到基本關(guān)系上,二是把連接條件分配到連接關(guān)系上。這些本質(zhì)上是邏輯優(yōu)化階段的“謂詞下推操作”。但是由于此時還沒有構(gòu)造join關(guān)系,所以不能推到join關(guān)系上

    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)){//構(gòu)造只有一個節(jié)點的關(guān)系joinlist = list_make1(jtnode);}else if (IsA(jtnode, FromExpr)){//遞歸構(gòu)造每一個From子句,然后把結(jié)果下推/** Now process the top-level quals.*/foreach(l, (List *) f->quals){ //還構(gòu)建了RestrictInfodistribute_qual_to_rels(root, qual,false, below_outer_join, JOIN_INNER,*qualscope, NULL, NULL, NULL,postponed_qual_list);}}else if (IsA(jtnode, JoinExpr)){//遞歸構(gòu)造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

    分發(fā)外連接子句的約束條件

    generate_base_implied_equalites

    找出隱含條件,進一步謂詞下推

    make_one_rel 構(gòu)造多表連接路徑并選擇最優(yōu)路徑的函數(shù)

    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);//為每個基本關(guān)系估計大小set_base_rel_sizes(root);//為每個基本關(guān)系生成RelOptInfo結(jié)構(gòu),并且生成訪問路徑放在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))//范圍表直接找出要連接的關(guān)系{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);//動態(tài)規(guī)劃} }

    動態(tài)規(guī)劃算法

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

    每層的關(guān)系如下:

  • 第四層:ABCD
  • 第三層:ABC,ACD,BCD
  • 第二層:AB,AC,AD,BC,BD...
  • 第一層: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個關(guān)系,最大鏈接層數(shù)就是n。*/root->join_rel_level = (List **) palloc0((levels_needed + 1) * sizeof(List *));root->join_rel_level[1] = initial_rels;//初始層數(shù)for (lev = 2; lev <= levels_needed; lev++){ListCell *lc;/*使用動態(tài)規(guī)劃求第lev層的所有關(guān)系,采用左深樹和緊密熟的方式。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層每個關(guān)系求最優(yōu)路徑set_cheapest(rel);}}rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);root->join_rel_level = NULL;return rel; }

    轉(zhuǎn)載于:https://www.cnblogs.com/biterror/p/7161671.html

    總結(jié)

    以上是生活随笔為你收集整理的PostgreSQL查询优化器之grouping_planner的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。