Postgresql源码(105)分区表剪枝代码分析

news2024/10/5 18:33:36

对于分区表,对于子表的剪枝是保证性能的最重要的手段,优化器在生成Plan的过程中对子表进行了裁剪,本篇对裁剪流程做简要总结。

1 构造数据

CREATE TABLE measurement (
    city_id         int not null,
    logdate         date not null,
    peaktemp        int,
    unitsales       int
) PARTITION BY RANGE (logdate);

CREATE TABLE measurement_y2006m01 PARTITION OF measurement FOR VALUES FROM ('2006-01-01') TO ('2006-02-01');
CREATE TABLE measurement_y2006m02 PARTITION OF measurement FOR VALUES FROM ('2006-02-01') TO ('2006-03-01');
CREATE TABLE measurement_y2006m03 PARTITION OF measurement FOR VALUES FROM ('2006-03-01') TO ('2006-04-01');
CREATE TABLE measurement_y2006m04 PARTITION OF measurement FOR VALUES FROM ('2006-04-01') TO ('2006-05-01');
CREATE TABLE measurement_y2006m05 PARTITION OF measurement FOR VALUES FROM ('2006-05-01') TO ('2006-06-01');

insert into measurement values (1, '2006-01-03', floor(random() * 100), floor(random() * 100));
insert into measurement values (2, '2006-02-04', floor(random() * 100), floor(random() * 100));
insert into measurement values (3, '2006-03-05', floor(random() * 100), floor(random() * 100));
insert into measurement values (4, '2006-03-06', floor(random() * 100), floor(random() * 100));
insert into measurement values (5, '2006-03-07', floor(random() * 100), floor(random() * 100));
insert into measurement values (6, '2006-03-08', floor(random() * 100), floor(random() * 100));
insert into measurement values (7, '2006-04-09', floor(random() * 100), floor(random() * 100));
insert into measurement values (8, '2006-04-10', floor(random() * 100), floor(random() * 100));
insert into measurement values (9, '2006-05-11', floor(random() * 100), floor(random() * 100));
insert into measurement values (10, '2006-05-12', floor(random() * 100), floor(random() * 100));

2 验证SQL

SQL1
这是一条经过裁剪的SQL,只扫描4月分区:

explain select * from measurement where logdate between '2006-04-05' and '2006-04-20';
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Seq Scan on measurement_y2006m04 measurement  (cost=0.00..37.75 rows=9 width=16)
   Filter: ((logdate >= '2006-04-05'::date) AND (logdate <= '2006-04-20'::date))

SQL2
这是一条无法裁剪的SQL,扫描所有月份的分区。

explain select * from measurement where peaktemp between 1 and 10;
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Append  (cost=0.00..188.97 rows=45 width=16)
   ->  Seq Scan on measurement_y2006m01 measurement_1  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m02 measurement_2  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m03 measurement_3  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m04 measurement_4  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m05 measurement_5  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))

3 SQL1分析(可剪枝SQL)

select * from measurement where logdate between '2006-04-05' and '2006-04-20';

3.1 语义分析阶段结果:pg_analyze_and_rewrite_fixedparams

p elog_node_display(LOG, "querytree_list", querytree_list, true)

在这里插入图片描述

在语义分析阶段未剪枝。

3.2 计划生成阶段结果:pg_plan_queries

p elog_node_display(LOG, "plantree_list", plantree_list, true)
在这里插入图片描述

pg_plan_queries
	pg_plan_query
		planner
			standard_planner
				subquery_planner              // 【1】第一步
				fetch_upper_rel               // 【2】第二步
				get_cheapest_fractional_path  // 【3】第三步
				create_plan                   // 【4】第四步

第一步到第四步的输出结果(除了最右面的图用来对比,其他都是当前可剪枝SQL的):
请添加图片描述

3.2.1 剪枝发生在subquery_planner

【1】subquery_planner函数中:PlannerInfo初始状态

在这里插入图片描述

