PostgreSQL 源码解读(40)- 查询语句#25(query_planner函数#3)
上一小节介绍了函数query_planner的主处理逻辑以及setup_simple_rel_arrays和setup_append_rel_array两个子函数的实现逻辑,本节继续介绍函数query_planner中的add_base_rels_to_query函数。
一、重要的数据结构
Relation
typedef struct RelationData
{
RelFileNode rd_node;
struct SMgrRelationData *rd_smgr;
int rd_refcnt;
BackendId rd_backend;
bool rd_islocaltemp;
bool rd_isnailed;
bool rd_isvalid;
char rd_indexvalid;
bool rd_statvalid;
SubTransactionId rd_createSubid;
SubTransactionId rd_newRelfilenodeSubid;
Form_pg_class rd_rel;
TupleDesc rd_att;
Oid rd_id;
LockInfoData rd_lockInfo;
RuleLock *rd_rules;
MemoryContext rd_rulescxt;
TriggerDesc *trigdesc;
struct RowSecurityDesc *rd_rsdesc;
List *rd_fkeylist;
bool rd_fkeyvalid;
MemoryContext rd_partkeycxt;
struct PartitionKeyData *rd_partkey;
MemoryContext rd_pdcxt;
struct PartitionDescData *rd_partdesc;
List *rd_partcheck;
List *rd_indexlist;
Oid rd_oidindex;
Oid rd_pkindex;
Oid rd_replidindex;
List *rd_statlist;
Bitmapset *rd_indexattr;
Bitmapset *rd_projindexattr;
Bitmapset *rd_keyattr;
Bitmapset *rd_pkattr;
Bitmapset *rd_idattr;
Bitmapset *rd_projidx;
PublicationActions *rd_pubactions;
bytea *rd_options;
Form_pg_index rd_index;
struct HeapTupleData *rd_indextuple;
Oid rd_amhandler;
MemoryContext rd_indexcxt;
struct IndexAmRoutine *rd_amroutine;
Oid *rd_opfamily;
Oid *rd_opcintype;
RegProcedure *rd_support;
FmgrInfo *rd_supportinfo;
int16 *rd_indoption;
List *rd_indexprs;
List *rd_indpred;
Oid *rd_exclops;
Oid *rd_exclprocs;
uint16 *rd_exclstrats;
void *rd_amcache;
Oid *rd_indcollation;
struct FdwRoutine *rd_fdwroutine;
Oid rd_toastoid;
struct PgStat_TableStatus *pgstat_info;
} RelationData;
typedef struct RelationData *Relation;
IndexOptInfo
索引信息
typedef struct IndexOptInfo
{
NodeTag type;
Oid indexoid;
Oid reltablespace;
RelOptInfo *rel;
BlockNumber pages;
double tuples;
int tree_height;
int ncolumns;
int nkeycolumns;
int *indexkeys;
Oid *indexcollations;
Oid *opfamily;
Oid *opcintype;
Oid *sortopfamily;
bool *reverse_sort;
bool *nulls_first;
bool *canreturn;
Oid relam;
List *indexprs;
List *indpred;
List *indextlist;
List *indrestrictinfo;
bool predOK;
bool unique;
bool immediate;
bool hypothetical;
//从Index Relation拷贝过来的AM(访问方法)API信息
bool amcanorderbyop;
bool amoptionalkey;
bool amsearcharray;
bool amsearchnulls;
bool amhasgettuple;
bool amhasgetbitmap;
bool amcanparallel;
void (*amcostestimate) ();
} IndexOptInfo;
ForeignKeyOptInfo
外键优化信息
typedef struct ForeignKeyOptInfo
{
NodeTag type;
Index con_relid;
Index ref_relid;
int nkeys;
AttrNumber conkey[INDEX_MAX_KEYS];
AttrNumber confkey[INDEX_MAX_KEYS];
Oid conpfeqop[INDEX_MAX_KEYS];
int nmatched_ec;
int nmatched_rcols;
int nmatched_ri;
struct EquivalenceClass *eclass[INDEX_MAX_KEYS];
List *rinfos[INDEX_MAX_KEYS];
} ForeignKeyOptInfo;
StatisticExtInfo
typedef struct StatisticExtInfo
{
NodeTag type;
Oid statOid;
RelOptInfo *rel;
char kind;
Bitmapset *keys;
} StatisticExtInfo;
二、源码解读
add_base_rels_to_query函数构建查询的RelOptInfos
add_base_rels_to_query
void
add_base_rels_to_query(PlannerInfo *root, Node *jtnode)//遍历jointree递归实现
{
//以下的递归遍历结构先前的内容已反复出现N次
if (jtnode == NULL)
return;
if (IsA(jtnode, RangeTblRef))//RTR
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
(void) build_simple_rel(root, varno, NULL);
}
else if (IsA(jtnode, FromExpr))//FromExpr
{
FromExpr *f = (FromExpr *) jtnode;
ListCell *l;
foreach(l, f->fromlist)//fromlist
add_base_rels_to_query(root, lfirst(l));
}
else if (IsA(jtnode, JoinExpr))//JoinExpr
{
JoinExpr *j = (JoinExpr *) jtnode;
add_base_rels_to_query(root, j->larg);//左Child
add_base_rels_to_query(root, j->rarg);//右Child
}
else
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(jtnode));
}
RelOptInfo *
build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
{
RelOptInfo *rel;
RangeTblEntry *rte;
Assert(relid > 0 && relid < root->simple_rel_array_size);
if (root->simple_rel_array[relid] != NULL)
elog(ERROR, "rel %d already exists", relid);
rte = root->simple_rte_array[relid];//获取RTE
Assert(rte != NULL);
rel = makeNode(RelOptInfo);//构建RelOptInfo
rel->reloptkind = parent ? RELOPT_OTHER_MEMBER_REL : RELOPT_BASEREL;
rel->relids = bms_make_singleton(relid);//初始化relids
rel->rows = 0;
rel->consider_startup = (root->tuple_fraction > 0);
rel->consider_param_startup = false;
rel->consider_parallel = false;
rel->reltarget = create_empty_pathtarget();
rel->pathlist = NIL;
rel->ppilist = NIL;
rel->partial_pathlist = NIL;
rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL;
rel->cheapest_unique_path = NULL;
rel->cheapest_parameterized_paths = NIL;
rel->direct_lateral_relids = NULL;
rel->lateral_relids = NULL;
rel->relid = relid;
rel->rtekind = rte->rtekind;
rel->lateral_vars = NIL;
rel->lateral_referencers = NULL;
rel->indexlist = NIL;
rel->statlist = NIL;
rel->pages = 0;
rel->tuples = 0;
rel->allvisfrac = 0;
rel->subroot = NULL;
rel->subplan_params = NIL;
rel->rel_parallel_workers = -1;
rel->serverid = InvalidOid;
rel->userid = rte->checkAsUser;
rel->useridiscurrent = false;
rel->fdwroutine = NULL;
rel->fdw_private = NULL;
rel->unique_for_rels = NIL;
rel->non_unique_for_rels = NIL;
rel->baserestrictinfo = NIL;
rel->baserestrictcost.startup = 0;
rel->baserestrictcost.per_tuple = 0;
rel->baserestrict_min_security = UINT_MAX;
rel->joininfo = NIL;
rel->has_eclass_joins = false;
rel->consider_partitionwise_join = false;
rel->part_scheme = NULL;
rel->nparts = 0;
rel->boundinfo = NULL;
rel->partition_qual = NIL;
rel->part_rels = NULL;
rel->partexprs = NULL;
rel->nullable_partexprs = NULL;
rel->partitioned_child_rels = NIL;
if (parent)//存在父RelOptInfo,设置top_parent_relids变量(最上层的Relids)
{
if (parent->top_parent_relids)
rel->top_parent_relids = parent->top_parent_relids;
else
rel->top_parent_relids = bms_copy(parent->relids);
}
else
rel->top_parent_relids = NULL;
switch (rte->rtekind)
{
case RTE_RELATION:
get_relation_info(root, rte->relid, rte->inh, rel);//基表,从数据字典中获取统计信息
break;
case RTE_SUBQUERY:
case RTE_FUNCTION:
case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
case RTE_NAMEDTUPLESTORE:
rel->min_attr = 0;
rel->max_attr = list_length(rte->eref->colnames);
rel->attr_needed = (Relids *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
rel->attr_widths = (int32 *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
break;
default:
elog(ERROR, "unrecognized RTE kind: %d",
(int) rte->rtekind);
break;
}
root->simple_rel_array[relid] = rel;//存储RelOptInfo
if (rte->securityQuals)
root->qual_security_level = Max(root->qual_security_level,
list_length(rte->securityQuals));
//如果这个RelOptInfo是一个appendrel的父节点,递归的构建其children对应的RelOptInfos
if (rte->inh)
{
ListCell *l;
int nparts = rel->nparts;
int cnt_parts = 0;
if (nparts > 0)
rel->part_rels = (RelOptInfo **)
palloc(sizeof(RelOptInfo *) * nparts);
foreach(l, root->append_rel_list)//递归调用
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
RelOptInfo *childrel;
if (appinfo->parent_relid != relid)
continue;
childrel = build_simple_rel(root, appinfo->child_relid,
rel);
if (!rel->part_scheme)
continue;
Assert(cnt_parts < nparts);
rel->part_rels[cnt_parts] = childrel;
cnt_parts++;
}
Assert(cnt_parts == nparts);
}
return rel;
}
void
get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
RelOptInfo *rel)
{
Index varno = rel->relid;//Relation的relid
Relation relation;//Relation信息
bool hasindex;//是否含有index
List *indexinfos = NIL;//IndexOptInfo链表
relation = heap_open(relationObjectId, NoLock);//Relation信息
if (!RelationNeedsWAL(relation) && RecoveryInProgress())//恢复过程不允许访问
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot access temporary or unlogged relations during recovery")));
rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1;//(FirstLowInvalidHeapAttributeNumber=-8)
//#define RelationGetNumberOfAttributes(relation) ((relation)->rd_rel->relnatts)
rel->max_attr = RelationGetNumberOfAttributes(relation);//
rel->reltablespace = RelationGetForm(relation)->reltablespace;//表空间
Assert(rel->max_attr >= rel->min_attr);
rel->attr_needed = (Relids *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));//初始化
rel->attr_widths = (int32 *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));//初始化
//如果不是inheritance parent,则估算Relation的大小
if (!inhparent)
estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
&rel->pages, &rel->tuples, &rel->allvisfrac);
rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1);
if (inhparent ||
(IgnoreSystemIndexes && IsSystemRelation(relation)))//继承表/系统表并且忽略索引
hasindex = false;
else
hasindex = relation->rd_rel->relhasindex;//是否含有索引
if (hasindex)//存在索引,则生成IndexOptInfo链表
{
List *indexoidlist;
ListCell *l;
LOCKMODE lmode;
indexoidlist = RelationGetIndexList(relation);//获取Relation的Index Oid链表
if (rel->relid == root->parse->resultRelation)
lmode = RowExclusiveLock;//该Relation是结果Relation,锁模式为行排它锁
else
lmode = AccessShareLock;//否则为访问共享锁
foreach(l, indexoidlist)//遍历Index Oid
{
Oid indexoid = lfirst_oid(l);
Relation indexRelation;
Form_pg_index index;
IndexAmRoutine *amroutine;
IndexOptInfo *info;
int ncolumns,
nkeycolumns;
int i;
indexRelation = index_open(indexoid, lmode);//获取Index相关信息
index = indexRelation->rd_index;
if (!IndexIsValid(index))
{
index_close(indexRelation, NoLock);//忽略无效的Index
continue;
}
if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
{
index_close(indexRelation, NoLock);//忽略分区索引
continue;
}
if (index->indcheckxmin &&
!TransactionIdPrecedes(HeapTupleHeaderGetXmin(indexRelation->rd_indextuple->t_data),
TransactionXmin))
{
root->glob->transientPlan = true;//有效索引,但还不能正常使用,忽略之
index_close(indexRelation, NoLock);
continue;
}
info = makeNode(IndexOptInfo);//创建IndexOptInfo节点
info->indexoid = index->indexrelid;//OID
info->reltablespace =
RelationGetForm(indexRelation)->reltablespace;//表空间
info->rel = rel;//Index所在的Relation
info->ncolumns = ncolumns = index->indnatts;//Index的列个数
info->nkeycolumns = nkeycolumns = index->indnkeyatts;//
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);//初始化内存空间
info->indexcollations = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns);
for (i = 0; i < ncolumns; i++)//索引键
{
info->indexkeys[i] = index->indkey.values[i];
info->canreturn[i] = index_can_return(indexRelation, i + 1);
}
for (i = 0; i < nkeycolumns; i++)//索引键属性
{
info->opfamily[i] = indexRelation->rd_opfamily[i];
info->opcintype[i] = indexRelation->rd_opcintype[i];
info->indexcollations[i] = indexRelation->rd_indcollation[i];
}
info->relam = indexRelation->rd_rel->relam;//?
amroutine = indexRelation->rd_amroutine;//拷贝IndexRelation中的信息
info->amcanorderbyop = amroutine->amcanorderbyop;
info->amoptionalkey = amroutine->amoptionalkey;
info->amsearcharray = amroutine->amsearcharray;
info->amsearchnulls = amroutine->amsearchnulls;
info->amcanparallel = amroutine->amcanparallel;
info->amhasgettuple = (amroutine->amgettuple != NULL);
info->amhasgetbitmap = (amroutine->amgetbitmap != NULL);
info->amcostestimate = amroutine->amcostestimate;
Assert(info->amcostestimate != NULL);
if (info->relam == BTREE_AM_OID)//BTree
{
Assert(amroutine->amcanorder);
info->sortopfamily = info->opfamily;
info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
for (i = 0; i < nkeycolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
}
}
else if (amroutine->amcanorder)//可排序的访问方法
{
info->sortopfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
for (i = 0; i < nkeycolumns; i++)
{
int16 opt = indexRelation->rd_indoption[i];
Oid ltopr;
Oid btopfamily;
Oid btopcintype;
int16 btstrategy;
info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;//是否倒序?
info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;//NULL值优先?
ltopr = get_opfamily_member(info->opfamily[i],
info->opcintype[i],
info->opcintype[i],
BTLessStrategyNumber);
if (OidIsValid(ltopr) &&
get_ordering_op_properties(ltopr,
&btopfamily,
&btopcintype,
&btstrategy) &&
btopcintype == info->opcintype[i] &&
btstrategy == BTLessStrategyNumber)
{
info->sortopfamily[i] = btopfamily;//排序操作类?
}
else//失败,索引视为未排序
{
info->sortopfamily = NULL;
info->reverse_sort = NULL;
info->nulls_first = NULL;
break;
}
}
}
else//非可排序,设置为NULL
{
info->sortopfamily = NULL;
info->reverse_sort = NULL;
info->nulls_first = NULL;
}
info->indexprs = RelationGetIndexExpressions(indexRelation);//索引表达式(函数索引)
info->indpred = RelationGetIndexPredicate(indexRelation);//索引谓词信息(条件索引)
if (info->indexprs && varno != 1)
ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
if (info->indpred && varno != 1)
ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
info->indextlist = build_index_tlist(root, info, relation);//索引的列
info->indrestrictinfo = NIL;
info->predOK = false;
info->unique = index->indisunique;
info->immediate = index->indimmediate;
info->hypothetical = false;
if (info->indpred == NIL)//非条件索引
{
info->pages = RelationGetNumberOfBlocks(indexRelation);//Index的pages
info->tuples = rel->tuples;//Index的元组
}
else
{
double allvisfrac;
estimate_rel_size(indexRelation, NULL,
&info->pages, &info->tuples, &allvisfrac);//估算Index的大小
if (info->tuples > rel->tuples)//Index的元组数不能大于数据表元组数
info->tuples = rel->tuples;
}
if (info->relam == BTREE_AM_OID)//BTree
{
info->tree_height = _bt_getrootheight(indexRelation);//BTree高度
}
else
{
info->tree_height = -1;//非BTree
}
index_close(indexRelation, NoLock);
indexinfos = lcons(info, indexinfos);
}
list_free(indexoidlist);
}
rel->indexlist = indexinfos;
rel->statlist = get_relation_statistics(rel, relation);
if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)//FDW
{
rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
}
else
{
rel->serverid = InvalidOid;
rel->fdwroutine = NULL;
}
get_relation_foreign_keys(root, rel, relation, inhparent);//收集外键信息
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);//收集分区表信息
heap_close(relation, NoLock);
if (get_relation_info_hook)
(*get_relation_info_hook) (root, relationObjectId, inhparent, rel);//钩子函数
}
三、跟踪分析
测试脚本,创建部分(条件)索引和函数索引:
testdb=# create index idx_dwxx_expr on t_dwxx(trim(dwmc));
CREATE INDEX
testdb=# create index idx_dwxx_predicate on t_dwxx(dwdz) where dwdz like '广东省%';
CREATE INDEX
testdb=# explain verbose select * from t_dwxx where dwdz like '广东省%';
QUERY PLAN
---------------------------------------------------------------
Seq Scan on public.t_dwxx (cost=0.00..1.04 rows=1 width=474)
Output: dwmc, dwbh, dwdz
Filter: ((t_dwxx.dwdz)::text ~~ '广东省%'::text)
(3 rows)
跟踪分析:
(gdb) b add_base_rels_to_query
Breakpoint 1 at 0x765400: file initsplan.c, line 107.
(gdb) c
Continuing.
Breakpoint 1, add_base_rels_to_query (root=0x23107f8, jtnode=0x2251cc8) at initsplan.c:107
107 if (jtnode == NULL)
(gdb) n
109 if (IsA(jtnode, RangeTblRef))
(gdb)
115 else if (IsA(jtnode, FromExpr))
(gdb)
第一次调用,jtnode类型为FromExpr
117 FromExpr *f = (FromExpr *) jtnode;
(gdb)
120 foreach(l, f->fromlist)
(gdb)
121 add_base_rels_to_query(root, lfirst(l));
(gdb)
Breakpoint 1, add_base_rels_to_query (root=0x23107f8, jtnode=0x22515f0) at initsplan.c:107
107 if (jtnode == NULL)
(gdb)
第二次调用,类型为RTR
109 if (IsA(jtnode, RangeTblRef))
(gdb)
111 int varno = ((RangeTblRef *) jtnode)->rtindex;
(gdb)
113 (void) build_simple_rel(root, varno, NULL);
(gdb) p varno
$1 = 1
进入build_simple_rel
...
180 switch (rte->rtekind)
(gdb)
184 get_relation_info(root, rte->relid, rte->inh, rel);
进入get_relation_info
查看Relation的相关信息:
...
##Relation的相关信息
121 relation = heap_open(relationObjectId, NoLock);
(gdb)
124 if (!RelationNeedsWAL(relation) && RecoveryInProgress())
(gdb) p *relation
$4 = {rd_node = {spcNode = 1663, dbNode = 16384, relNode = 16394}, rd_smgr = 0x230d358, rd_refcnt = 1, rd_backend = -1,
rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 1 '\001', rd_statvalid = true,
rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f6b9a010380, rd_att = 0x7f6b99fff5e8, rd_id = 16394,
rd_lockInfo = {lockRelId = {relId = 16394, dbId = 16384}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0,
rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0,
rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x7f6b9a011b80, rd_oidindex = 0, rd_pkindex = 16476,
rd_replidindex = 16476, rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0,
rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0, rd_indextuple = 0x0,
rd_amhandler = 0, rd_indexcxt = 0x0, rd_amroutine = 0x0, rd_opfamily = 0x0, rd_opcintype = 0x0, rd_support = 0x0,
rd_supportinfo = 0x0, rd_indoption = 0x0, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0,
rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0,
pgstat_info = 0x22d11b8}
##rd_pkindex = 16476,关键字对应的OID
##pg_class输出的结构体
(gdb) p *relation->rd_rel
$5 = {relname = {data = "t_dwxx", '\000' <repeats 57 times>}, relnamespace = 2200, reltype = 16396, reloftype = 0,
relowner = 10, relam = 0, relfilenode = 16394, reltablespace = 0, relpages = 1, reltuples = 3, relallvisible = 0,
reltoastrelid = 0, relhasindex = true, relisshared = false, relpersistence = 112 'p', relkind = 114 'r', relnatts = 3,
relchecks = 0, relhasoids = false, relhasrules = false, relhastriggers = false, relhassubclass = false,
relrowsecurity = false, relforcerowsecurity = false, relispopulated = true, relreplident = 100 'd',
relispartition = false, relrewrite = 0, relfrozenxid = 587, relminmxid = 1}
##属性(3个)
(gdb) p *relation->rd_att
$6 = {natts = 3, tdtypeid = 16396, tdtypmod = -1, tdhasoid = false, tdrefcount = 1, constr = 0x7f6b99fffb18,
attrs = 0x7f6b99fff608}
(gdb) p relation->rd_att->attrs[0]
$8 = {attrelid = 16394, attname = {data = "dwmc", '\000' <repeats 59 times>}, atttypid = 1043, attstattarget = -1,
attlen = -1, attnum = 1, attndims = 0, attcacheoff = 0, atttypmod = 104, attbyval = false, attstorage = 120 'x',
attalign = 105 'i', attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000',
attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 100}
(gdb) p relation->rd_att->attrs[1]
$9 = {attrelid = 16394, attname = {data = "dwbh", '\000' <repeats 59 times>}, atttypid = 1043, attstattarget = -1,
attlen = -1, attnum = 2, attndims = 0, attcacheoff = -1, atttypmod = 14, attbyval = false, attstorage = 120 'x',
attalign = 105 'i', attnotnull = true, atthasdef = false, atthasmissing = false, attidentity = 0 '\000',
attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 100}
(gdb) p relation->rd_att->attrs[3]
$10 = {attrelid = 0, attname = {data = '\000' <repeats 44 times>, "\230\023-\002", '\000' <repeats 15 times>},
atttypid = 0, attstattarget = 0, attlen = 0, attnum = 0, attndims = 0, attcacheoff = 0, atttypmod = 0, attbyval = false,
attstorage = 0 '\000', attalign = 0 '\000', attnotnull = false, atthasdef = false, atthasmissing = false,
attidentity = 0 '\000', attisdropped = false, attislocal = false, attinhcount = 0, attcollation = 0}
##Index相应的OID
(gdb) p relation->rd_indexlist->head->data.oid_value
$12 = 16476
(gdb) p relation->rd_indexlist->head->next->data.oid_value
$13 = 16497
(gdb) p relation->rd_indexlist->head->next->next->data.oid_value
$14 = 16499
...
进入estimate_rel_size
146 estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
(gdb) step
estimate_rel_size (rel=0x7f6b9a00f390, attr_widths=0x231c674, pages=0x23124d8, tuples=0x23124e0, allvisfrac=0x23124e8)
at plancat.c:948
948 switch (rel->rd_rel->relkind)
(gdb) p reltuples
$19 = 3
...
回到get_relation_info
(gdb)
get_relation_info (root=0x23107f8, relationObjectId=16394, inhparent=false, rel=0x2312428) at plancat.c:150
150 rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1);
获取索引信息(IndexOptInfo的获取在这里是重点)
162 if (hasindex)
(gdb)
168 indexoidlist = RelationGetIndexList(relation);
...
#第一个Index
(gdb) p indexoid
$2 = 16476
#IndexRelation的相关信息
(gdb) p *indexRelation
$3 = {rd_node = {spcNode = 1663, dbNode = 16384, relNode = 16476}, rd_smgr = 0x230d3c8, rd_refcnt = 1, rd_backend = -1,
rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 0 '\000', rd_statvalid = false,
rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f6b99fff7f8, rd_att = 0x7f6b9a00f5a0, rd_id = 16476,
rd_lockInfo = {lockRelId = {relId = 16476, dbId = 16384}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0,
rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0,
rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x0, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0,
rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0, rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0,
rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x7f6b9a011898, rd_indextuple = 0x7f6b9a011860,
rd_amhandler = 330, rd_indexcxt = 0x2313400, rd_amroutine = 0x2313530, rd_opfamily = 0x2313640, rd_opcintype = 0x2313658,
rd_support = 0x2313670, rd_supportinfo = 0x2313690, rd_indoption = 0x23137b8, rd_indexprs = 0x0, rd_indpred = 0x0,
rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, rd_amcache = 0x22fada8, rd_indcollation = 0x23137a0,
rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x22d1230}
(gdb) p *indexRelation->rd_rel
$4 = {relname = {data = "t_dwxx_pkey", '\000' <repeats 52 times>}, relnamespace = 2200, reltype = 0, reloftype = 0,
relowner = 10, relam = 403, relfilenode = 16476, reltablespace = 0, relpages = 2, reltuples = 3, relallvisible = 0,
reltoastrelid = 0, relhasindex = false, relisshared = false, relpersistence = 112 'p', relkind = 105 'i', relnatts = 1,
relchecks = 0, relhasoids = false, relhasrules = false, relhastriggers = false, relhassubclass = false,
relrowsecurity = false, relforcerowsecurity = false, relispopulated = true, relreplident = 110 'n',
relispartition = false, relrewrite = 0, relfrozenxid = 0, relminmxid = 0}
...
#开始构造IndexOptInfo
237 info = makeNode(IndexOptInfo);
(gdb)
239 info->indexoid = index->indexrelid;
(gdb)
241 RelationGetForm(indexRelation)->reltablespace;
(gdb)
240 info->reltablespace =
(gdb)
242 info->rel = rel;
...
(gdb) p index->indnatts
$5 = 1
(gdb) n
246 info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
(gdb) p index->indnkeyatts
$6 = 1
...
252 for (i = 0; i < ncolumns; i++)
(gdb)
254 info->indexkeys[i] = index->indkey.values[i];
(gdb) p index->indkey.values[i]
$7 = 2
(gdb) p index->indkey
$8 = {vl_len_ = 104, ndim = 1, dataoffset = 0, elemtype = 21, dim1 = 1, lbound1 = 0, values = 0x7f6b9a0118c8}
...
##需结合数据字典查看
(gdb) p indexRelation->rd_opfamily[i]
$10 = 1994
(gdb) p indexRelation->rd_opcintype[i]
$11 = 25
(gdb) p indexRelation->rd_indcollation[i]
$12 = 100
...
##访问方法,后续做物理优化会使用
(gdb) p indexRelation->rd_rel->relam
$13 = 403
(gdb) p indexRelation->rd_amroutine
$14 = (struct IndexAmRoutine *) 0x2313530
(gdb) p *indexRelation->rd_amroutine
$15 = {type = T_IndexAmRoutine, amstrategies = 5, amsupport = 3, amcanorder = true, amcanorderbyop = false,
amcanbackward = true, amcanunique = true, amcanmulticol = true, amoptionalkey = true, amsearcharray = true,
amsearchnulls = true, amstorage = false, amclusterable = true, ampredlocks = true, amcanparallel = true,
amcaninclude = true, amkeytype = 0, ambuild = 0x4ea341 <btbuild>, ambuildempty = 0x4e282a <btbuildempty>,
aminsert = 0x4e28d0 <btinsert>, ambulkdelete = 0x4e37f0 <btbulkdelete>, amvacuumcleanup = 0x4e397f <btvacuumcleanup>,
amcanreturn = 0x4e427d <btcanreturn>, amcostestimate = 0x94f0ad <btcostestimate>, amoptions = 0x4e9f7f <btoptions>,
amproperty = 0x4e9fa9 <btproperty>, amvalidate = 0x4ecad6 <btvalidate>, ambeginscan = 0x4e2bd8 <btbeginscan>,
amrescan = 0x4e2d54 <btrescan>, amgettuple = 0x4e294f <btgettuple>, amgetbitmap = 0x4e2a7f <btgetbitmap>,
amendscan = 0x4e2f23 <btendscan>, ammarkpos = 0x4e303c <btmarkpos>, amrestrpos = 0x4e310b <btrestrpos>,
amestimateparallelscan = 0x4e3281 <btestimateparallelscan>, aminitparallelscan = 0x4e328c <btinitparallelscan>,
amparallelrescan = 0x4e32da <btparallelrescan>}
##部分属性值
(gdb) p amroutine->amcanorderbyop
$16 = false
(gdb) p amroutine->amoptionalkey
$17 = true
(gdb) p amroutine->amsearcharray
$18 = true
(gdb) p amroutine->amsearchnulls
$19 = true
(gdb) p amroutine->amcanparallel
$20 = true
##下面是函数指针
(gdb) p *amroutine->amgettuple
$21 = {_Bool (IndexScanDesc, ScanDirection)} 0x4e294f <btgettuple>
(gdb) p *amroutine->amgetbitmap
$24 = {int64 (IndexScanDesc, TIDBitmap *)} 0x4e2a7f <btgetbitmap>
(gdb) p *amroutine->amcostestimate
$26 = {void (struct PlannerInfo *, struct IndexPath *, double, Cost *, Cost *, Selectivity *, double *,
double *)} 0x94f0ad <btcostestimate>
282 if (info->relam == BTREE_AM_OID)
##BTree索引
...
##PK,唯一性为true
(gdb) p index->indisunique
$31 = true
...
(gdb) p info->tree_height
$32 = 0
##第2个索引(函数索引)
183 foreach(l, indexoidlist)
(gdb)
185 Oid indexoid = lfirst_oid(l);
...
进入RelationGetIndexExpressions函数
371 info->indexprs = RelationGetIndexExpressions(indexRelation);
(gdb) step
RelationGetIndexExpressions (relation=0x7f6b9a011970) at relcache.c:4625
##IndexRelation中已有相关信息
4625 if (relation->rd_indexprs)
(gdb) n
4626 return copyObject(relation->rd_indexprs);
##函数表达式中的args有相关的参数,类似的分析方法先前已有提及
(gdb) p *(FuncExpr *)relation->rd_indexprs->head->data.ptr_value
$36 = {xpr = {type = T_FuncExpr}, funcid = 885, funcresulttype = 25, funcretset = false, funcvariadic = false,
funcformat = COERCE_EXPLICIT_CALL, funccollid = 100, inputcollid = 100, args = 0x22fb638, location = -1}
回到get_relation_info
...
##第3个索引,这是一个部分(条件)索引
183 foreach(l, indexoidlist)
(gdb)
185 Oid indexoid = lfirst_oid(l);
...
372 info->indpred = RelationGetIndexPredicate(indexRelation);
##这是一个OpExpr,详细的结构先前已有提及
(gdb) p *(Node *)indexRelation->rd_indpred->head->data.ptr_value
$38 = {type = T_OpExpr}
$39 = {xpr = {type = T_OpExpr}, opno = 1209, opfuncid = 850, opresulttype = 16, opretset = false, opcollid = 0,
inputcollid = 100, args = 0x23140d8, location = -1}
...
回到build_simple_rel函数
461 if (get_relation_info_hook)
(gdb)
463 }
(gdb)
build_simple_rel (root=0x23107f8, relid=1, parent=0x0) at relnode.c:185
185 break;
(gdb) n
213 root->simple_rel_array[relid] = rel;
(gdb)
221 if (rte->securityQuals)
(gdb)
231 if (rte->inh)
(gdb)
271 return rel;
(gdb)
272 }
(gdb)
回到add_base_rels_to_query
add_base_rels_to_query (root=0x23107f8, jtnode=0x22515f0) at initsplan.c:133
133 }
##递归调用完毕,回到FromExpr->fromlist
(gdb) n
add_base_rels_to_query (root=0x23107f8, jtnode=0x2251cc8) at initsplan.c:120
120 foreach(l, f->fromlist)
(gdb) n
133 }
(gdb)
query_planner (root=0x23107f8, tlist=0x2312798, qp_callback=0x76e97d <standard_qp_callback>, qp_extra=0x7ffc7d69a9a0)
at planmain.c:150
150 build_base_rel_tlists(root, tlist);
(gdb)
#DONE!
四、参考资料
planmain.c
rel.h
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
PostgreSQL 源码解读(40)- 查询语句#25(query_planner函数#3)
下载Word文档到电脑,方便收藏和打印~