溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PostgreSQL索引掃描成本估算中的函數(shù)分析

發(fā)布時(shí)間:2021-11-11 10:27:45 來(lái)源:億速云 閱讀:151 作者:iii 欄目:關(guān)系型數(shù)據(jù)庫(kù)

這篇文章主要介紹“PostgreSQL索引掃描成本估算中的函數(shù)分析”,在日常操作中,相信很多人在PostgreSQL索引掃描成本估算中的函數(shù)分析問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”P(pán)ostgreSQL索引掃描成本估算中的函數(shù)分析”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

一、數(shù)據(jù)結(jié)構(gòu)

IndexClauseSet
用于收集匹配索引的的條件語(yǔ)句

 /* Data structure for collecting qual clauses that match an index */
 typedef struct
 {
     bool        nonempty;       /* True if lists are not all empty */
     /* Lists of RestrictInfos, one per index column */
     List       *indexclauses[INDEX_MAX_KEYS];
 } IndexClauseSet;

二、源碼解讀

get_index_paths
get_index_paths函數(shù)根據(jù)給定的索引和索引條件子句,構(gòu)造索引訪問(wèn)路徑(IndexPath).

//--------------------------------------------------- get_index_paths

 /*
  * get_index_paths
  *    Given an index and a set of index clauses for it, construct IndexPaths.
  *    給定索引和索引條件子句,構(gòu)造索引訪問(wèn)路徑(IndexPaths).
  *
  * Plain indexpaths are sent directly to add_path, while potential
  * bitmap indexpaths are added to *bitindexpaths for later processing.
  * Plain索引訪問(wèn)路徑直接作為參數(shù)傳入到函數(shù)add_path中,潛在可能的位圖索引路徑
  * 被添加到bitindexpaths中供以后處理。
  *
  * This is a fairly simple frontend to build_index_paths().  Its reason for
  * existence is mainly to handle ScalarArrayOpExpr quals properly.  If the
  * index AM supports them natively, we should just include them in simple
  * index paths.  If not, we should exclude them while building simple index
  * paths, and then make a separate attempt to include them in bitmap paths.
  * Furthermore, we should consider excluding lower-order ScalarArrayOpExpr
  * quals so as to create ordered paths.
  * 該函數(shù)簡(jiǎn)單構(gòu)造build_index_paths所需要的參數(shù),并調(diào)用之.該函數(shù)存在的原因是正確
  * 處理ScalarArrayOpExpr表達(dá)式.
  */
 static void
 get_index_paths(PlannerInfo *root, RelOptInfo *rel,
                 IndexOptInfo *index, IndexClauseSet *clauses,
                 List **bitindexpaths)
 {
     List       *indexpaths;
     bool        skip_nonnative_saop = false;
     bool        skip_lower_saop = false;
     ListCell   *lc;
 
     /*
      * Build simple index paths using the clauses.  Allow ScalarArrayOpExpr
      * clauses only if the index AM supports them natively, and skip any such
      * clauses for index columns after the first (so that we produce ordered
      * paths if possible).
      */
     indexpaths = build_index_paths(root, rel,
                                    index, clauses,
                                    index->predOK,
                                    ST_ANYSCAN,
                                    &skip_nonnative_saop,
                                    &skip_lower_saop);//調(diào)用build_index_paths函數(shù)
 
     /*
      * If we skipped any lower-order ScalarArrayOpExprs on an index with an AM
      * that supports them, then try again including those clauses.  This will
      * produce paths with more selectivity but no ordering.
      */
     if (skip_lower_saop)
     {
         indexpaths = list_concat(indexpaths,
                                  build_index_paths(root, rel,
                                                    index, clauses,
                                                    index->predOK,
                                                    ST_ANYSCAN,
                                                    &skip_nonnative_saop,
                                                    NULL));
     }
 
     /*
      * Submit all the ones that can form plain IndexScan plans to add_path. (A
      * plain IndexPath can represent either a plain IndexScan or an
      * IndexOnlyScan, but for our purposes here that distinction does not
      * matter.  However, some of the indexes might support only bitmap scans,
      * and those we mustn't submit to add_path here.)
      * 逐一把可以形成Plain索引掃描計(jì)劃的的訪問(wèn)路徑作為參數(shù)調(diào)用add_path
      * (plain IndexPath可以是常規(guī)的索引掃描或者是IndexOnlyScan)
      *
      * Also, pick out the ones that are usable as bitmap scans.  For that, we
      * must discard indexes that don't support bitmap scans, and we also are
      * only interested in paths that have some selectivity; we should discard
      * anything that was generated solely for ordering purposes.
      * 找出可用于位圖掃描的索引
      */
     foreach(lc, indexpaths)//遍歷訪問(wèn)路徑
     {
         IndexPath  *ipath = (IndexPath *) lfirst(lc);
 
         if (index->amhasgettuple)
             add_path(rel, (Path *) ipath);//調(diào)用add_path
 
         if (index->amhasgetbitmap &&
             (ipath->path.pathkeys == NIL ||
              ipath->indexselectivity < 1.0))
             *bitindexpaths = lappend(*bitindexpaths, ipath);//如可以,添加到位圖索引掃描路徑鏈表中
     }
 
     /*
      * If there were ScalarArrayOpExpr clauses that the index can't handle
      * natively, generate bitmap scan paths relying on executor-managed
      * ScalarArrayOpExpr.
      */
     if (skip_nonnative_saop)
     {
         indexpaths = build_index_paths(root, rel,
                                        index, clauses,
                                        false,
                                        ST_BITMAPSCAN,
                                        NULL,
                                        NULL);
         *bitindexpaths = list_concat(*bitindexpaths, indexpaths);
     }
 }
 
