代码地址: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. CF Divan and Kostomuksha

    题意:NKOJ CF 思路:首先发现贪心不了.因此dp.然后这题需要维护的就\(g_i\)和\(sum{g_i}\) 状态:\(dp[i]\): 当前最后一个为\(g_i\)的最大值 \(dp[i]= ...

  2. 制造企业信息化时代,SaaS系统下沉,移动端上升

    这个时代,我们是不是有很多岗位一定是要在电脑前面完成?如果我们让部分岗位的办公室人员离开电脑,让他们通过移动端来完成工作,这又会产生出一个什么样的变化?是否意味着可以有更多的时间在一线生产制造现场,从 ...

  3. 33个非常实用的JavaScript一行代码

    33个非常实用的JavaScript一行代码 一.日期处理 1. 检察日期是否有效 该方法用于检测给出的日期是否有效: const isDateValid = (...val) => !Numb ...

  4. bare Git 仓库是什么?

    背景 今天,坐我旁边的同事问我一些关于服务器上命令的问题.其中有一个用了特殊参数的 git init 的命令,我也不认识,遂去 Google... bare Git 仓库 定义 A bare Git ...

  5. 【FAQ】运动健康服务REST API接口使用过程中常见问题和解决方法总结

    华为运动健康服务(HUAWEI Health Kit)为三方生态应用提供了REST API接口,通过其接口可访问数据库,为用户提供运动健康类数据服务.在实际的集成过程中,开发者们可能会遇到各种问题,这 ...

  6. 『忘了再学』Shell基础 — 29、AWK内置变量

    目录 1.AWK内置变量 2.练习说明 (1)$n变量练习 (2)FS变量练习 (3)NF变量和NR变量练习 3.总结: 1.AWK内置变量 AWK内置变量如下表: awk内置变量 作用 $0 代表目 ...

  7. vivo大规模 Kubernetes 集群自动化运维实践

    作者:vivo 互联网服务器团队-Zhang Rong 一.背景 随着vivo业务迁移到K8s的增长,我们需要将K8s部署到多个数据中心.如何高效.可靠的在数据中心管理多个大规模的K8s集群是我们面临 ...

  8. 攻防世界pwn题:实时数据检测

    0x00:查看文件 一个32位的文件,canary.NX.PIE保护机制均关闭. 0x01:用IDA进行静态分析 程序很简单,输入一串字符(个数限制:512),然后再输出.最后根据key变量进行条件语 ...

  9. 一些好用的javascript/typescript方法封装分享

    1.数字格式化 JS版-直接写到原型链上 /** * @author: silencetea * @name: * @description: 数字格式化,默认每三位用英文逗号分隔 * @param ...

  10. element ui 自定义主题失败(primordials is not defined)

    卸载: 1.卸载cnpm npm uninstall cnpm -g 2.卸载vue-cli npm uninstall @vue/cli -g 3.卸载nodejs和删除文件 C:\Program ...