代码地址:postgresql-13.1-ml: Integration of CardEst Methods into PostgreSQL by HTTP Server (github.com)

当前进度:可以支持单表查询的基数估计模块的替换。至于多表join的基数估计模块替换还在开发中

注意:本文的重点在于PG的修改。记录一下我的修改思路。

整体流程

PG作为http客户端,向基数估计服务端发送http请求。内容为需要基数估计的sql语句。

基数估计服务端返回该语句的selectivity。

PG收到该查询的selectivity后乘以当前表的大小,即得到rows

PG原版基数估计调用逻辑

make_one_rel                                        // allpath.c
|-set_base_rel_sizes
|-set_rel_size
|-set_plain_rel_size // allpath.c
|-set_baserel_size_estimates // costsize.c // [单表]
|-clauselist_selectivity // clausesel.c // [单表/JOIN] 接受 CNF 形式的谓词数组(由 AND 连接数组中的各个谓词)
|-statext_clauselist_selectivity // extended_stats.c // [单表/JOIN] 多列统计信息(最优MCV+函数依赖关系),对谓词进行估算
|-dependencies_clauselist_selectivity // dependencies.c // [单表/JOIN] P(a, b) = P(a) * (f + (1-f) * P(b)) 这里 f 即是 (a, b) 之间的函数依赖程度。
|-clauselist_selectivity_simple // clausesel.c // [单表/JOIN] 对剩下的谓词使用单列统计信息进行估算,wrapper,维护区间信息
|-clause_selectivity // clausesel.c // [单表/JOIN] 处理 DNF(由 OR 连接各个谓词),NOT表达式,CNF回到clauselist_selectivity
|-restriction_selectivity // plancat.c // [单表] 当需要为某个操作符计算某类操作的选择率的时候,PostgreSQL通过调用函数管理器,执行存储在过程函数系统表(pg_proc.h)中登记的选择率计算函数。
|-scalarltsel... // selfuncs.c // [单表] 选择率计算函数主要存在selfuncs.c
|-scalarineqsel_wrapper // selfuncs.c // [单表] 判断expr是否是 var op sth. 或者是 sth. op var
|-scalarineqsel // selfuncs.c // [单表] 处理"<", "<=", ">", ">=" 的选择率估计
|-mcv_selectivity // selfuncs.c // [单表] MCV 估计
|-histogram_selectivity // selfuncs.c // [单表] 直方图估计
|-make_rel_from_joinlist // allpath.c // [JOIN] 动态规划
|-standard_join_search // allpath.c // [JOIN] 创建RelOptInfo链表数组存储在root中。root->join_rel_level[1] 存储所有初始表的rel,root->join_rel_level[2]存储所有两张表join的rel...
|-join_search_one_level // joinrel.c // [JOIN] 生成当前level的RelOptInfo, level表示考虑当前的join有level张表。
遍历join_rel_level[level-1](old_rel), 与join_rel_level[1]【左深树】,
优先连接有连接关系的rels或者有连接顺序限制的rels,进入make_rels_by_clause_joins;
对没有连接关系的表或连接顺序限制的表也尝试make, 进入make_rels_by_clauseless_joins
建立【浓密树】。浓密树抛开基表,连接(2, N-2),(3, N-3),(4, N-4)等多种情况。但建立浓密树的rel需要满足两个条件。
两个rel需要有相关的连接条件或者有连接顺序的限制;两个rel代表的表不能有交集。 还有最后的尝试【卡氏积】。
|-make_join_rel // joinrel.c // [JOIN] if 满足建浓密树的条件
|-make_rels_by_clause_joins // joinrel.c // [JOIN] 判断是否可以连接(要求两个连接rel的relids没有重叠),可以连接便make
|-make_join_rel // joinrel.c // [JOIN]
|-make_rels_by_clauseless_joins // joinrel.c // [JOIN] 对没有连接关系的表或连接顺序限制的表也尝试make
|-make_join_rel // joinrel.c //
|-build_join_rel // relnode.c // [JOIN]
|-set_joinrel_size_estimates // costsize.c // [JOIN]
|-calc_joinrel_size_estimate // costsize.c // [JOIN]
|-clauselist_selectivity // clausesel.c // 同上
|-clause_selectivity // clausesel.c // [单表/JOIN] 处理 DNF(由 OR 连接各个谓词),NOT表达式,CNF回到clauselist_selectivity
|-join_selectivity // plancat.c // [JOIN] 当需要为某个操作符计算某类操作的选择率的时候,PostgreSQL通过调用函数管理器,执行存储在过程函数系统表(pg_proc.h)中登记的选择率计算函数。
|-eqjoinsel_inner... // selfuncs.c // [JOIN] 主要是用MCV对join结果集进行估算
|-populate_joinrel_with_paths // joinrel.c // [JOIN] add paths to joinrel (交换rel1和rel2算两个path)
|-try_partitionwise_join // joinrel.c // if enable_partitionwise_join==True; 智能分区联表
|-build_child_join_rel // relnode.c
|-set_joinrel_size_estimates // costsize.c // [JOIN] 同上

