用HTTP服务的方式集成learned cardinality estimate方法进 Postgresql
代码地址: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函数
待续
添加第三方库
该项目需要其它两个第三方库
- C语言的HTTP服务的client端的库,参考项目:linux下socket(C)构造HTTP客户端
- C语言解析json格式的库,参考项目:cJSON
将第三方库的头文件和实现文件加入到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)
多表查询的效果
待续
待完善
- 多表查询的基数估计部分还在开发中
- 当前版本只适用于实验环境。尚未对不支持的查询进行过滤。
参考资料
- End-to-End-CardEst-Benchmark
- VLDBSS2022实验
- PostgreSQL 在内核增加一个配置参数
- linux下socket(C)构造HTTP客户端
- cJSON使用详细教程 | 一个轻量级C语言JSON解析器
- cJSON
用HTTP服务的方式集成learned cardinality estimate方法进 Postgresql的更多相关文章
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-06 Feign核心源码解读和服务调用方式ribbon和Feign选择
笔记 6.Feign核心源码解读和服务调用方式ribbon和Feign选择 简介: 讲解Feign核心源码解读和 服务间的调用方式ribbon.feign选择 ...
- 在 mac osx 上安装OpenOffice并以服务的方式启动
OpenOffice是Apache基金会旗下的一款先进的开源办公软件套件,包含文本文档.电子表格.演示文稿.绘图.数据库等.包含Microsoft office所有功能.它不仅可以作为桌面应用供普通用 ...
- CAS学习笔记三:SpringBoot自动配置与手动配置过滤器方式集成CAS客户端
本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式集成CAS客户端. 需要提前搭建 CAS 服务端,参考 https://www.cnblogs.com/hell ...
- CAS学习笔记五:SpringBoot自动/手动配置方式集成CAS单点登出
本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式实现CAS客户端登出及单点登出. 本文基于<CAS学习笔记三:SpringBoot自动/手动配置方式集成C ...
- 启动/关闭oracle服务有三种方式
启动oracle服务有三种方式: 1 从控制面板 2 使用MS-DOS命令 3 通过Oracle Administration Assistant for WindowsNT -通过控制面板启动ora ...
- 在Linux上以服务的方式运行ASP.NET Core站点
更新:用supervisor是更好的解决方法,详见 Linux下为 dotnet 创建守护进程 要在生成环境下在Linux服务器上跑ASP.NET Core站点,首先要解决的问题是以服务的方式运行AS ...
- 源码详解openfire保存消息记录_修改服务端方式
实现openfire消息记录通常有两种方式,修改服务端和添加消息记录插件. 今天,简单的说明一下修改服务端方式实现消息记录保存功能. 实现思路 修改前: 默认的,openfire只提供保存离线记录至o ...
- WCF服务部署到IIS上,然后通过web服务引用方式出现错误的解决办法
本文转载:http://www.cnblogs.com/shenba/archive/2012/01/06/2313932.html 昨天在用IIS部署一个WCF服务时,碰到了如下错误: 理解了文档内 ...
- Spring Cloud Alibaba基础教程:支持的几种服务消费方式(RestTemplate、WebClient、Feign)
通过<Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现>一文的学习,我们已经学会如何使用Nacos来实现服务的注册与发现,同时也介绍如何通过LoadBal ...
随机推荐
- 「ABC 249Ex」Dye Color
考虑停时定理. 初始势能为 \(\sum \Phi(cnt_i)\),末势能为 \(\Phi(n)\),我们希望构造这样一个 \(\Phi:Z\to Z\) 函数,使得每一次操作期望势能变化量为常数. ...
- 一分钟学会如何自定义小程序轮播图(蜜雪冰城Demo)
最近开发小程序项目用到了轮播图,默认的有点单调,作为后端程序员,研究一番最终实现了.本文会从思路,代码详细介绍,相信读过此文后,不管以后在开发中碰到轮播图还是需要自定义修改其他的样式都可以按这个思路解 ...
- GDB的简单使用一
GDB的简单使用一 一.概念 二.GDB的基本使用方法一 调试前预备知识 获取进程的内核转储 启动gdb调试 1.启动 2.设置断点 3.运行程序 4.显示栈帧 5.显示变量 6.显示寄存器 7.单步 ...
- PHP odbc查询SQL SERVER数据库带有中文时无返回数据
近日遇到一个小麻烦当数据库中有中文字符数据 结果odbc_fetch_array后 我用json_encode怎么也得不到数据页面一片空白 我脑子也一片空白后来才知道sqlserver 没有 UTF- ...
- ElasticSearch7.3学习(三十)----ES7.X SQL新特性解析及使用Java api实现sql功能
一.ES7 sql新特性 1.1 数据准备 创建索引及映射 建立价格.颜色.品牌.售卖日期 四个字段 PUT /tvs PUT /tvs/_mapping { "properties&quo ...
- Nodejs实现图片的上传、压缩预览、定时删除
前言 我们程序员日常都会用到图片压缩,面对这么常用的功能,肯定要尝试实现一番.第一步,node基本配置 这里我们用到的是koa框架,它可是继express框架之后又一个更富有表现力.更健壮的web框架 ...
- sap 调用Http 服务
REPORT ZMJ_GETAPI. DATA: LEN TYPE I, "发送报文长度 LEN_STRING TYPE STRING, URL TYPE STRING, "接口地 ...
- cve_2019_0708_bluekeep漏洞
一.环境说明 kali linux windows 7 sp1 二.cve_2019_0708_bluekeep漏洞利用 msf5 auxiliary(dos/windows/rdp/ms12_020 ...
- UiPath官网认证中文教程
RPA之家公众号:RPA之家 RPA之家官网:http://rpazj.com 斗鱼直播:http://www.douyu.com/rpazj UiPath中文社区QQ群:465630324 RPA& ...
- NC17400 gpa
NC17400 gpa 题目 题目描述 Kanade selected n courses in the university. The academic credit of the i-th cou ...