本文只是逻辑上的概览,并没有太过深入的设计细节的描述,对应的postgresql 的代码版本是 REL_12_2

1. DML 语句入口

如何搭建 gdb 调试pg 源代码环境,可以参考:利用GDB 快速阅读 postgresql 内核源代码

  1. 启动pg 数据库:
    ./bin/pg_ctl -D /home/zhg/pgsql/pgsql/data -l logfile restart
  2. 启动 psql, ./bin/psql testdb testdb 是我已经创建好的数据库,且已经创建好了一个测试表
  3. 重开一个新的终端,gdb attach -p pid 参考 上文链接,需要连接到 [local] idle 进程,并设置好源码目录
  4. 在psql 终端输入 查询语句 select * from a; ,此时即可在 gdb 终端进行调试。

刚进入之后整个 pg 的函数栈如下,主要是利用epoll 来处理 客户端的链接。

2. 执行链路

在主进程的 PostgresMain 函数中处理来自 psql 交互终端的请求(此时还没有办法确认是一个查询请求):

gdb 不断得next执行,最终会通过 exec_simple_query(query_string) 函数进入输入命令的处理阶段。

进入之后的主要的执行步骤 以及其对应的函数 有如下几个:

  1. start_xact_command 开启事务,写入事务标记,创建快照并入栈。

  2. pg_parse_query 根据输入的 命令字符串 进行 SQL 词法和语法解析,主要目的是解析出DML 命令(一个输入可能有多个 DML 命令),最后以链表的形式返回解析结果。实现代码是在 src/backend/parser/gram.y 中。

  3. 接下来都是在链表内部 循环执行每一个指令

    利用gdb 我们能够很清晰得看到 parsetree_list 中的内容,可以看到在我们输入的 select * from a; 这个语句中,解析出来的链表长度只有1,也就是只有一个 DML 指令,同时指令的 statement 内容是 T_SelectStmt 类型。

  4. 创建快照 并入栈 PushActiveSnapshot (解析+优化时需要创建快照),在 pg_analyze_and_rewrite(): 解析器

  5. 会生成执行计划(优化器的逻辑都在里面): pg_plan_queries ,移除快照PopActiveSnapshot。最终 优化器会对 DML 语句生成执行计划。

  6. 执行器的 执行逻辑部分:
    CreatePortal() --> PortalDefineQuery() --> PortalStart() --> PortalSetResultFormat() --> PortalRun() --> PortalDrop()
    基本链路如下图:

  7. finish_xact_command() 提交事务,主要是 commit部分,会写wal (redo类型 的一种持久化文件,因为 DML 是 select 语句,其实不需要,这里的链路主要是在 inert/update 时会写 WAL)。

3. 执行器的详细逻辑

这里着重主要介绍 上文中的第六步,也就是执行器的逻辑。
执行器的入口通过 Portal 展开,主要的几个变量如下:

  1. Portal : 表示可以执行的 或者 正在执行的状态信息,包括前面优化器生成的执行计划。
  2. Estate : 保存执行器的工作状态
  3. TupleTableSlot : 保存元组数据的 数据结构。

执行器的大体逻辑包括:

  • CreatePortal, 创建 Portal 变量(构造 Portal 变量),作为执行计划的载体
  • PortalStart, 初始化DML 对应DML 语句在底层存储引擎侧的执行逻辑,比如 select * from table; 对应的 Portal 策略是 PORTAL_ONE_SELECT,其底层默认是 heap表引擎,会将heap 表引擎底层的执行 查找逻辑的函数交给 Portal 变量内部的 PlanState 的一个 函数指成员。
  • PortalRun,执行计划,底层存储引擎的数据读取会通过上一步初始化好的函数进行。
  • PortalDrop,执行完成,清理对应执行过程中pin主的资源,以及触发一些插件的执行逻辑。

这主要的几个入口逻辑 以及后续的执行链路基本如下:

在后续我们靠近存储引擎侧的入口部分,比如在PortalStart 调用栈中,因为我们的执行计划 Plan 在 select * from table; 这个语句下的 类型是 T_SeqScan

gdb能够看到,Plan 的类型


这个时候会根据 Plan 的类型来选择对应的执行函数,如下图,根据 T_SeqScan 选择了 ExecInitSeqScan

将选择好的具体执行DML的函数 赋值给 PlanState 中ExecProcNode 回调函数变量,其他的DML 语句生成的执行计划的执行类型 也会根据类型初始化为各自的 ExecProcNode

4. 总结

从代码层面来看 sql 语句的执行链路,能够完整看到一条语句如何 被pg 解析,经过优化器 到达执行器,在执行器内部通过什么样的方式去和底层的 heap 引擎进行交互。

以上的代码执行逻辑同样适用于 其他的 DML 语句(INSERT, UPDATE, DELETE等),只是底层生成执行计划时的引擎访问函数就有差异了。