【2】subquery_planner函数中:进入grouping_planner前都没有剪枝
subquery_planner
	foreach(l, parse->rtable)
		switch (rte->rtekind)
			case RTE_RELATION:
				if (rte->inh)
					rte->inh = has_subclass(rte->relid);   // 确认当前父表存在子表!去pg_class查relhassubclass字段
	...
	...
	grouping_planner  // 进入前

在这里插入图片描述

【3】prune_append_rel_partitions函数开始剪枝!
query_planner
	...
	...
	add_other_rels_to_query
		/* If it's marked as inheritable, look for children. */
		if (rte->inh)
			expand_inherited_rtentry	
				expand_partitioned_rtentry
					PartitionDirectoryLookup
						relinfo->live_parts = live_parts = prune_append_rel_partitions(relinfo);
	

剪枝函数:prune_append_rel_partitions
剪枝后只有一个分区:relinfo->live_parts = {nwords = 1, words = 0x173e4c0}
剪枝依据:relinfo:
在这里插入图片描述

  1. prune_append_rel_partitions构造裁剪步骤steps调用get_matching_partitions
  2. get_matching_partitions收到steps:三步(between产生两个比较,和一个固定的combine)
prune_append_rel_partitions
	get_matching_partitions(&context, pruning_steps);    // 收到pruning_steps

pruning_steps:
	{step = {type = T_PartitionPruneStepOp, step_id = 0}, opstrategy = 2, exprs = 0x172cfe0, cmpfns = 0x172cf88, nullkeys = 0x0}
		exprs = Const
		cmpfns = 1092 date_cmp
	{step = {type = T_PartitionPruneStepOp, step_id = 1}, opstrategy = 4, exprs = 0x172d1f0, cmpfns = 0x172d198, nullkeys = 0x0}
		exprs = Const
		cmpfns = 1092 date_cmp
	{step = {type = T_PartitionPruneStepCombine, step_id = 2}, combineOp = PARTPRUNE_COMBINE_INTERSECT, source_stepids = 0x172d350}
		source_stepids = {0, 1}
	

get_matching_partitions 处理上面steps,产生结果:results[]

PruneStepResult = {bound_offsets = 0x172d558, scan_default = false, scan_null = false}
	bound_offsets = Bitmapset{0001 1111}
PruneStepResult = {bound_offsets = 0x172d5a8, scan_default = false, scan_null = false}
	bound_offsets = Bitmapset{0111 0000}
PruneStepResult = {bound_offsets = 0x172d5f8, scan_default = false, scan_null = false}
	bound_offsets = Bitmapset{0001 0000}   // 只存了4

expand_partitioned_rtentry函数中,使用4找到4-1=3号子表:

expand_partitioned_rtentry
	while ((i = bms_next_member(live_parts, i)) >= 0)
		Oid                     childOID = partdesc->oids[i];    // i = 3 找到3号子表

剪枝流程完成,后续细节不再展开。

3.3 执行阶段

按照裁剪计划数执行,只扫描4月表measurement_y2006m04

explain select * from measurement where logdate between '2006-04-05' and '2006-04-20';
                                    QUERY PLAN                                    
----------------------------------------------------------------------------------
 Seq Scan on measurement_y2006m04 measurement  (cost=0.00..37.75 rows=9 width=16)
   Filter: ((logdate >= '2006-04-05'::date) AND (logdate <= '2006-04-20'::date))

4 SQL2分析(无法裁剪)

select * from measurement where peaktemp between 1 and 10;

4.1 计划生成阶段

p elog_node_display(LOG, "plantree_list", plantree_list, true)
在这里插入图片描述

4.2 执行阶段

按照计划数执行会自动把所有子表扫一遍。

explain select * from measurement where peaktemp between 1 and 10;
                                        QUERY PLAN                                        
------------------------------------------------------------------------------------------
 Append  (cost=0.00..188.97 rows=45 width=16)
   ->  Seq Scan on measurement_y2006m01 measurement_1  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m02 measurement_2  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m03 measurement_3  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m04 measurement_4  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))
   ->  Seq Scan on measurement_y2006m05 measurement_5  (cost=0.00..37.75 rows=9 width=16)
         Filter: ((peaktemp >= 1) AND (peaktemp <= 10))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633550.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电子科技大学 数学专业-功不唐捐,玉汝于成