修改源码

主要修改代码costsize.c

单表修改set_baserel_size_estimates函数

修改逻辑

其中get_expr函数的逻辑可参考print.c文件中print_expr函数

多表修改set_joinrel_size_estimates函数

待续

添加第三方库

该项目需要其它两个第三方库

将第三方库的头文件和实现文件加入到PG中:

  • 把http.h 添加到 /src/include/utils/下
  • costsize.c 添加 #include "utils/http.h”
  • 把cJSON.h 添加到 /src/include/utils/下
  • 把cJSON.c 添加到 /src/backend/utils/adt/下
  • cJSON.c 把#include "cJSON.h”修改成#include "utils/cJSON.h”
  • 在/src/backend/utils/adt/Makefile添加 cJSON.o \
  • costsize.c 添加 #include "utils/cJSON.h”

效果

单表查询的效果

测试数据集:imdb.title

PG原版计划

imdb=# explain analyze select * from title where kind_id>1 and kind_id<10;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on title (cost=174.01..25746.20 rows=12642 width=306) (actual time=163.325..646.420 rows=1865487 loops=1)
Recheck Cond: ((kind_id > 1) AND (kind_id < 10))
Heap Blocks: exact=35995
-> Bitmap Index Scan on kind_id_title (cost=0.00..170.85 rows=12642 width=0) (actual time=156.207..156.208 rows=1865487 loops=1)
Index Cond: ((kind_id > 1) AND (kind_id < 10))
Planning Time: 1.313 ms
Execution Time: 710.562 ms
(7 rows)

集成learned方法的计划

imdb=# explain analyze select * from title where kind_id>1 and kind_id<10;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on title (cost=0.00..73920.58 rows=1242940 width=94) (actual time=0.037..586.408 rows=1865487 loops=1)
Filter: ((kind_id > 1) AND (kind_id < 10))
Rows Removed by Filter: 662825
Planning Time: 32.463 ms
Execution Time: 656.291 ms
(5 rows)

最优计划

imdb=# explain analyze select * from title where kind_id>1 and kind_id<10;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on title (cost=0.00..73920.58 rows=1865384 width=94) (actual time=0.084..548.721 rows=1865487 loops=1)
Filter: ((kind_id > 1) AND (kind_id < 10))
Rows Removed by Filter: 662825
Planning Time: 4.067 ms
Execution Time: 614.774 ms
(5 rows)

多表查询的效果

待续

待完善

  1. 多表查询的基数估计部分还在开发中
  2. 当前版本只适用于实验环境。尚未对不支持的查询进行过滤。

参考资料

  1. End-to-End-CardEst-Benchmark
  2. VLDBSS2022实验
  3. PostgreSQL 在内核增加一个配置参数
  4. linux下socket(C)构造HTTP客户端
  5. cJSON使用详细教程 | 一个轻量级C语言JSON解析器
  6. cJSON

