PostgreSql源码阅读笔记5(参考husthxd在ITPUB的博客)

参考内容

PostgreSQL 源码解读(81)- 查询语句#66(Review - exec_simp…

exec_simple_query:

在这里插入图片描述

参考内容

PostgreSQL 源码解读(82)- 查询语句#67(PortalXXX系列函数)

几种Portal:

PORTAL_ONE_SELECT:

  • 包含一个SELECT查询。按需要的结果重复(递增)地运行执行器,支持可持有游标

PORTAL_ONE_RETURNING:

  • 带有RETURNING子句的INSERT/UPDATE/DELETE查询

PORTAL_ONE_MOD_WITH:

  • 只包含一个SELECT查询,但它具有数据修改的CTEs。

PORTAL_UTIL_SELECT:

  • EXPLAIN或SHOW

PORTAL_MULTI_QUERY:

  • 其它情况 如 create table

在这里插入图片描述
portal相关:create,start,run,drop

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考内容

PostgreSQL 源码解读(83)- 查询语句#68(PortalStart函数)
PostgreSQL 源码解读(84)- 查询语句#69(PortalStart->InitP…
PostgreSQL 源码解读(85)- 查询语句#70(PortalRun->InitPla…

PortalStart -> ExecutorStart -> InitPlan

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考内容

PostgreSQL 源码解读(86)- 查询语句#71(PortalRun->PortalR…

之前有中间保存的结果:创建slot,取元组,向远端发送,关闭远端,清除slot
第一次运行:切换上下文,开始计时,打开接收端,一条条调用plan的执行函数,一条条发送元组,结束计时,切回上下文
在这里插入图片描述

参考内容

PostgreSQL 源码解读(87)- 查询语句#72(PortalRunSelect->E…

seqscan节点的执行:红色为实际执行函数

表达式的计算用统一的入口:ExecEvalExprSwitchContext()
在这里插入图片描述

参考内容

PostgreSQL 源码解读(88)- 查询语句#73(SeqNext函数#1)
PostgreSQL 源码解读(89)- 查询语句#74(SeqNext函数#2)

访问元组的函数对 SeqScan 节点来说是 SeqNext 函数:

在这里插入图片描述

准备工作包括:pin表、计算页数、标记启始页、确定扫描条件、更新统计

在这里插入图片描述
扫描过程包括:获取页,判断元组可见性,判断串行冲突,判断符合扫描条件

在这里插入图片描述

参考内容

PostgreSQL 源码解读(90)- 查询语句#75(ExecHashJoin函数#1)
PostgreSQL 源码解读(91)- 查询语句#76(ExecHashJoin函数#2)

hashjoin的步骤:

  1. 为内循环创建hash表,利用hashvalue低位作为桶号,高位作为batch号,当表大小不够时扩大一倍的hash表,当扩大到超过了内存阈值,就要扩大总batch数(每次也是扩大一倍),将当前batch加入桶中,其它批次的输入到临时文件里。(不同batch相当于有不同的hashvalue)
  2. 外部获取一个batch,对每一条连接内部的元组
  3. 对没连接的外部元组连null内部
  4. 处理完成后,对右连接和全连接还要连null外部