当然,这个DML 语句的执行链路都是在 PG 的 主逻辑中,但是 postgres 进程还会有一些非常重要的子进程:

  • checkpointer,写heap 表引擎的时候只是将 insert语句 插入的数据,生成了可以写入的 heap tuple放在内存中的 buffer中,后续落盘会通过 checkpointer 进行落盘。(数据的ACD 特性是通过 REDO log 保证的,前面 第二节主体执行链路中提到的 start_xact_commandfinish_xact_command 中的redo 写入的逻辑)。
  • autovacuum 主要是用来进行 GC heap表引擎 支持MVCC 引入的多版本,当然还有一些索引 之类的多版本清理。
  • logical replication 用来做 主从复制的。
  • walwriter 专门负责 调度写 前面说到的 redo log 的。
  • stats collector,采集pg 内部的 stats 信息。

一条 Select 语句 在 Postgresql 中的执行链路相关推荐

  1. 一文搞懂select语句在MySQL中的执行流程!

    MySQL作为互联网行业使用最多的关系型数据库之一,与其免费.开源的特性是密不可分的.然而,很多小伙伴工作了很多年,只知道使用MySQL进行CRUD操作,这也导致很多小伙伴工作多年后,想跳槽进入大厂, ...

  2. 一条sql语句在mysql中如何执行的

    文心阁小说本篇文章会分析下一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL ...

  3. 原来select语句在MySQL中是这样执行的!看完又涨见识了!这回我要碾压面试官!

    大家好,我是冰河~~ MySQL作为互联网行业使用最多的关系型数据库之一,与其免费.开源的特性是密不可分的.然而,很多小伙伴工作了很多年,只知道使用MySQL进行CRUD操作,这也导致很多小伙伴工作多 ...

  4. 用一条sql语句删除表中所相同记录

    用一条sql语句删除表中所相同记录如下一.具有主键的情况 a.具有唯一性的字段id(为唯一主键) delete table where id not in ( select max(id) from ...

  5. 一条SQL语句在MySQL中是如何执行的

    来源:http://t.cn/E6U9Z9T 概览 本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的. 一.mysql架 ...

  6. 一条SQL语句查询数据库中的所有表、存储过程、触发器

    一条SQL语句查询数据库中的所有表.存储过程.触发器 (sysobjects表信息)   该条语句查询返回所有的用户表 select * from sysobjects where xtype='u' ...

  7. MySQL实战 | 01 当执行一条 select 语句时,MySQL 到底做了啥?

    原文链接:当执行一条 select 语句时,MySQL 到底做了啥? 也许,你也跟我一样,在遇到数据库问题时,总时茫然失措,想重启解决问题,又怕导致数据丢失,更怕重启失败,影响业务. 就算重启成功了, ...

  8. PostgreSQL中的执行计划

    PostgreSQL中的执行计划 EXPLAN 预生成执行计划 EXPLAN sql 真实执行计划 explan analyze sql 输出详细内容 explan(analyze on, timin ...

  9. mysql中,一条select语句是如何执行的?

    接下来通过语句弄明白整个Select语句的内部运行状态: 连接器: Mysql>mysql -uroot -p 你首先连接到这个数据库上:链接器负责跟客户端建立连接,获取权限,维持和管理连接 ● ...

最新文章

  1. 我的第一份工作是个小公司
  2. Eclipse开发struts完全指南
  3. 曙光计算机系统,曙光1000大规模并行计算机系统
  4. 2010.9.29 今日问题
  5. Spring中BeanPostProcessor
  6. 电脑 你离我有多远!
  7. java中下拉框select和单选按钮的回显操作
  8. 【图像去噪】基于matlab中值+均值+高斯+Laplacian+Sobel+Prewitt图像去噪【含Matlab源码 025期】
  9. 解决Android studio在虚拟机上可以正常运行,而在手机上闪退的问题
  10. 淘宝手淘搜索怎么做?大神导航,一个神奇的网站,从此开启大神之路!
  11. 产品需求文档模板,不用找了(附“简”例)【转】
  12. MFC制作的入坑级别管理系统
  13. 计数排序CountingSort
  14. C/C++中的逻辑右移和算术右移
  15. 全球响应,维谛技术(Vertiv)助力EPC企业出海“加速度”
  16. 红帽Linux重置root密码
  17. 为什么需要稀疏编码及解释
  18. 【全网最全最细】青龙面板搭配Ninja+依赖+Ninja配置的超细讲解教程!!!
  19. 移动技术开创互联网奇迹
  20. Bash shell语言学习

热门文章

  1. wordpress企业网站主题仿制02-wordpress企业网站首页的仿制
  2. linux sh文件格式,SH文件扩展名 - 什么是.sh以及如何打开? - ReviverSoft
  3. win如何卸载cuda8
  4. Node.js v0.10.31API手册-Addons插件
  5. 超鸿蒙混希夷的翻译,对《愚溪诗序》一处译文的思考
  6. Sql Server利器sql prompt
  7. The Shawshank Redemption-2
  8. RHCS基本理論(台湾人写的不错的文章)
  9. Mobius反演学习
  10. Excel导出模板加数据时,下拉框丢失解决方案