[pgrx开发postgresql数据库扩展]4.基本计算函数的编写与性能对比

news2024/11/26 4:47:26

前言

再次声明:

并不是所有场景都需要(或者适合)用rust来写的,绝大部分操作数据库的功能和计算,用SQL就已经足够了!

本系列中,所有的案例,仅用于说明pgrx的能力,而并非是说这样做比用SQL更合适。反之:对于操作数据库本身的部分,大部分能用SQL来实现的东西,都比做一个扩展开发要更加合适。

——如果哪位大神写Rust走火入魔,说啥数据库功能都要用Rust来扩展实现的,不报我的名字,你们打成半死就行,报我的名字,请打成八成死。

单值输入与输出函数

这里的单值,是针对序列这种多值类型而言的。

SQL做为第四代语言,与第三代语言最大的区别,就是尽量舍弃了所谓的计算机思维,即for和if。

例如我们在高级语言里面对一批数据要进行查询或者筛选,必须是按照计算机的思维方式来进行:

例如老板说,我们准备找出大于35岁的同学,以向社会进行输送,那么程序员要实现这个想法,就得这样思考和实现问题: 对整个数据集进行一个个的迭代,然后一个个的比较,如果满足条件,就进行社会输出……

for row in dataset:
    if row['age'] > 35:
        row["结果"] = "输送社会"
    else:
        row["结果"] = "在用几年"

但是SQL里面,要实现这个功能,则不会有for和if这类语句:

select * from dataset where age > 35

有正如高级语言要执行,先要被编译器编译成汇编,然后再编译成机器语言再进行执行意义,SQL要执行,实际上也要别数据库引擎编译成汇编指令和机器语言,那么依然可以是可以解读为for和if的。

例如,我们写了这样一个数据库扩展:

#[pg_extern]
fn age_add(age:i32) -> i32 {
    age +1
}

来看看效果,非常直观:

那么在实际使用中,比如要作用于数据库表格上的话,是什么样子呢?

先有这样一张表:

如果我们把自定义的函数作用在这张表上的时候,就是这样的:

可以看见,相当于对于表emps进行逐行的迭代计算,然后得到了结果。

当然,这种功能肯定没必要用扩展这种牛刀杀鸡的做法,直接用SQL就可以了:

下面我们来做一个稍微复杂点的场景:

有如下这样一张表:

这是一个员工信息表有五个字段,分别id,名称、加入公司的时间、生日和工资,一共是20万条记录:我用Python的faker库生成的,当然没来得及去关注入职时间和生日之间的相关关系,里面肯定有没满18岁就参加工作的问题……就不要在意这些细节了。

现在我们要计算一下年终奖金的系数,规则如下:

基数为2,也就是两个月工资,如果在公司超过10年,每年加1.5个点,如果不满10年,则每年1个点,不满一年的按基准算,最后用系数乘以工资,得到最后的奖金。

这个场景在业务编码里面经常见到,虽然很简单,但是包含了多条件判断、时间计算和数学计算等多种计算模型,当然……用SQL本身就很容实现,如下所示:

WITH a AS (
SELECT *,
    CASE
    WHEN date_part('year',age(now(),indate)) >= 10 
        THEN 2 + date_part('year',age(now(),indate))* 0.015

    WHEN date_part('year',age(now(),indate)) <= 1 
        THEN 2

    ELSE 2 + date_part('year',age(now(),indate))* 0.01
    END as xs
FROM tab_emps )
SELECT * ,pay*xs FROM a
LIMIT 10; 

结果如下:

那么我们在扩展函数里面写怎么做呢? (再次强调,仅为说明能力,绝对不是建议大家这种功能小功能也动用扩展函数来牛刀杀鸡)

代码如下:

#[pg_extern]
fn cal_bonus(indate:pgrx::Date,pay:i64) -> f32{
    let now: DateTime<Local> = Local::now();
    let now_epoch = now.timestamp()/60/60/24;
    
    let x = (now_epoch as i32 - indate.to_unix_epoch_days()) / 365 ;
    
    let mut xs:f32=0.0;
    if x >=10{
        xs = 2.0 + x as f32 * 0.015;
    }
    else if x <=1 {
        xs = 2.0;
    }
    else{
        xs = 2.0 + x as f32 * 0.01;
    }
    xs * pay as f32
}

结果如下:

可以看见二者的结果是完全一样的。

性能对比

我们来具体对比一下,使用SQL原生方式和与扩展函数两种方式,在PG上面的执行效率,我们采用EXPLAIN ANALYZE的方式来测试效率:

  1. 对于加1方法的测试:

为了复用建立出来的20万条记录的表格,所以我们需要修改一下方法: 把输入参数从i32改成i64——rust是一种强类型的语言,所以数据库中的integer和bigint是无法通用。