电子科技大学 数学专业 功不唐捐&#xff0c;玉汝于成 1.本科背景 本科是坐落于湖南湘潭的湖南科技大学&#xff0c;专业为网络工程专业&#xff0c;因热爱数学专业&#xff0c;所以决定跨考数学专业。 本科专业课平均成绩85&#xff0c;排名10/104。CET 4 474分&#xff0c;…

【动态规划专栏】-- 01 背包问题 -- 动态规划经典题型

目录 背包问题概述 01 背包问题 01背包⭐⭐ 【算法原理】 第一问 第二问 C 算法代码 复杂度分析 【空间优化 - 滚动数组】 C 算法代码 复杂度分析 分割等和子集⭐⭐ 【算法原理】 对于类01背包问题 C 算法代码 【空间优化 - 滚动数组】 C 算法代码 目标和…

利用宝塔搭建个人博客:简单而高效的教程

前言 宝塔面板是一款服务器管理软件&#xff0c;支持windows和linux系统&#xff0c;可以通过Web端轻松管理服务器&#xff0c;提升运维效率。 例如&#xff1a;创建管理网站、FTP、数据库&#xff0c;拥有可视化文件管理器&#xff0c;可视化软件管理器&#xff0c;可视化CP…

[C++]异常笔记

我不怕练过一万种腿法的对手,就怕将一种腿法 练一万次的对手。 什么是C的异常 在C中&#xff0c;异常处理通常使用try-catch块来实现。try块用于包含可能会抛出异常的代码&#xff0c;而catch块用于捕获并处理异常。当异常被抛出时&#xff0c;程序会跳过try块中未执行…

Redis6之简介与安装

目录 一、NoSQL NoSQL 特点 使用场景 二、Redis介绍 简介 特性 使用场景 三、Redis安装 1、下载 2、安装 3、启动、停止 4、补充 四、key键操作 一、NoSQL NoSQL 非关系型数据库&#xff1b;存储原理非常简单(典型的数据类型为k-v),不存在繁杂的关系链&#xff…

LabVIEW与Space Wire配合开发

LabVIEW与Space Wire配合开发 Space Wire是欧洲航天局开发的一种高速、点对点、全双工的串行总线网络&#xff0c;以IEEE1355-1995和LVDS 两个商业标准为基础&#xff0c;汲取了1394技术、ATM技术、以太网技术的优点&#xff0c;同时考虑了空间应用的特点&#xff0c;在故障检…

10 - 守护进程深度分析

---- 整理自狄泰软件唐佐林老师课程 查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;Linux系统编程训练营 - 目录 文章目录 1. 会话与终端的关联1.1 思考1.2 新会话关联控制终端的方法1.3 一些相关推论1.4 一些想法1.5 编程实验&#xff1a;会话与终端 2. 守护进程…

RK android13编译环境搭建与常用编译命令

RK android13编译环境搭建与常用编译命令 1 使用清华的源1.1 备份sources.list1.2 用下面的内容替换/etc/apt/sources.list里面的内容1.3 更新源 2 安装编译环境3 常用编译命令3.1 设置项目的编译命令&#xff0c;环境变量3.1 编译所有模块3.2 编译android3.2 编译kernel3.3 编…

linux驱动学习2-pinctrl子系统和gpio子系统

pinctrl子系统 pinctrl 子系统主要用于管理芯片的引脚。 iomuxc节点介绍 首先我们在/ebf-buster-linux/arch/arm/boot/dts/imx6ull.dtsi 文件中查找 iomuxc 节点&#xff0c;可以看到如下定义 iomuxc: iomuxc20e0000 {compatible "fsl,imx6ul-iomuxc";reg <…

【软件环境安装部署】Linux服务器下 Docker 安装 MongoDB 以及 SpringBoot 整合 MongoDB 开发使用

文章目录 安装测试 MongoDB拉取镜像创建和启动容器登录mongo容器&#xff0c;并进入到【admin】数据库创建一个用户&#xff0c;mongo 默认没有用户连接mongo数据库测试数据库&#xff0c;插入一条语句测试数据库&#xff0c;查询刚才插入的语句查看所有数据库开放指定端口navi…