//----------------------------------------------------------- build_index_paths
 /*
  * build_index_paths
  *    Given an index and a set of index clauses for it, construct zero
  *    or more IndexPaths. It also constructs zero or more partial IndexPaths.
  *    給定索引和該索引的條件,構(gòu)造0-N個(gè)索引訪問(wèn)路徑或partial索引訪問(wèn)路徑(用于并行)
  *
  * We return a list of paths because (1) this routine checks some cases
  * that should cause us to not generate any IndexPath, and (2) in some
  * cases we want to consider both a forward and a backward scan, so as
  * to obtain both sort orders.  Note that the paths are just returned
  * to the caller and not immediately fed to add_path().
  * 函數(shù)返回訪問(wèn)路徑鏈表:(1)執(zhí)行過(guò)程中的檢查會(huì)導(dǎo)致產(chǎn)生不了索引訪問(wèn)路徑 
  * (2)在某些情況下,同時(shí)考慮正向/反向掃描,以便獲得兩種排序順序。
  * 注意:訪問(wèn)路徑返回給調(diào)用方,不會(huì)馬上反饋到函數(shù)add_path中
  *
  * At top level, useful_predicate should be exactly the index's predOK flag
  * (ie, true if it has a predicate that was proven from the restriction
  * clauses).  When working on an arm of an OR clause, useful_predicate
  * should be true if the predicate required the current OR list to be proven.
  * Note that this routine should never be called at all if the index has an
  * unprovable predicate.
  * 在頂層,useful_predicate標(biāo)記應(yīng)與索引的predOK標(biāo)記一致.在操作OR自己的arm(?)時(shí),
  * 如果謂詞需要當(dāng)前的OR鏈表證明,則useful_predicate應(yīng)為T(mén).
  * 注意:如果索引有一個(gè)未經(jīng)驗(yàn)證的謂詞,則該例程不能被調(diào)用.
  *
  * scantype indicates whether we want to create plain indexscans, bitmap
  * indexscans, or both.  When it's ST_BITMAPSCAN, we will not consider
  * index ordering while deciding if a Path is worth generating.
  * scantype:提示是否創(chuàng)建plain/bitmap或者兩者兼顧的索引掃描.
  * 如該參數(shù)值為ST_BITMAPSCAN,則在決定訪問(wèn)路徑是否產(chǎn)生時(shí)不會(huì)考慮使用索引排序
  *
  * If skip_nonnative_saop is non-NULL, we ignore ScalarArrayOpExpr clauses
  * unless the index AM supports them directly, and we set *skip_nonnative_saop
  * to true if we found any such clauses (caller must initialize the variable
  * to false).  If it's NULL, we do not ignore ScalarArrayOpExpr clauses.
  * skip_nonnative_saop:
  * 如為NOT NULL,除非索引的訪問(wèn)方法(AM)直接支持,否則會(huì)忽略
  *     ScalarArrayOpExpr子句,如支持,則更新skip_nonnative_saop標(biāo)記為T(mén).
  * 如為NULL,不能忽略ScalarArrayOpExpr子句.
  *
  * If skip_lower_saop is non-NULL, we ignore ScalarArrayOpExpr clauses for
  * non-first index columns, and we set *skip_lower_saop to true if we found
  * any such clauses (caller must initialize the variable to false).  If it's
  * NULL, we do not ignore non-first ScalarArrayOpExpr clauses, but they will
  * result in considering the scan's output to be unordered.
  * skip_lower_saop:
  * 如為NOT NULL,ScalarArrayOpExpr子句中的首列不是索引列,則忽略之,
  *     同時(shí)如果找到相應(yīng)的子句,則設(shè)置skip_lower_saop標(biāo)記為T(mén).
  * 如為NULL,除首個(gè)ScalarArrayOpExpr子句外,其他子句不能被忽略,但輸出時(shí)不作排序
  * 
  * 輸入/輸出參數(shù):
  * 'rel' is the index's heap relation
  * rel-相應(yīng)的RelOptInfo
  * 'index' is the index for which we want to generate paths
  * index-相應(yīng)的索引IndexOptInfo
  * 'clauses' is the collection of indexable clauses (RestrictInfo nodes)
  * clauses-RestrictInfo節(jié)點(diǎn)集合
  * 'useful_predicate' indicates whether the index has a useful predicate
  * useful_predicate-提示索引是否有可用的謂詞
  * 'scantype' indicates whether we need plain or bitmap scan support
  * scantype-掃描類型,提示是否需要plain/bitmap掃描支持
  * 'skip_nonnative_saop' indicates whether to accept SAOP if index AM doesn't
  * skip_nonnative_saop-提示是否接受SAOP
  * 'skip_lower_saop' indicates whether to accept non-first-column SAOP
  * skip_lower_saop-提示是否接受非首列SAOP
  */
 static List *
 build_index_paths(PlannerInfo *root, RelOptInfo *rel,
                   IndexOptInfo *index, IndexClauseSet *clauses,
                   bool useful_predicate,
                   ScanTypeControl scantype,
                   bool *skip_nonnative_saop,
                   bool *skip_lower_saop)
 {
     List       *result = NIL;
     IndexPath  *ipath;
     List       *index_clauses;
     List       *clause_columns;
     Relids      outer_relids;
     double      loop_count;
     List       *orderbyclauses;
     List       *orderbyclausecols;
     List       *index_pathkeys;
     List       *useful_pathkeys;
     bool        found_lower_saop_clause;
     bool        pathkeys_possibly_useful;
     bool        index_is_ordered;
     bool        index_only_scan;
     int         indexcol;
 
     /*
      * Check that index supports the desired scan type(s)
      */
     switch (scantype)
     {
         case ST_INDEXSCAN:
             if (!index->amhasgettuple)
                 return NIL;
             break;
         case ST_BITMAPSCAN:
             if (!index->amhasgetbitmap)
                 return NIL;
             break;
         case ST_ANYSCAN:
             /* either or both are OK */
             break;
     }
 
     /*
      * 1. Collect the index clauses into a single list.
      * 1. 收集索引子句到單獨(dú)的鏈表中 
      *
      * We build a list of RestrictInfo nodes for clauses to be used with this
      * index, along with an integer list of the index column numbers (zero
      * based) that each clause should be used with.  The clauses are ordered
      * by index key, so that the column numbers form a nondecreasing sequence.
      * (This order is depended on by btree and possibly other places.)  The
      * lists can be empty, if the index AM allows that.
      * 我們?yōu)閷⑴c此索引一起使用的子句構(gòu)建了一個(gè)RestrictInfo節(jié)點(diǎn)鏈表,
      * 以及每個(gè)子句應(yīng)該與之一起使用的索引列編號(hào)(從0開(kāi)始)的整數(shù)鏈表.
      * 子句是按索引鍵排序的,因此列號(hào)形成一個(gè)非遞減序列。
      *  (這個(gè)排序取決于BTree和可能的其他地方).
      * 如果索引訪問(wèn)方法(AM)允許,鏈表可為空.
      *
      * found_lower_saop_clause is set true if we accept a ScalarArrayOpExpr
      * index clause for a non-first index column.  This prevents us from
      * assuming that the scan result is ordered.  (Actually, the result is
      * still ordered if there are equality constraints for all earlier
      * columns, but it seems too expensive and non-modular for this code to be
      * aware of that refinement.)
      *
      * We also build a Relids set showing which outer rels are required by the
      * selected clauses.  Any lateral_relids are included in that, but not
      * otherwise accounted for.
      * 建立一個(gè)已選擇的子句所依賴外部rels的Relids集合,包括lateral_relids.
      */
     index_clauses = NIL;
     clause_columns = NIL;
     found_lower_saop_clause = false;
     outer_relids = bms_copy(rel->lateral_relids);
     for (indexcol = 0; indexcol < index->ncolumns; indexcol++)//遍歷索引列
     {
         ListCell   *lc;
 
         foreach(lc, clauses->indexclauses[indexcol])//遍歷該列所對(duì)應(yīng)的約束條件
         {
             RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);//約束條件
 
             if (IsA(rinfo->clause, ScalarArrayOpExpr))//ScalarArrayOpExpr,TODO
             {
                 if (!index->amsearcharray)
                 {
                     if (skip_nonnative_saop)
                     {
                         /* Ignore because not supported by index */
                         *skip_nonnative_saop = true;
                         continue;
                     }
                     /* Caller had better intend this only for bitmap scan */
                     Assert(scantype == ST_BITMAPSCAN);
                 }
                 if (indexcol > 0)
                 {
                     if (skip_lower_saop)
                     {
                         /* Caller doesn't want to lose index ordering */
                         *skip_lower_saop = true;
                         continue;
                     }
                     found_lower_saop_clause = true;
                 }
             }
             index_clauses = lappend(index_clauses, rinfo);//添加到鏈表中
             clause_columns = lappend_int(clause_columns, indexcol);
             outer_relids = bms_add_members(outer_relids,
                                            rinfo->clause_relids);
         }
 
         /*
          * If no clauses match the first index column, check for amoptionalkey
          * restriction.  We can't generate a scan over an index with
          * amoptionalkey = false unless there's at least one index clause.
          * (When working on columns after the first, this test cannot fail. It
          * is always okay for columns after the first to not have any
          * clauses.)
          */
         if (index_clauses == NIL && !index->amoptionalkey)//沒(méi)有約束條件,返回空指針
             return NIL;
     }
 
     /* We do not want the index's rel itself listed in outer_relids */
     outer_relids = bms_del_member(outer_relids, rel->relid);//去掉自身relid
     /* Enforce convention that outer_relids is exactly NULL if empty */
     if (bms_is_empty(outer_relids))
         outer_relids = NULL;//設(shè)置為NULL
 
     /* Compute loop_count for cost estimation purposes */
     //計(jì)算成本估算所需要的循環(huán)次數(shù)loop_count
     loop_count = get_loop_count(root, rel->relid, outer_relids);
 
     /*
      * 2. Compute pathkeys describing index's ordering, if any, then see how
      * many of them are actually useful for this query.  This is not relevant
      * if we are only trying to build bitmap indexscans, nor if we have to
      * assume the scan is unordered.
      * 2.計(jì)算描述索引排序的路徑鍵(如果有的話),如存在的話,檢查有多少對(duì)查詢有用。
      *   如果只是嘗試構(gòu)建位圖索引掃描,或者掃描是無(wú)序的,那就無(wú)關(guān)緊要了。
      */
     pathkeys_possibly_useful = (scantype != ST_BITMAPSCAN &&
                                 !found_lower_saop_clause &&
                                 has_useful_pathkeys(root, rel));//是否存在可用的Pathkeys
     index_is_ordered = (index->sortopfamily != NULL);//索引是否排序?
     if (index_is_ordered && pathkeys_possibly_useful)//索引排序&存在可用的Pathkeys
     {
         index_pathkeys = build_index_pathkeys(root, index,
                                               ForwardScanDirection);//創(chuàng)建正向(ForwardScanDirection)掃描排序鍵
         useful_pathkeys = truncate_useless_pathkeys(root, rel,
                                                     index_pathkeys);//截?cái)酂o(wú)用的Pathkeys
         orderbyclauses = NIL;
         orderbyclausecols = NIL;
     }
     else if (index->amcanorderbyop && pathkeys_possibly_useful)//訪問(wèn)方法可以通過(guò)操作符排序
     {
         /* see if we can generate ordering operators for query_pathkeys */
         match_pathkeys_to_index(index, root->query_pathkeys,
                                 &orderbyclauses,
                                 &orderbyclausecols);//是否可以生成排序操作符
         if (orderbyclauses)
             useful_pathkeys = root->query_pathkeys;//如可以,則賦值
         else
             useful_pathkeys = NIL;
     }
     else//設(shè)置為NULL
     {
         useful_pathkeys = NIL;
         orderbyclauses = NIL;
         orderbyclausecols = NIL;
     }
 
     /*
      * 3. Check if an index-only scan is possible.  If we're not building
      * plain indexscans, this isn't relevant since bitmap scans don't support
      * index data retrieval anyway.
      * 3. 檢查是否只需要掃描索引.如果我們不構(gòu)建純索引掃描,這是無(wú)關(guān)緊要的,
     *     因?yàn)槲粓D掃描不支持索引數(shù)據(jù)檢索。
      */
     index_only_scan = (scantype != ST_BITMAPSCAN &&
                        check_index_only(rel, index));
 
     /*
      * 4. Generate an indexscan path if there are relevant restriction clauses
      * in the current clauses, OR the index ordering is potentially useful for
      * later merging or final output ordering, OR the index has a useful
      * predicate, OR an index-only scan is possible.
      * 4. 如果當(dāng)前子句中有相關(guān)的限制子句,或者索引排序?qū)τ谝院蟮?
      *    合并或最終的輸出排序可能有用,或者索引存在可用的謂詞,
      *    或者可能進(jìn)行純索引掃描,則生成索引掃描路徑。
      */
     if (index_clauses != NIL || useful_pathkeys != NIL || useful_predicate ||
         index_only_scan)
     {
         ipath = create_index_path(root, index,
                                   index_clauses,
                                   clause_columns,
                                   orderbyclauses,
                                   orderbyclausecols,
                                   useful_pathkeys,
                                   index_is_ordered ?
                                   ForwardScanDirection :
                                   NoMovementScanDirection,
                                   index_only_scan,
                                   outer_relids,
                                   loop_count,
                                   false);//創(chuàng)建索引掃描路徑
         result = lappend(result, ipath);//添加到結(jié)果鏈表中
 
         /*
          * If appropriate, consider parallel index scan.  We don't allow
          * parallel index scan for bitmap index scans.
          * 如果合適,考慮并行索引掃描。如為位圖索引,則不能使用并行.。
          */
         if (index->amcanparallel &&
             rel->consider_parallel && outer_relids == NULL &&
             scantype != ST_BITMAPSCAN)
         {
             ipath = create_index_path(root, index,
                                       index_clauses,
                                       clause_columns,
                                       orderbyclauses,
                                       orderbyclausecols,
                                       useful_pathkeys,
                                       index_is_ordered ?
                                       ForwardScanDirection :
                                       NoMovementScanDirection,
                                       index_only_scan,
                                       outer_relids,
                                       loop_count,
                                       true);//創(chuàng)建并行索引掃描路徑
 
             /*
              * if, after costing the path, we find that it's not worth using
              * parallel workers, just free it.
              */
             if (ipath->path.parallel_workers > 0)//在worker>0的情況下
                 add_partial_path(rel, (Path *) ipath);//添加partial路徑
             else
                 pfree(ipath);
         }
     }
 
     /*
      * 5. If the index is ordered, a backwards scan might be interesting.
      * 5. 如果索引是已排序的(如BTree等),構(gòu)建反向掃描(BackwardScanDirection)路徑
      */
     if (index_is_ordered && pathkeys_possibly_useful)
     {
         index_pathkeys = build_index_pathkeys(root, index,
                                               BackwardScanDirection);
         useful_pathkeys = truncate_useless_pathkeys(root, rel,
                                                     index_pathkeys);
         if (useful_pathkeys != NIL)
         {
             ipath = create_index_path(root, index,
                                       index_clauses,
                                       clause_columns,
                                       NIL,
                                       NIL,
                                       useful_pathkeys,
                                       BackwardScanDirection,
                                       index_only_scan,
                                       outer_relids,
                                       loop_count,
                                       false);
             result = lappend(result, ipath);
 
             /* If appropriate, consider parallel index scan */
             if (index->amcanparallel &&
                 rel->consider_parallel && outer_relids == NULL &&
                 scantype != ST_BITMAPSCAN)
             {
                 ipath = create_index_path(root, index,
                                           index_clauses,
                                           clause_columns,
                                           NIL,
                                           NIL,
                                           useful_pathkeys,
                                           BackwardScanDirection,
                                           index_only_scan,
                                           outer_relids,
                                           loop_count,
                                           true);
 
                 /*
                  * if, after costing the path, we find that it's not worth
                  * using parallel workers, just free it.
                  */
                 if (ipath->path.parallel_workers > 0)
                     add_partial_path(rel, (Path *) ipath);
                 else
                     pfree(ipath);
             }
         }
     }
 
     return result;
 }