当然,我们也可以用泛型来做,不过既然本教程针对的是初学者,这里我就不用了,以免增加学习负担。

#[pg_extern] fn age_add(age:i64) -> i64 { age +1 }

结果如下:

我们发现,对于20万条数据,用SQL执行加1操作,仅用了23ms,而采用扩展函数,则需要用37ms。

接下去,我们分别测试更新和插入,用两种方法,生成一张新的表格,然后在做一次更新,分别来看看性能:

CREATE AS SELECT的性能:

依然是原生SQL性能更好

然后看看UPDATE的性能:

三个测试的结果如下:

然后我们再来测试一下稍微复杂点的系数与奖金计算:

查询

创建:

更新 (原生SQL的子查询模式更新,实在太慢了,20万条没有执行成功,所以我把数量缩减到了1000条,也有可能是我SQL语句没写对……因为以前没有搞过子查询模式的更新这种东西,如果哪位大神写过,可以联系我……)

而让我感到震惊的是,使用扩展函数编写的更新,对于20万条数据,整体执行的时间如下:

对比如下:

结论

  1. 简单计算和查询,SQL语言比扩展模式性能更好。
  2. 复杂计算和查询,随着数据量的变大,Rust扩展模式越发显示出优势,可能是因为在SQL里面也需要调用底层语言编写的函数,而导致转换间的性能损失吧。
  3. 如果有复杂计算且更新的需求,扩展函数的性能比原生SQL要好太多太多……可能并非是性能,而是运行机制的问题,此结论因为虾神SQL能力不行,所以不可靠。
  4. 不管是原生SQL模式还是扩展函数模式,一定都比DBC(Database Connectivity)模式要强很多很多……

待续未完。

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

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

相关文章

Spring依赖注入(DI配置)

Spring依赖注入 1. 依赖注入方式【重点】1.1 依赖注入的两种方式1.2 setter方式注入问题导入引用类型简单类型 1.3 构造方式注入问题导入引用类型简单类型参数适配【了解】 1.4 依赖注入方式选择 2. 依赖自动装配【理解】问题导入2.1 自动装配概念2.2 自动装配类型依赖自动装配…

ThinkPHP模型操作上

ThinkPHP模型操作上 前言模型一、创建模型二、模型操作 总结 前言 在mvc架构中&#xff0c;模型的解释是写逻辑代码的地方&#xff0c;其实还可以这样理解&#xff0c;就是一串操作写在一个模型类中&#xff0c;就是你要完成某一项功能&#xff0c;将这个功能的代码写在一个mod…

chatgpt能做本地化部署,训练私有化学科领域数据吗?-----模型只在工具之上,想法只在算力范围之内

GPTGLM-6B场景应用&#xff1a; 最近&#xff0c;ChatGPT已经火出圈了&#xff0c;一般OpenAI需要梯子&#xff0c;然后需要花钱&#xff0c;导致很多限制&#xff0c;用的很不方便&#xff08;很希望大厂努力&#xff0c;有国人自己的大语言模型&#xff09;&#xff0c;目前…

Bean 作⽤域和⽣命周期

目录 1.lombok 1.1 1.添加依赖&#xff1a;&#xff08;pom.xml&#xff09; 1.2 在实体类上使用lombok提供的注解 1.3 安装插件 2. Bean 的 6 种作⽤域&#xff08;Scope&#xff09; 2.1 singleton&#xff08;默认模式&#xff09; 2.2 prototype&#xff08;原型模式…

【EasyPoi实战系列】Spring Boot使用EasyPoi的注解让表格更漂亮以及图片的导出 - 第468篇

历史文章&#xff08;文章累计460&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 【…

利用电脑和手机MT4平台软件设置报警功能的方法及步骤

使用MT4&#xff08;MetaTrader 4&#xff09;的报警功能&#xff0c;就可以在汇率达到指定数值&#xff0c;或者是在EA进场买进或结束交易的时候在手机接受推播通知。即使正在外出&#xff0c;也不会因此而错失机会&#xff0c;也可以借此确认进场交易内容&#xff0c;是相当便…

部署CDN的网站如何找真实IP

部署CDN的网站找真实IP 1.概述 目前很多网站使用了cdn服务&#xff0c;用了此服务 可以隐藏服务器的真实IP&#xff0c;加速网站静态文件的访问&#xff0c;而且你请求网站服务时&#xff0c;cdn服务会根据你所在的地区&#xff0c;选择合适的线路给予你访问&#xff0c;由此达…

黑盒测试过程中【测试方法】详解2-正交实验