【状态估计】基于线性卡尔曼滤波器和粒子滤波器无人机估计地形高度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

python基础----11-----闭包、装饰器、单例、工厂、多线程、socket、正则表达式、递归

一 闭包 闭包&#xff1a;通过封装一个函数&#xff0c; 该函数内部又封装一个函数用于返回&#xff0c;使得得到一个无法直接修改值的临时变量&#xff0c;只能通过函数调用修改。闭包的作用&#xff1a;代替全局变量&#xff0c;避免全局变量的滥用。闭包的优缺点&#xff1…

华为荣耀系列uniapp无法USB连接手机调试问题解决方案汇总

华为荣耀系列是一个异常奇葩的手机&#xff0c;经常出现无法调试的问题。 目前我整理出一套完整的切实多次测试可行的解决方案。 一、打开手机的关于手机 设置里面-一直快速点击版本号&#xff0c;连续点10几下。 此时处于开发者模式。 二、打开开发者选项 1、打开开发者…

搭建一个定制版New Bing吧

项目介绍 项目地址&#xff1a;https://github.com/adams549659584/go-proxy-bingai 引用项目简介&#xff1a;用 Vue3 和 Go 搭建的微软 New Bing 演示站点&#xff0c;拥有一致的 UI 体验&#xff0c;支持 ChatGPT 提示词&#xff0c;国内可用&#xff0c;国内可用&#xff…

功能安全开发学习实践心得-概念篇

【写在前面】 记录功能安全开发学习&实践过程中遇到的坎&#xff0c;此篇为概念&#xff08;即行业/标准术语&#xff09;的梳理。实践过程中发现不清楚概念&#xff0c;交流即没法进行&#xff0c;反之&#xff0c;理清概念的过程&#xff0c;即是把整个开发过程串联的过…

50、基于51单片机NRF24l01无线寻物跟踪儿童防丢器系统(程序+原理图+PCB图+设计资料+参考论文+开题报告+元器件清单等)

摘 要 正现代城市生活节奏越来越快,在城市中生活的人们,由于工作、家庭、个人发展、孩子教育、职场竞争等诸多原因,大脑时刻处于紧张状态,容易产生紧张和焦虑情绪,生活压力也越来越大。长期处于这样的状态中,会导致记忆力下降、注意力不集中、容易丢三落四,比如人们常常会记不…

『DevOpse最佳实践』使用Jenkins和Harbor进行持续集成和交付的解决方案

&#x1f4e3;读完这篇文章里你能收获到 全文采用图文形式讲解学会使用Harbor配置项目学会在Jenkins中配置Harbor推送权限使用Jenkins和Harbor进行持续集成的实践感谢点赞收藏&#xff0c;避免下次找不到~ 文章目录 一、准备工作1. 环境准备2. 修改Docker配置文件3. Docker登陆…

Netty实战(十一)

预置的ChannelHandler和编解码器&#xff08;一&#xff09;HTTP和SSL/TLS的添加和使用 一、SSL和TLS添加二、基于Netty的HTTP程序2.1 HTTP解码器、编码器和编解码器2.2 聚合HTTP消息2.3 HTTP压缩 一、SSL和TLS添加 作为一个通讯框架&#xff0c;通讯数据的安全性也是不可或缺的…

LVS+KeepAlived集群

LVSKeepAlived集群 一.KeepAlived的原理 1.1基于什么协议 KeepAlived基于VRRP热备份协议# VRRP协议号112# VRRP组播地址224.0.0.18# VRRP通告报文的TTL值必须是2551.2如何选举Master 1&#xff09;初始化时根据state判断master和backup。 2&#xff09;最终根据优先级决定m…

【小沐学Python】Python实现在线电子书(Sphinx + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建测试工程4、项目文件结构5、编译为本地文件6、编译为http服务7、更改样式主题8、支持markdown9、修改文档显示结构10、项目托管到github11、部署到ReadtheDocs结语 1、简介 Sphinx 是一个 文档生成器 &#xff0c;您也可以把它看成一种工具&…