在扩batch数的时候,内部元组马上重新hash,但已经到文件里的元组不会马上hash,而是保留在原来batch中,在join到这一个批次时会重新建这一batch的hash表,这时会把属于后面批次的值hash到后面批次。(内部重hash:**ExecHashJoinNewBatch **,外部重hash:**ExecHashJoin **-> HJ_NEED_NEW_OUTER
在这里插入图片描述
在这里插入图片描述

参考内容

PostgreSQL 源码解读(93)- 查询语句#77(ExecHashJoin函数#3)
PostgreSQL 源码解读(95)- 查询语句#78(ExecHashJoin函数#4-H…
PostgreSQL 源码解读(97)- 查询语句#79(ExecHashJoin函数#5-H…

  • 从文件获取元组时不是每次都读文件,而是一次读满一个buffer的大小,再一条条取
  • 获取列值不是数组或指针方式获取,而是用函数来获取
    在这里插入图片描述
    ExecScanHashBucket 获取桶元组也是两步,从桶数组中获取对应最小元组,并判断是否满足条件,满足就返回

参考内容

PostgreSQL 源码解读(92)- 分区表#1(数据插入路由#1)
PostgreSQL 源码解读(94)- 分区表#2(数据插入路由#2)
PostgreSQL 源码解读(96)- 分区表#3(数据插入路由#3-获取分区键值)
PostgreSQL 源码解读(98)- 分区表#4(数据查询路由#1-“扩展”分区表)
PostgreSQL 源码解读(99)- 分区表#5(数据查询路由#2-RelOptInfo数…
PostgreSQL 源码解读(100)- 分区表#6(数据查询路由#3-prune part…
PostgreSQL 源码解读(101)- 分区表#7(数据查询路由#4-prune part…
PostgreSQL 源码解读(102)- 分区表#8(数据查询路由#5-构建APPEND访问路径)
PostgreSQL 源码解读(103)- 分区表#9(数据查询路由#6-APPEND初始化和实现)

append 表有两种:继承表(分区表)或 UNION ALL 子查询。
hash 值合并函数: a ^= b + UINT64CONST(0x49a0f4dd15e5a8e3) + (a << 54) + (a >> 7);
执行插入时涉及 ExecModifyTable 需要对分区路由
PortalRunMulti
-> ProcessQuery
​ -> ExecutorRun
​ -> ExecutePlan
​ -> ExecProcNode
​ -> ExecModifyTable
​ -> ExecPrepareTupleRouting 分区的路由
在这里插入图片描述

修剪分区发生在限制条件都准备好之后:

subquery_planner
-> grouping_planner
-> query_planner 查询优化
​ -> add_other_rels_to_query 修剪分区表入口
​ -> expand_inherited_rtentry 修剪分区表,创建RTE
​ -> expand_partitioned_rtentry 递归展开所有分区表到 root->append_rel_list 里
在这里插入图片描述
在这里插入图片描述

生成修剪分区步骤的大概过程:

  1. 归约限制条件至最简
  2. 找到限制条件中涉及的列,它们属于那种分区条件
  3. 对每种分区条件生成修剪的步骤
    1. is null 条件:
      • 对列表分区和范围分区可直接生成步骤把非null的分区裁剪掉
      • 对于hash分区,必须所有分区键都涉及is null 条件才裁剪
    2. op 条件:
      • 生成步骤
    3. is not null 条件:
      • 生成步骤,删除 null 分区

在这里插入图片描述

执行裁剪:

裁剪对 hash、列表、范围 用不同策略
在这里插入图片描述

分区表路径生成过程

subquery_planner
-> grouping_planner
-> query_planner 查询优化
​ -> make_one_rel 生成路径
​ -> set_base_rel_pathlists 生成表访问路径
​ -> set_append_rel_pathlist 生成分区表的路径
生成了四种路径

在这里插入图片描述

参考内容

PostgreSQL 源码解读(103)- 分区表#9(数据查询路由#6-APPEND初始化和实现)

append 操作的初始化
在这里插入图片描述
append 操作执行
在这里插入图片描述

参考内容

参见PostgreSQL 源码解读(104)- WAL#1(Insert & WAL-heap_insert函数#1)
参见PostgreSQL 源码解读(105)- WAL#2(Insert & WAL-heap_insert函数#2)

知识点:

WAL:Write after Logging 在数据之前写日志

虽然是先写数据到页缓冲区再写日志,但刷新到磁盘时要先刷新日志,再刷新数据。LSN是日志的最后一条的结束位置,只有日志都写好了才设置LSN。

bootstrap 模式:引导模式,启动模式

插入数据时 heap_insert

先检查串行冲突,再加锁一块表的页缓冲区,插入元组到缓冲区,标记脏块,并记录这个插入日志。最后把这个临时元组标记为无效,并更新页面统计信息

日志内容包括:页头元组头元组内容。(最后要在日志页的头部设置LSN)
在这里插入图片描述

参考内容

参见PostgreSQL 源码解读(106)- WAL#3(Insert & WAL-heap_insert函数#3)
参见PostgreSQL 源码解读(107)- WAL#4(Insert & WAL-heap_insert函数#4)

知识点:

临界区:CritSectionCount

  1. 在处理中断(ProcessClientWriteInterrupt、ProcessInterrupts)时,必须没有数据处于临界区(CritSectionCount != 0),否则直接返回
  2. 创建上下文(MemoryContextCreate)时要求没有数据在临界区(避免内存冲突)
  3. 所有log相关操作(log_newpage_buffer、XLogEnsureRecordSpace、XLogWrite、XactLogAbortRecord、XactLogCommitRecord)要在临界区做(log不可以被中断)
  4. 初始化错误报告(errstart)时,如果在临界区内,则要写到server log里

插入日志底层实现 XLogInsert

由于需不需要备份页数据与Redo的位置有关,所以当Redo位置改变时,要重新判断,重新assemble(红色箭头)

数据包含了四块:记录头部、页上数据(需要备份的话)、原缓冲区数据、实际 logRecord 的数据
在这里插入图片描述

获取与释放锁的过程(下图黄色部分)

获取过程:

  1. 关闭一个信息中断
  2. 获取一次,不成功的话就把自己放在队列,等待信号

释放过程:

  1. 把自己的锁从锁队列里移出来并释放
  2. 收集多个共享锁或一个排他锁
  3. 为它们发送唤醒信号
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值