三、跟蹤分析

測(cè)試腳本如下

select a.*,b.grbh,b.je 
from t_dwxx a,
    lateral (select t1.dwbh,t1.grbh,t2.je 
     from t_grxx t1 
          inner join t_jfxx t2 on t1.dwbh = a.dwbh and t1.grbh = t2.grbh) b
where a.dwbh = '1001'
order by b.dwbh;

啟動(dòng)gdb

(gdb) b get_index_paths
Breakpoint 1 at 0x74db5e: file indxpath.c, line 740.
(gdb) c
Continuing.

Breakpoint 1, get_index_paths (root=0x2704720, rel=0x27041b0, index=0x2713898, clauses=0x7fff834d8090, 
    bitindexpaths=0x7fff834d81b0) at indxpath.c:740
740   bool    skip_nonnative_saop = false;

選擇t_dwxx的主鍵進(jìn)行跟蹤

(gdb) p *index
$2 = {type = T_IndexOptInfo, indexoid = 16738, reltablespace = 0, rel = 0x27041b0, pages = 30, tuples = 10000, 
  tree_height = 1, ncolumns = 1, nkeycolumns = 1, indexkeys = 0x2713bd8, indexcollations = 0x2713bf0, opfamily = 0x2713c08, 
  opcintype = 0x2713c20, sortopfamily = 0x2713c08, reverse_sort = 0x2713c50, nulls_first = 0x2713c68, 
  canreturn = 0x2713c38, relam = 403, indexprs = 0x0, indpred = 0x0, indextlist = 0x2713ba8, indrestrictinfo = 0x2716c18, 
  predOK = false, unique = true, immediate = true, hypothetical = false, amcanorderbyop = false, amoptionalkey = true, 
  amsearcharray = true, amsearchnulls = true, amhasgettuple = true, amhasgetbitmap = true, amcanparallel = true, 
  amcostestimate = 0x94f0ad <btcostestimate>}
