上一篇我们介绍了查询规划模块的总体流程和预处理部分的源码。查询规划模块再执行完预处理之后,可以进入正式的查询规划处理流程了。
查询规划的主要工作由grouping_planner函数完成。在具体实现的时候,针对postgresql中独有的继承表,程序使用inheritance_planner函数来解决,该函数主要是先将继承表的继承关系变换为非继承表来处理,然后仍然调用的是grouping_planner函数来完成查询规划的工作。
因此,我们说查询规划的主要工作在于grouping_planner函数。本篇的重点也是来解析该函数内部的调用关系和处理流程。
3.查询规划处理
这里大家真的要做好准备,因为grouping_planner函数本身就有将近1000行~
那什么,我们还是先上图吧。有图更清楚,文字太多大家也会晕的。以下是grouping_planner函数的流程图。
grouping_planner函数是生成查询计划树的主要函数。该函数首先要考虑查询计划中是否有集合操作(可通过查询树的setOperation变量来判断)。如果有则需要进行集合操作:遍历setOperation,为其中的每一个子查询生成计划。而对于非集合操作,计划的生成过程如下:
1) 如果查询含有GROUP BY子句,那么就调整其GROUP BY属性的顺序以匹配ORDER BY子句中的属性顺序(如果使用了grouping sets,则需要做进一步的变换,对于grouping sets,可以看这篇文章),这样就可以使用一次排序操作同时实现排序和分组;
2) 调用preprocess_targetlist预处理INSERT、UPDATE、DELETE和FOR UPDATE情况下的目标属性;
3) 计算并确定代表排序需求的路径关键字,按优先级递减排序主要有groupClause、WindowClause,distinctClause和sortClause;
4) 调用query_planner函数为一个基本查询创建路径并获得cheapest_path(代价最低执行路径),再调用get_cheape