用HTTP服务的方式集成learned cardinality estimate方法进 Postgresql的更多相关文章

  1. 小D课堂 - 新版本微服务springcloud+Docker教程_4-06 Feign核心源码解读和服务调用方式ribbon和Feign选择

    笔记 6.Feign核心源码解读和服务调用方式ribbon和Feign选择         简介: 讲解Feign核心源码解读和 服务间的调用方式ribbon.feign选择             ...

  2. 在 mac osx 上安装OpenOffice并以服务的方式启动

    OpenOffice是Apache基金会旗下的一款先进的开源办公软件套件,包含文本文档.电子表格.演示文稿.绘图.数据库等.包含Microsoft office所有功能.它不仅可以作为桌面应用供普通用 ...

  3. CAS学习笔记三:SpringBoot自动配置与手动配置过滤器方式集成CAS客户端

    本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式集成CAS客户端. 需要提前搭建 CAS 服务端,参考 https://www.cnblogs.com/hell ...

  4. CAS学习笔记五:SpringBoot自动/手动配置方式集成CAS单点登出

    本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式实现CAS客户端登出及单点登出. 本文基于<CAS学习笔记三:SpringBoot自动/手动配置方式集成C ...

  5. 启动/关闭oracle服务有三种方式

    启动oracle服务有三种方式: 1 从控制面板 2 使用MS-DOS命令 3 通过Oracle Administration Assistant for WindowsNT -通过控制面板启动ora ...

  6. 在Linux上以服务的方式运行ASP.NET Core站点

    更新:用supervisor是更好的解决方法,详见 Linux下为 dotnet 创建守护进程 要在生成环境下在Linux服务器上跑ASP.NET Core站点,首先要解决的问题是以服务的方式运行AS ...

  7. 源码详解openfire保存消息记录_修改服务端方式

    实现openfire消息记录通常有两种方式,修改服务端和添加消息记录插件. 今天,简单的说明一下修改服务端方式实现消息记录保存功能. 实现思路 修改前: 默认的,openfire只提供保存离线记录至o ...

  8. WCF服务部署到IIS上,然后通过web服务引用方式出现错误的解决办法

    本文转载:http://www.cnblogs.com/shenba/archive/2012/01/06/2313932.html 昨天在用IIS部署一个WCF服务时,碰到了如下错误: 理解了文档内 ...

  9. Spring Cloud Alibaba基础教程:支持的几种服务消费方式(RestTemplate、WebClient、Feign)

    通过<Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现>一文的学习,我们已经学会如何使用Nacos来实现服务的注册与发现,同时也介绍如何通过LoadBal ...

随机推荐

  1. 《HALCON数字图像处理》第四章笔记

    目录 第四章 HALCON数据结构 HALCON Image图像 图像通道 HALCON Region区域 Region的初步介绍 Region的点与线 Region的行程 Region的区域特征 H ...

  2. ACM-01背包问题-Python

    日后完善 二维数组实现 if __name__ == '__main__': # 背包空间 space = 10 # 默认第一个元素为 0, 仅仅是为了方便理解 weights = [0, 2, 2, ...

  3. React与Koa一起打造一个仿稀土掘金全栈个人博客(技术篇)

    本篇文章将分为前台角度与后台角度来分析我是怎么开发的.前台角度主要资源 react.js ant Design for-editor axios craco-less immutable react- ...

  4. DBPack 赋能 python 微服务协调分布式事务

    作者:朱晗 中国电子云 什么是分布式事务 事务处理几乎在每一个信息系统中都会涉及,它存在的意义是为了保证系统数据符合期望的,且相互关联的数据之间不会产生矛盾,即数据状态的一致性. 按照数据库的经典理论 ...

  5. 使用阿里云RDS for SQL Server性能洞察优化数据库负载-初识性能洞察

    简介 数据库性能调优通常需要较高数据库水平,并伴随较多的前期准备工作,比如收集各种性能基线.不同种类的性能指标.慢SQL日志等,这通常费时费力且效果一般,当面对多个数据库时总体拥有成本会大幅增加.今天 ...

  6. UiPath选择器之页面选择器的介绍和使用

    一.页面选择器的介绍 某些软件程序的布局和属性节点具有易变的值,例如某些Web应用程序.UiPath Studio无法预测这些变化,因此,您可能必须手动生成一些选择器. 每个属性都有一个分配的值.选择 ...

  7. 初学python常用,python模块安装和卸载的几种方法

    兄弟们常常因为遇到模块不会安装,或者遇到报错就懵了,就很耽误学习进度,今天我们就一次性了解Python几种安装模块的方法~不过~ 实在是懒得看 点击此处找管理员小姐姐手把手教你安装 一.命令提示符窗口 ...

  8. Nacos配置失败(java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance after all server)

    解决: nacos服务器过载,可以删掉nacos文件夹下的data文件夹,重新启动.

  9. Task.Run(), Task.Factory.StartNew() 和 New Task() 的行为不一致分析

    重现 在 .Net5 平台下,创建一个控制台程序,注意控制台程序的Main()方法如下: static async Task Main(string[] args) 方法的主体非常简单,使用Task. ...

  10. 零基础学Java(3)运算符

    运算符 运算符用于连接值.Java提供了一组丰富的算术和逻辑运算符以及数学函数. 算术运算符 在Java中,使用算术运算符+.-.*./表示加.减.乘.除运算.当参与/运算的两个操作数都是整数时,表示 ...