概述
在任何数据库中,分析和优化SQL的执行,最重要的工作就是执行计划的解读,而说到执行计划得先了解postgresql的查询执行过程。
PG数据库查询执行流程
1、Main
Main是整个后台的入口,基本上不处理任何逻辑,只是简单的分发处理逻辑。
但是像检查当前用户是否是”root”,还是会做的。因为我们知道,root用户是不能起动PG server的。
2、Postmaster
著名的postmaster 后台进程就是由此代码实现的。这个代码封装了PG所有后台进程的入口。这里为什么只是说“入口”呢,因为实现由各自的代码文件实现。这里不负责。如像checkpoint进程,bgwriter进程,wal writer进程,autovacuum laucner进程,stats collector进程以及archiver进程等。这些进程都是由postmaster fork出来。另外postgres用户进程,vacuum worker进程等也是由postmaster进程负责fork。除此之外,postmaster 还负责监听用户请求,将用户请求从监听端口中接收过来,fork出一个postgres进程,专门负责处理用户SQL语句。
3、postgres
postgres是用户进程,专门负责处理用户请求。也就是通常所说的backend进程。用户终端在上一步postmaster fork出postgres backend进程后,直接与此postgres 进程交互。
无论是后台进程还是backend 进程,都由postmaster来维护。postmaster在全局级别维护了一个数组,为每个进程分配一个slot。
4、Parse statement
postgres进程被fork后,接受用户并处理用户语句。因此这里首先会识别用户所发出的语句。如insert,delete,update,select等DML语句,另外还有如create table,create index等DDL语句。
只是识别语句的类型,并不会做其他任何处理。然后由traffic cop 代码块进行分发。
Postgresql 执行insert、delete、update、select都是通过postgres.c里面的exec_simple_query方法。
5、traffic corp
这步最主要的使用就是根据不同的语句类型分发到不同代码进行处理。所以称作为traffic corp,也就是交通协调疏导的意思。如果是DML语句或者是select 语句,都属于QUERY,进入QUERY处理逻辑。如果是DDL语句,那么属于Utility Command,进入Utility Command处理逻辑。因为DDL与DML的处理逻辑是非常不一样的。
6、Query Rewrite & Generate Path
6.1、进行语法分析,生成语法树
querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0, NULL);
只是简单的产生raw parse tree,这个里面不涉及语义检查。只是做语法扫描。
6.2、语义分析和查询重写
plantree_list = pg_plan_queries(querytree_list,CURSOR_OPT_PARALLEL_OK, NULL);
这里会进行语义分析,会访问数据库中的对像,需要持有锁。这个过程会将简单的一个select 语句拆分成多个部分,将parse tree(语法树)转换成query tree,生成parse tree。如将整个select语句转换成:from 部分,where条件部分,group by 部分,order by 部分以及having 部分等。是任何数据库都需要操作的,并且非常重要的一环。
后面再经过analyze和rewrite,生成query tree,即查询树。查询树的生成需要进行语义检查。这一步会调用optimizer,并根据cost选择一种最优的执行路径。
7、生成执行计划
/*
* Run the portal to completion, and then drop it (and the receiver).
*/
(void) PortalRun(portal,
FETCH_ALL,
true, /* always top level */
true,
receiver,
receiver,
completionTag);
根据上面的query tree产生执行计划和执行树。这部分核心代码在planner.c中,是PG的Query Optimizer。会根据表和索引的统计信息去计算不同路径的可能代价值,最后选出最优者。
8、执行查询
/*
* Run the portal to completion, and then drop it (and the receiver).
*/
(void) PortalRun(portal,
FETCH_ALL,
true, /* always top level */
true,
receiver,
receiver,
completionTag);
执行plan,它会遍历每个节点,以致完成,最后将查询结果返回给客户端。
通过了解pg的查询执行过程,我们可以意识到在做优化时PG执行计划的重要性,后面再单独介绍这块内容,感兴趣的朋友可以关注下!