本节Review standard_planner函数的实现逻辑,该函数查询优化器的主入口。
一、源码解读
standard_planner函数由exec_simple_query->pg_plan_queries->pg_plan_query->planner函数调用,其调用栈如下:
(gdb) b planner
Breakpoint 1 at 0x7c7442: file planner.c, line 259.
(gdb) c
Continuing.
Breakpoint 1, planner (parse=0x2eee0b0, cursorOptions=256, boundParams=0x0) at planner.c:259
259 if (planner_hook)
(gdb) bt
#0 planner (parse=0x2eee0b0, cursorOptions=256, boundParams=0x0) at planner.c:259
#1 0x00000000008c5824 in pg_plan_query (querytree=0x2eee0b0, cursorOptions=256, boundParams=0x0) at postgres.c:809
#2 0x00000000008c595d in pg_plan_queries (querytrees=0x2f10ac8, cursorOptions=256, boundParams=0x0) at postgres.c:875
#3 0x00000000008c5c35 in exec_simple_query (query_string=0x2eed1a8 "select * from t1;") at postgres.c:1050
#4 0x00000000008ca0f8 in PostgresMain (argc=1, argv=0x2f16cb8, dbname=0x2f16b20 "testdb", username=0x2ee9d48 "xdb")
at postgres.c:4159
#5 0x0000000000825880 in BackendRun (port=0x2f0eb00) at postmaster.c:4361
#6 0x0000000000824fe4 in BackendStartup (port=0x2f0eb00) at postmaster.c:4033
#7 0x0000000000821371 in ServerLoop () at postmaster.c:1706
#8 0x0000000000820c09 in PostmasterMain (argc=1, argv=0x2ee7d00) at postmaster.c:1379
#9 0x0000000000747ea7 in main (argc=1, argv=0x2ee7d00) at main.c:228
该函数根据输入的查询树(Query)生成已规划的语句,可用于执行器实际执行.
PlannedStmt *
planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt *result;
if (planner_hook)//钩子函数
result = (*planner_hook) (parse, cursorOptions, boundParams);
else
result = standard_planner(parse, cursorOptions, boundParams);
return result;
}
PlannedStmt *
standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)//标准优化过程
{
PlannedStmt *result;//返回结果
PlannerGlobal *glob;//全局的Plan信息-Global information for planning/optimization
double tuple_fraction;//
PlannerInfo *root;//每个Query的Plan信息-Per-query information for planning/optimization
RelOptInfo *final_rel;//Plan中的每个Relation信息-Per-relation information for planning/optimization
Path *best_path;//最优路径
Plan *top_plan;//最上层的Plan
ListCell *lp,//临时变量
*lr;
glob = makeNode(PlannerGlobal);//构建PlannerGlobal
//初始化参数
glob->boundParams = boundParams;
glob->subplans = NIL;
glob->subroots = NIL;
glob->rewindPlanIDs = NULL;
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
glob->nonleafResultRelations = NIL;
glob->rootResultRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->paramExecTypes = NIL;
glob->lastPHId = 0;
glob->lastRowMarkId = 0;
glob->lastPlanNodeId = 0;
glob->transientPlan = false;
glob->dependsOnRole = false;
if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
IsUnderPostmaster &&
parse->commandType == CMD_SELECT &&
!parse->hasModifyingCTE &&
max_parallel_workers_per_gather > 0 &&
!IsParallelWorker() &&
!IsolationIsSerializable())//并行模式的判断
{
glob->maxParallelHazard = max_parallel_hazard(parse);
glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
}
else
{
glob->maxParallelHazard = PROPARALLEL_UNSAFE;
glob->parallelModeOK = false;
}
glob->parallelModeNeeded = glob->parallelModeOK &&
(force_parallel_mode != FORCE_PARALLEL_OFF);
//确定扫描比例
if (cursorOptions & CURSOR_OPT_FAST_PLAN)
{
tuple_fraction = cursor_tuple_fraction;//使用GUC 参数
if (tuple_fraction >= 1.0)
tuple_fraction = 0.0;
else if (tuple_fraction <= 0.0)
tuple_fraction = 1e-10;
}
else
{
//默认假设:需要所有元组
tuple_fraction = 0.0;
}
//主规划过程入口(可能会递归执行)
root = subquery_planner(glob, parse, NULL,
false, tuple_fraction);//获取PlannerInfo根节点
//选择最优路径并把该路径转换为执行计划
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);//获取顶层的RelOptInfo
best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);//选择最佳路径
top_plan = create_plan(root, best_path);//生成执行计划
if (cursorOptions & CURSOR_OPT_SCROLL)
{
if (!ExecSupportsBackwardScan(top_plan))
top_plan = materialize_finished_plan(top_plan);
}
if (force_parallel_mode != FORCE_PARALLEL_OFF && top_plan->parallel_safe)
{
Gather *gather = makeNode(Gather);
gather->plan.initPlan = top_plan->initPlan;
top_plan->initPlan = NIL;
gather->plan.targetlist = top_plan->targetlist;
gather->plan.qual = NIL;
gather->plan.lefttree = top_plan;
gather->plan.righttree = NULL;
gather->num_workers = 1;
gather->single_copy = true;
gather->invisible = (force_parallel_mode == FORCE_PARALLEL_REGRESS);
gather->rescan_param = -1;
gather->plan.startup_cost = top_plan->startup_cost +
parallel_setup_cost;
gather->plan.total_cost = top_plan->total_cost +
parallel_setup_cost + parallel_tuple_cost * top_plan->plan_rows;
gather->plan.plan_rows = top_plan->plan_rows;
gather->plan.plan_width = top_plan->plan_width;
gather->plan.parallel_aware = false;
gather->plan.parallel_safe = false;
//使用并行模式
root->glob->parallelModeNeeded = true;
top_plan = &gather->plan;
}
if (glob->paramExecTypes != NIL)
{
Assert(list_length(glob->subplans) == list_length(glob->subroots));
forboth(lp, glob->subplans, lr, glob->subroots)
{
Plan *subplan = (Plan *) lfirst(lp);
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
SS_finalize_plan(subroot, subplan);
}
SS_finalize_plan(root, top_plan);
}
//最后的清理工作
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
Assert(glob->nonleafResultRelations == NIL);
Assert(glob->rootResultRelations == NIL);
top_plan = set_plan_references(root, top_plan);
Assert(list_length(glob->subplans) == list_length(glob->subroots));
forboth(lp, glob->subplans, lr, glob->subroots)
{
Plan *subplan = (Plan *) lfirst(lp);
PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
lfirst(lp) = set_plan_references(subroot, subplan);
}
//构建PlannedStmt结构
result = makeNode(PlannedStmt);
result->commandType = parse->commandType;//命令类型
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->dependsOnRole = glob->dependsOnRole;
result->parallelModeNeeded = glob->parallelModeNeeded;
result->planTree = top_plan;//执行计划(这是后续执行SQL使用到的最重要的地方)
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
result->nonleafResultRelations = glob->nonleafResultRelations;
result->rootResultRelations = glob->rootResultRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
result->relationOids = glob->relationOids;
result->invalItems = glob->invalItems;
result->paramExecTypes = glob->paramExecTypes;
result->utilityStmt = parse->utilityStmt;
result->stmt_location = parse->stmt_location;
result->stmt_len = parse->stmt_len;
result->jitFlags = PGJIT_NONE;
if (jit_enabled && jit_above_cost >= 0 &&
top_plan->total_cost > jit_above_cost)
{
result->jitFlags |= PGJIT_PERFORM;
if (jit_optimize_above_cost >= 0 &&
top_plan->total_cost > jit_optimize_above_cost)
result->jitFlags |= PGJIT_OPT3;
if (jit_inline_above_cost >= 0 &&
top_plan->total_cost > jit_inline_above_cost)
result->jitFlags |= PGJIT_INLINE;
if (jit_expressions)
result->jitFlags |= PGJIT_EXPR;
if (jit_tuple_deforming)
result->jitFlags |= PGJIT_DEFORM;
}
return result;
}
pg_plan_queries&pg_plan_query
List *
pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams)
{
List *stmt_list = NIL;
ListCell *query_list;
foreach(query_list, querytrees)
{
Query *query = lfirst_node(Query, query_list);
PlannedStmt *stmt;
if (query->commandType == CMD_UTILITY)
{
stmt = makeNode(PlannedStmt);
stmt->commandType = CMD_UTILITY;
stmt->canSetTag = query->canSetTag;
stmt->utilityStmt = query->utilityStmt;
stmt->stmt_location = query->stmt_location;
stmt->stmt_len = query->stmt_len;
}
else
{
stmt = pg_plan_query(query, cursorOptions, boundParams);
}
stmt_list = lappend(stmt_list, stmt);
}
return stmt_list;
}
PlannedStmt *
pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt *plan;
if (querytree->commandType == CMD_UTILITY)
return NULL;
Assert(ActiveSnapshotSet());
TRACE_POSTGRESQL_QUERY_PLAN_START();
if (log_planner_stats)
ResetUsage();
plan = planner(querytree, cursorOptions, boundParams);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
#ifdef COPY_PARSE_PLAN_TREES
{
PlannedStmt *new_plan = copyObject(plan);
#ifdef NOT_USED
if (!equal(new_plan, plan))
elog(WARNING, "copyObject() failed to produce an equal plan tree");
else
#endif
plan = new_plan;
}
#endif
#ifdef WRITE_READ_PARSE_PLAN_TREES
{
char *str;
PlannedStmt *new_plan;
str = nodeToString(plan);
new_plan = stringToNodeWithLocations(str);
pfree(str);
#ifdef NOT_USED
if (!equal(new_plan, plan))
elog(WARNING, "outfuncs/readfuncs failed to produce an equal plan tree");
else
#endif
plan = new_plan;
}
#endif
if (Debug_print_plan)
elog_node_display(LOG, "plan", plan, Debug_pretty_print);
TRACE_POSTGRESQL_QUERY_PLAN_DONE();
return plan;
}
二、参考资料
allpaths.c
PG Document:Query Planning
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756
相关文章
发现更多好内容- 如何在 Java 中实现对正方形的缩放操作?(如何在Java中对正方形进行缩放操作)
- 如何正确使用 Java 的 join 方法?(java join方法怎么使用)
- Java 中 DecimalFormat 在哪些场景下使用较为合适?(Java DecimalFormat在哪里使用合适)
- 如何确保Redis客户端的安全性:实用技巧与最佳实践
- 在 JavaScript 中如何使用 parentNode?(javascript中的parentNode怎么用)
- 如何高效编码 Java Supplier 接口?(java supplier接口的高效编码技巧)
- 如何进行 Java NoSQL 查询优化?(java nosql查询优化怎样进行)
- Java 中 `equals()` 的核心究竟是什么?(java eques的核心是什么)
- Java代理模式的优缺点分别有哪些?(Java代理模式有哪些优缺点)
- 2024下半年北京软考成绩复查时间及流程
猜你喜欢
AI推送时光机PostgreSQL 源码解读(17)- 查询语句#2(查询优化基础)
数据库2024-04-02
PostgreSQL 源码解读(42)- 查询语句#27(等价类)
数据库2024-04-02
咦!没有更多了?去看看其它编程学习网 内容吧