这篇文章主要讲解了“PostgreSQL中query_planner函数处理逻辑是怎样的”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中query_planner函数处理逻辑是怎样的”吧!
一、重要的数据结构
在query_planner中,对root(PlannerInfo)结构进行初始化和处理,为后续的计划作准备.
PlannerInfo
struct AppendRelInfo;
typedef struct PlannerInfo
{
NodeTag type;//Node标识
Query *parse;
PlannerGlobal *glob;
Index query_level;
struct PlannerInfo *parent_root;
List *plan_params;
Bitmapset *outer_params;
struct RelOptInfo **simple_rel_array;
int simple_rel_array_size;
RangeTblEntry **simple_rte_array;
struct AppendRelInfo **append_rel_array;//先前已介绍,在处理集合操作如UNION ALL时使用
Relids all_baserels;//"base rels"
Relids nullable_baserels;//Nullable-side端的"base rels"
List *join_rel_list;
struct HTAB *join_rel_hash;
List **join_rel_level;
int join_cur_level;
List *init_plans;
List *cte_plan_ids;
List *multiexpr_params;
List *eq_classes;
List *canon_pathkeys;
List *left_join_clauses;
List *right_join_clauses;
List *full_join_clauses;
List *join_info_list;
List *append_rel_list;
List *rowMarks;
List *placeholder_list;
List *fkey_list;
List *query_pathkeys;
List *group_pathkeys;
List *window_pathkeys;
List *distinct_pathkeys;
List *sort_pathkeys;
List *part_schemes;
List *initial_rels;
List *upper_rels[UPPERREL_FINAL + 1];
struct PathTarget *upper_targets[UPPERREL_FINAL + 1];//
List *processed_tlist;//最后需处理的投影列
AttrNumber *grouping_map;
List *minmax_aggs;
MemoryContext planner_cxt;
double total_table_pages;
double tuple_fraction;
double limit_tuples;
Index qual_security_level;
InheritanceKind inhTargetKind;
bool hasJoinRTEs;
bool hasLateralRTEs;
bool hasDeletedRTEs;
bool hasHavingQual;
bool hasPseudoConstantQuals;
bool hasRecursion;
int wt_param_id;
struct Path *non_recursive_path;
Relids curOuterRels;
List *curOuterParams;
void *join_search_private;
bool partColsUpdated;
} PlannerInfo;
二、源码解读
本节介绍query_planner的主流程以及setup_simple_rel_arrays和setup_append_rel_array两个子函数的实现逻辑.
query_planner
RelOptInfo *
query_planner(PlannerInfo *root, List *tlist,
query_pathkeys_callback qp_callback, void *qp_extra)
{
Query *parse = root->parse;//查询树
List *joinlist;
RelOptInfo *final_rel;//结果
Index rti;//RTE的index
double total_pages;//总pages数
if (parse->jointree->fromlist == NIL)//简单SQL,无FROM/WHERE语句
{
final_rel = build_empty_join_rel(root);//创建返回结果
if (root->glob->parallelModeOK)//并行模式?
final_rel->consider_parallel =
is_parallel_safe(root, parse->jointree->quals);
add_path(final_rel, (Path *)
create_result_path(root, final_rel,
final_rel->reltarget,
(List *) parse->jointree->quals));//添加访问路径
set_cheapest(final_rel);//选择最优的访问路径
root->canon_pathkeys = NIL;
(*qp_callback) (root, qp_extra);//回调函数
return final_rel;//返回
}
root->join_rel_list = NIL;//初始化PlannerInfo
root->join_rel_hash = NULL;
root->join_rel_level = NULL;
root->join_cur_level = 0;
root->canon_pathkeys = NIL;
root->left_join_clauses = NIL;
root->right_join_clauses = NIL;
root->full_join_clauses = NIL;
root->join_info_list = NIL;
root->placeholder_list = NIL;
root->fkey_list = NIL;
root->initial_rels = NIL;
setup_simple_rel_arrays(root);//初始化PlannerInfo->simple_rel/rte_array&size
setup_append_rel_array(root);//初始化PlannerInfo->append_rel_array(通过append_rel_list)
add_base_rels_to_query(root, (Node *) parse->jointree);//构建RelOptInfo节点
build_base_rel_tlists(root, tlist);//构建"base rels"的投影列
find_placeholders_in_jointree(root);//处理jointree中的PHI
find_lateral_references(root);//处理jointree中Lateral依赖
joinlist = deconstruct_jointree(root);//重构jointree
reconsider_outer_join_clauses(root);//已创建等价类,那么需要重新考虑被推后处理的外连接表达式
generate_base_implied_equalities(root);//等价类构建后,生成因此外加的约束语句
(*qp_callback) (root, qp_extra);//调用回调函数
fix_placeholder_input_needed_levels(root);//检查在子查询上拉时生成的PH表达式,确保Vars是OK的
joinlist = remove_useless_joins(root, joinlist);//清除无用的外连接
reduce_unique_semijoins(root);//消除半连接
add_placeholders_to_base_rels(root);//在"base rels"中添加PH
create_lateral_join_info(root);//创建Lateral连接信息
match_foreign_keys_to_quals(root);//匹配外键信息
extract_restriction_or_clauses(root);//在OR语句中抽取约束条件
total_pages = 0;
for (rti = 1; rti < root->simple_rel_array_size; rti++)//计算总pages
{
RelOptInfo *brel = root->simple_rel_array[rti];
if (brel == NULL)
continue;
Assert(brel->relid == rti);
if (IS_SIMPLE_REL(brel))
total_pages += (double) brel->pages;
}
root->total_table_pages = total_pages;//赋值
final_rel = make_one_rel(root, joinlist);//执行主要的计划过程
if (!final_rel || !final_rel->cheapest_total_path ||
final_rel->cheapest_total_path->param_info != NULL)
elog(ERROR, "failed to construct the join relation");//检查
return final_rel;//返回结果
}
setup_simple_rel_arrays
初始化setup_simple_rel_arrays(注意:[0]无用)和setup_simple_rel_arrays
void
setup_simple_rel_arrays(PlannerInfo *root)
{
Index rti;
ListCell *lc;
root->simple_rel_array_size = list_length(root->parse->rtable) + 1;
root->simple_rel_array = (RelOptInfo **)
palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
root->simple_rte_array = (RangeTblEntry **)
palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
rti = 1;
foreach(lc, root->parse->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
root->simple_rte_array[rti++] = rte;
}
}
setup_append_rel_array
源码比较简单,读取append_rel_list中的信息初始化append_rel_array
void
setup_append_rel_array(PlannerInfo *root)
{
ListCell *lc;
int size = list_length(root->parse->rtable) + 1;
if (root->append_rel_list == NIL)
{
root->append_rel_array = NULL;
return;
}
root->append_rel_array = (AppendRelInfo **)
palloc0(size * sizeof(AppendRelInfo *));
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
int child_relid = appinfo->child_relid;
Assert(child_relid < size);
if (root->append_rel_array[child_relid])
elog(ERROR, "child relation already exists");
root->append_rel_array[child_relid] = appinfo;
}
}
感谢各位的阅读,以上就是“PostgreSQL中query_planner函数处理逻辑是怎样的”的内容了,经过本文的学习后,相信大家对PostgreSQL中query_planner函数处理逻辑是怎样的这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!