--
testdb=# select relname from pg_class where oid=16738;
   relname   
-------------
 t_dwxx_pkey
(1 row)
--

進(jìn)入函數(shù)build_index_paths

(gdb) step
build_index_paths (root=0x2704720, rel=0x27041b0, index=0x27135b8, clauses=0x7fff834d8090, useful_predicate=false, 
    scantype=ST_ANYSCAN, skip_nonnative_saop=0x7fff834d7e27, skip_lower_saop=0x7fff834d7e26) at indxpath.c:864
864   List     *result = NIL;

查看輸入?yún)?shù),其中clauses中的indexclauses數(shù)組,存儲(chǔ)約束條件鏈表

(gdb) p *clauses
$3 = {nonempty = true, indexclauses = {0x2717728, 0x0 <repeats 31 times>}}
(gdb) set $ri=(RestrictInfo *)clauses->indexclauses[0]->head->data.ptr_value

鏈表的第一個(gè)約束條件為:t_dwxx.dwbh(varno = 1, varattno = 2)='1001'(constvalue = 40986784)

(gdb) p *((OpExpr *)$ri->clause)->args
$11 = {type = T_List, length = 2, head = 0x27169f8, tail = 0x27169a8}
(gdb) p *(Node *)((OpExpr *)$ri->clause)->args->head->data.ptr_value
$12 = {type = T_RelabelType}
(gdb) p *(Node *)((OpExpr *)$ri->clause)->args->head->next->data.ptr_value
$13 = {type = T_Const}
(gdb) set $tmp1=(RelabelType *)((OpExpr *)$ri->clause)->args->head->data.ptr_value
(gdb) set $tmp2=(Const *)((OpExpr *)$ri->clause)->args->head->next->data.ptr_value
(gdb) p *(Var *)$tmp1->arg
$17 = {xpr = {type = T_Var}, varno = 1, varattno = 2, vartype = 1043, vartypmod = 24, varcollid = 100, varlevelsup = 0, 
  varnoold = 1, varoattno = 2, location = 147}
