当前位置: 首页 > 科技观察

PostgreSQL逻辑优化——这样构建整体架构

时间:2023-03-17 00:45:01 科技观察

完成transform和rewrite操作的查询树是最优查询树吗?如果不是,应该如何优化查询树?用于优化的策略是本文的重点,优化部分也是整个查询引擎的难点。如何优化子链接(SubLink)?子查询(SubQuery)呢?如何优化表达?如何找到最便宜的查询计划(CheapestPlan)?哪些因素会影响JOIN策略(JoinStrategies)的选择,这些策略是什么?查询成本(Cost)是如何预估的?何时具体化查询计划(PlanMaterialization)等一系列问题。在查询计划的优化过程中,针对不同的语句类型采用不同的处理策略:(1)对于工具语句(如DML、DDL语句),不做进一步优化。(2)当语句为非工具语句时,PostgreSQL使用pg_plan_queries对语句进行优化。和之前一样,PostreSQL也提供了自定义优化引擎接口,我们可以使用自定义优化器planner_hook,也可以使用标准化优化器standard_planner。Pg_plan_queries的函数原型如下。逻辑优化——整体架构介绍在不使用第三方提供的优化器的情况下,PostgreSQL使用planner函数作为优化的入口函数,函数subquery_planner完成具体的优化操作。从下图中的CallStack我们可以看出planner和subquery_planner的调用关系。该函数将查询树作为输入参数并返回优化后的语句。在standard_planner中,先处理“DECLARECURSORstmt”形式的语句,即cursor语句,设置tuple_fraction值。那么什么是tuple_fraction?tuple_fraction描述了我们期望获得的元组的比例,0表示我们需要获得所有的元组;当tuple_factionε(0,1)时,表示我们需要从满足条件的元组中取出tuple_faction那么多的元组;当tuple_faction|[1,+¥)时,表示我们将按照指定的元组个数进行查找,例如LIMIT语句中指定的元组个数。完成tuple_faction的设置后,进入后续的优化流程。subquery_planner的函数原型如下。这里你可能会疑惑,为什么是subquery_planner呢?从名字上看,这个函数好像是用来处理子查询的,那为什么要把它作为优化整个查询语句的入口点(PrimaryEntryPoint)呢?作为查询语句的一部分,子查询语句在很大程度上与父查询具有相似的结构。同时,两者在处理方式和方式上也有一定的相似之处:子查询的处理流程可以类比于父查询。过程中使用。例如本例中的子查询语句SELECTsnoFROMstudentWHEREstudent.classno=sub.classno,与整个查询语句的处理方式相同。因此,将subquery_planner作为我们查询优化的切入点,虽然从函数名上看似乎是用来处理子查询语句的。从gram.y中给出的SelectStmt的定义可以看出,其中包括WINDOWS、HAVING、ORDERBY、GROUPBY等子句。那么看来subquery_planner函数也应该有这些语句对应的优化处理。在这方面,subquery_planner类似于原始语法树到查询树的转换处理方式。根据以上分析,我们可以给出subquery_planner的函数原型如下图。根据上面给出的原型,只要完成假设的process_xxx函数,就可以实现查询语法树的优化。你是不是觉得很简单?当然不是,原理很简单,但是理论和实践还是有一定距离的。例如,如何处理查询中大量出现的子链接?你如何对d运算符执行“下推”?如何选择指数?如何选择JOIN策略?这些都需要小心处理。PostgreSQL给出的subquery_planner如下。从PostgreSQL给出的实现可以看出,其核心处理思路与我们所讨论的是一致的:根据查询语句的类型对其进行分类处理。这里要注意的一件事是查询计划的生成。PostgreSQL也将查询计划的生成包含在subquery_planner中,但为了讨论方便,我们不将查询计划的生成包含在subquery_planner中。我们总结查询优化的主要步骤如下:处理CTE表达式,ss_process_ctes;提升子链接,pull_up_sublinks;FROM子句中的内联函数、集合操作、RETURN和函数处理、inline_set_returning_functions;提升子查询,pull_up_subqueries;UNIONALL语句处理,flatten_simple_union_all;处理FORUPDATE(行锁)情况,preprocess_rowmarks;继承表的处理,expand_inherited_tables;处理目标列(目标列表),preprocess_expression;处理withCheckOptions,preprocess_expression;处理RETURN表达式,preprocess_expression;处理条件语句——qual,preprocess_qual_conditions;处理HAVING子句,preprocess_qual_conditions;处理WINDOW子句,preprocess_qual_conditions;处理LIMITOFF子句,preprocess_qual_conditions;WHERE和HAVING子句中的条件合并,如果有HAVING子句可以合并到WHERE条件,否则保留在HAVING子句中;去除外连接(OuterJoin)中的冗余部分,reduce_outer_joins;生成查询计划,grouping_planner。