在黑盒测试过程中&#xff0c;有9种常用的方法&#xff1a;1.等价类划分 2.边界值分析 3.判定表法 4.正交实验法 5.流程图分析 6.因果图法 7.输入域覆盖法 8.输出域覆盖法 9.猜错法 前面我们已经讲解过了等价类划分、边界值、判定表。 可以参考我之前的文章&#xff…

k8s部署Pyroscope并分析golang性能瓶颈

Pyroscope是什么 Pyroscope是一种开源的应用程序性能分析工具&#xff0c;它可以帮助我们发现和解决应用中的性能问题。Pyroscope支持多种编程语言并提供了丰富的性能数据&#xff0c;可以帮助我们跟踪应用程序的执行情况&#xff0c;并根据收集到的数据来识别性能瓶颈。 Pyros…

什么是VBST和PVST?两者有啥区别?

在计算机网络中&#xff0c;VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种将局域网划分为多个逻辑上独立的子网的技术&#xff0c;它可以帮助网络管理员更好地管理网络资源。 在VLAN技术中&#xff0c;STP&#xff08;Spanning Tree P…

Git 如何修改历史的 Commit message

目录 修改最近一条Commit 修改过去若干条 Commit 场景&#xff1a;当分批次多次提交时&#xff0c;突然发现提交的message不符合规范&#xff0c;想要修改&#xff0c;这时就可以使用了 修改最近一条Commit 如果只是想修最近一条 Commit, 直接使用命令: git commit --amen…

基于DistFlow方程求解给定的通用径向单相配电网络的配电功率流方程(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 本文介绍了基于DistFlow方程求解给定的通用径向单相配电网络的配电功率流方程及结果展示。 &#x1f4da;2 运行结果 主函数部…

JVM垃圾回收机制和常见算法

GC回收垃圾流程第一步是定位内存空间中没有引用到的对象&#xff0c;然后才能进行回收。那么GC是如何定位这些内存中没有用到的对象呢&#xff1f; 一、引用计数器算法&#xff08;废弃&#xff09; 引用计数器算法是给每一个对象设置一个计数器&#xff0c;当有地方引用这个对…

Linux入门操作

pwd 查看当前目录 与 自动补全 文件详情 drwxrwxr-x d代表文件夹 -代表文件 其中rwx rwx r-x r是可读 w是可写 x 执行 第一组&#xff08;前三个&#xff09;指文件拥有者的权限 第二组&#xff08;中三个&#xff09;代表文件拥有的组的权限 第三组&#xff08;后三个&am…

5.2.1二叉树的定义和基本术语

二叉树的基本概念&#xff1a; 二叉树是递归定义的二叉树 下面我们来看几个特殊的二叉树&#xff1a; 特点&#xff1a; 1&#xff09;只有最后一层有叶子节点 2&#xff09;不存在度为1的结点 3&#xff09;按层序从1开始编号&#xff0c;结点i的左孩子为2i&#xff0c;右孩…

three.js地图可视化项目-广州模型

概述 如有不明白的可以加QQ&#xff1a;2354528292&#xff1b;wx: aichitudousien 更多教学视频请访问&#xff1a;https://space.bilibili.com/236087412 详细教学请到上方视频链接访问&#xff0c;总共3个多小时的教学~ three.js地图可视化项目-广州模型 搭建开发环境 使用…

Tomcat的概念、部署、及优化

一、Tomcat概述 1、Tomcat的概念 Tomcat是Java语言开发的&#xff0c;服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP程序的首选。一般来说&am…

金陵科技学院五年一贯制专转本旅游学概论考试大纲

金陵科技学院五年一贯制专转本旅游学概论考试大纲 一、考核对象 本课程的考核对象为五年一贯制高职专转本“旅游管理”专业入学考试考生。 二、考核方式 本课程考核采用闭卷笔试的方式。 三、命题依据及原则 1、命题依据 参考书目&#xff1a;《旅游学概论》(第七版) 李…

【Git 入门教程】第一节、什么是Git?

在软件开发中&#xff0c;代码的管理和版本控制非常重要。为了更好地管理代码&#xff0c;需要使用一种有效的工具来保证代码的质量和稳定性。而Git正是这样一种工具。 一、概念 Git是一种分布式版本控制系统&#xff0c;它可以追踪文件的变化&#xff0c;并且可以协同工作。它…

SpringBoot——MyBatis-Plus源码分析及开发实践详解

focus w x&#xff1a;CodingTechWork 文章目录 focus w x&#xff1a;CodingTechWork 引言MyBatis-Plus 介绍概述特点常用注解TableNameTableIdIdType类型 TableField MyBatis-Plus 源码分析IService原生CURD接口savesaveorUpdateremoveupdategetlistpage Mapper原生CURD接口i…