(gdb) p *(Const *)$tmp2
$18 = {xpr = {type = T_Const}, consttype = 25, consttypmod = -1, constcollid = 100, constlen = -1, constvalue = 40986784, 
  constisnull = false, constbyval = false, location = 194}

掃描類型,ST_ANYSCAN,包括plain&bitmap

(gdb) n
883   switch (scantype)
(gdb) p scantype
$19 = ST_ANYSCAN

Step 1:收集索引子句到單獨(dú)的鏈表中

923   for (indexcol = 0; indexcol < index->ncolumns; indexcol++)
(gdb) p outer_relids
$20 = (Relids) 0x0
(gdb) n
927     foreach(lc, clauses->indexclauses[indexcol])
(gdb) p indexcol
$21 = 0
(gdb) n
#rinfo約束條件:t_dwxx.dwbh='1001'
929       RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
(gdb) 
931       if (IsA(rinfo->clause, ScalarArrayOpExpr))
(gdb)

Step 1的主要邏輯:

(gdb) n
955       index_clauses = lappend(index_clauses, rinfo);
(gdb) p *index_clauses
Cannot access memory at address 0x0
(gdb) n
956       clause_columns = lappend_int(clause_columns, indexcol);
(gdb) 
958                        rinfo->clause_relids);
(gdb) 
957       outer_relids = bms_add_members(outer_relids,

Step 1完成后:

(gdb) p *outer_relids
$23 = {nwords = 1, words = 0x27177fc}
(gdb) p *index_clauses
$26 = {type = T_List, length = 1, head = 0x2717758, tail = 0x2717758}
(gdb) p outer_relids->words[0]
$27 = 0  -->無(wú)外部的Relids
(gdb) p *clause_columns
$31 = {type = T_IntList, length = 1, head = 0x27177a8, tail = 0x27177a8}
(gdb) p clause_columns->head->data.int_value
$32 = 0 -->列數(shù)組編號(hào)為0

循環(huán)次數(shù):

(gdb) p loop_count
$33 = 1

Step 2:計(jì)算描述索引排序的路徑鍵(如果有的話),如存在的話,檢查有多少對(duì)查詢有用。

...
(gdb) p pathkeys_possibly_useful
$35 = true
(gdb) p index_is_ordered
$36 = true

創(chuàng)建正向掃描排序鍵

(gdb) n
994     index_pathkeys = build_index_pathkeys(root, index,
(gdb) p *index_pathkeys
Cannot access memory at address 0x0 -->無(wú)需排序

Step 3:檢查是否只需要掃描索引

(gdb) p index_only_scan
$37 = false -->No way!

Step 4:生成索引掃描路徑
調(diào)用函數(shù)create_index_path(下節(jié)介紹)

1036      ipath = create_index_path(root, index,
(gdb) 
1049      result = lappend(result, ipath);
(gdb) p *ipath
$38 = {path = {type = T_IndexPath, pathtype = T_IndexScan, parent = 0x27041b0, pathtarget = 0x27134c8, param_info = 0x0, 
    parallel_aware = false, parallel_safe = true, parallel_workers = 0, rows = 1, startup_cost = 0.28500000000000003, 
    total_cost = 8.3025000000000002, pathkeys = 0x0}, indexinfo = 0x27135b8, indexclauses = 0x2717778, 
  indexquals = 0x27178e8, indexqualcols = 0x2717938, indexorderbys = 0x0, indexorderbycols = 0x0, 
  indexscandir = ForwardScanDirection, indextotalcost = 4.2925000000000004, indexselectivity = 0.0001}

Step 5:構(gòu)建反向掃描(BackwardScanDirection)路徑

(gdb) p index_is_ordered
$41 = true
(gdb) p pathkeys_possibly_useful
$42 = true
...
(gdb) p *index_pathkeys
Cannot access memory at address 0x0 -->無(wú)需排序

返回結(jié)果

1137    return result;
(gdb) 
1138  }

到此,關(guān)于“PostgreSQL索引掃描成本估算中的函數(shù)分析”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI