PostgreSQL作为传统关系型数据,在设计架构上和Oracle非常相似,下图可以带给你直观的了解。
核心进程:
postgres: logger 负责写日志相关进程
postgres: checkpointer checkpoint进程
postgres: background writer 刷数据进程
postgres: walwriter WAL日志进程
postgres: autovacuum launcher vacuum launcher 进程
postgres: stats collector 统计信息进程
postgres: logical replication launcher 逻辑复制launcher进程
- WAL sender process (if Streaming Replication is active)
- WAL receiver process (if Streaming Replication is active)
从描述上可以看出,PostgreSQL是进程模型,尤其要注意每一个客户端连接对应一个后台进程,这也就意味着‘连接’在PostgreSQL里面是非常重要的资源,在之后有会专题来聊连接的问题。
看到这里会有一个疑问,没有连接管理进程,谁来负责建立连接呢? 答案是postgres主进程负责连接的建立和释放,一个肉眼可见的瓶颈点吧?
回到正题,一条查询SQL是怎么执行的呢?
客户端要和数据库建立通信,需要经过连接器,它收到建立连接请求后,postgres主进程会fork出一个子进程来完成SQL执行操作,由客户端发起的SQL经过解析器-->优化器-->执行器等阶段后返回查询结果到客户端。
连接器
PostgreSQL通过postmaster进程监控建立连接请求,核心逻辑是通过fork子进程方式创建连接,创建连接时会做一系列初始化操作,其中InitPostmasterChild中通过宏控制是否启用setsid,建立完连接后进入ClientAuthentication,认证步骤第一步是进行账号来源客户端IP、认证方法检查,以此来决定使用何种方式认证。接下来看一个HBA报错:
HBA配置由$DATADIR/pg_hba.conf文件内容控制,配置好账号访问策略后,以md5认证方式访问数据库,输入密码后,可以愉快的玩耍了。
解析器
解析器会对SQL做语法解析,生成解析树,一个SQL写法不对会直接返回错误。细节可以参考pg_parse_query。
优化器
拿到解析树之后,经过pg_analyze_and_rewrite会对SQL进行分析和重写,在分析阶段会对SQL语义判断,比如列存不存在、有没有跨DB查询、表的别名用的对不对都会在这个阶段做判断,列名不存在SQL错误:
groupby列和查询列不一致报错:
通过重重检查之后,数据库会生成最优的‘执行规划’,它指明SQL应该按照什么样的路径执行。走全表扫描还是用索引,用A索引还是B索引,内部有一套成本估算的方法来评估。
做过Oracle的朋友一定熟悉硬解析、软解析、软软解析,那PostgreSQL的机制是什么呢?
PG12引入plan_cache_mode参数,可以控制解析策略,灵活调整查询计划查询对SQL的影响。
执行器
在SQL真正执行之前,还需要对查询计划做初始化和预检查,主要内部在InitPlan部分,初始化查询计划包括打开文件、访问存储、启动规则管理、权限检查等。常见的权限错误问题如下:
经过上面的步骤,执行器会返回存储上满足条件的数据。
看到这里相信对PostgreSQL内部执行流程有了整体了解,那么下面的SQL会报错吗?
前提:id1是主键、id2和c1是普通列。
select c1,count(*) from t10 where id2=55 group by id1;