本文主要是介绍PGX:Rust的postgresql扩展开发框架:1何为数据库扩展,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
吃屎的牛对图片支持有问题,如果图挂了,请到我公众号或者知乎专栏去查看:
https://zhuanlan.zhihu.com/p/623058163
数据库的扩展开发
数据库与操作系统、编译器被并称为IT三大基础领域
目前因为开源圈子的风生水起,国产(重音)数据库这个问题基本上是被攻克了……
这里面重点表扬一下达梦,确实是国产之光……其他的嘛:
今天我们不讨论有关战略和形而上学的东西,今天我们来聊一个非常硬核的数据库核心技术问题:数据库的扩展开发。
说道这里,估计有同学马上会跳出来说,虾神你还活在25年前么?会个Crud就敢说核心技术了?难道你不知道对于数据库的Crud Boy已经变成了骂人的话么?说一个码农是Crud boy,就像对一个人在球场上说:——你打球像他
……emmm……好吧,我这里不是想要讲不是其他语言连接到数据库上面进行应用开发,做已经被做成了坤坤的Crud,而是正儿八经的扩展开发:
如何编写直接运行在数据库引擎上的数据库扩展函数。
数据库的两种使用方式
我们都知道,使用数据库一共有两种方式:
- 使用数据库连接API(Database Connectivity),连接到数据库上,然后进行Crud,比如Java的JDBC或者微软推荐的ODBC,这种方式完全把数据库就当成了一个数据存储和查询工具来用,也就是数据库提供啥功能就用啥功能……这是标准的Crud……
- 这种模式的优点就是不用关心数据库底层技术,只需要了解编码用的语言和技术就行,数据库对于crud boy来说,也就是个放数据的地方……
- 缺点也是一样,基本上没有对于数据库底层的理解和使用能力,即数据库提供啥功能你就只能用啥功能,另外你的所有功能都必须运行在编程框架提供的应用基础上,而不是数据库的引擎上。
- 是正统的数据库开发:利用SQL来使用数据库功能,这样就不具体依赖与各种不同的语言与API了,所有的功能直接运行在数据库引擎上,在最贴近数据的地方进行计算。
- 这种模式的优点就是不具体依赖于第三方语言的DBC API,直接在数据库引擎上编写功能,所有的功能都直接运行在数据库引擎上,具有极高的性能。
- 缺点就是数据库官方支持的语言,就是SQL,而SQL作为第四代语言,优点缺点都非常突出,最主要的缺点有缺少标准库、语言不具备复杂多样性的语法规则和能力,无法编写复杂度高的业务逻辑代码等。
而通用的数据库函数,基本上都是以SQL模式进行调用了,下面举个例子:
例如,我们在单位的员工数据里面,需要查询业绩最大的员工,两种不同的模式的做法如下:
如果数据量少的话,两种方法实际上没有多大的差距,但是如果数据量极其巨大,两种方式的差距可能就天差地别了。
第一种方式要从数据库中把所有信息全部获取出来,然后通过总线或者网络传递到第三方APP的业务逻辑中进行处理,无论是对于网络传输和处理服务器的开销,都有很大的压力,而且应用服务器从数据库取到的数据,99%都是无效数据,可以说这是一种非常低效的解决方式;唯一节约只有数据库的CPU资源(但是IO资源还是浪费掉了)
第二种方式,把MAX计算的任务直接交给了数据库引擎,算完之后,直接把结果数据返回给了应用服务器,这样最大限度的节约了IO资源和应用服务器的CPU资源,但是运算的任务是直接放在数据库引擎上的,这样就会使用一部分数据库的计算资源。
所以两种方式在不同的模式下,都有它的优势:
第一种模式看起来很浪费资源,但是如果我们的业务逻辑不仅仅是求一个max,而是一系列比较复杂的迭代运算,要不断的在整份数据中循环、对比、计算,这种复杂的运算如果放在数据库引擎上,会严重影响数据库的性能,所以干脆一次性把所有数据都取到应用服务器上来进行复杂迭代了,反而效果更好。
但是对于我们大部分的应用来说,基本上都是IO密集型的,所以第二种模式在系统编码架构设计中占有绝对多数。所以,其中唯一的限制,就是类似于max这样的数据库函数有多少了……
数据库函数的开发方式之SQL:
数据库函数因为主要执行在数据库的引擎上,所以必须要以数据库引擎能够解析和使用的语言来进行编写开发,一般情况下,都是以SQL语言来进行编写的,如下所示:
正如上图所说的,SQL的能力实在有些弱,我随手一列就能列出一堆很常见一些功能,但是SQL干不干了的:
- 读写文件(╯°Д°)╯︵ ┻━┻ 特么你要数据库读写文件干嘛……为什么不?如果需要快速导入特殊格式的文件呢?)
- 爬虫(╯°Д°)╯︵ ┻━┻ 特么你家数据库直接爬数据啊)
- 发送邮件(╯°Д°)╯︵ ┻━┻ ,特么你家数据库直接发送邮件想干嘛?监控还是偷数据?)
- 加密与解密(╯°Д°)╯︵ ┻━┻ ,特么你家数据库直接加密解密数据么?)
- 解析xml/json/yml/pbf……(╯°Д°)╯︵ ┻━┻ ,特么你家数据库直接解析这些文件干嘛?)
- 自动更新Redis (╯°Д°)╯︵ ┻━┻ ,过分了啊,谁在数据库里面去对redis做更新的?)
- ……
- ……
- ……
先别管这些需求合理不合理,这些功能几乎都是一些在基础开发中可以做,你也可以说,我在应用程序里面就可以做了,为什么要在数据库里面做,我们不在数据库里面去做,是因为不知道数据库可不可以做,也不知道如何在数据库里面做,但凡我们能够在数据库里面做到,那么离开就会打开一个新的世界!
所以,我们需要一种可以很快速、方便编写数据库扩展的方法。
实际上各个厂商都有自己的数据库扩展方法,比如Oracle可以用Java来写他的扩展,而SQL Server可以用C#来写,不过鉴于开源的数据库如Postgresql、MySQL啥的(包括国产数据库),都用的C语言写的,所以大部分数据库在一段时间内,都只能用C语言编写数据库的扩展。
例如Postgresql里面最出名的扩展PostGIS。
要用C来写个数据库扩展,那真心是不容易,如下所示:
一个非常简单的 generate_series 函数,它生成一个给定起止的列表。这样一个简单的功能,如果要用 extension 实现,核心代码大概就要 100 行,还不包括上百行的脚手架代码,这段代码充斥了 SRF,memory context,function context 等一大堆让人不明嚼栗的概念,如果你想要写对,必然要狠狠花上一番功夫。
那么有没有很简单的,让人一看就懂,一学就会,是个人有个手就能学会的数据库扩展开发呢?
继续往下看,这就是我今天要介绍的内容:
PGX 基于Rust的Postgresql扩展开发框架
在正式介绍PGX之前,我们先通过一个简单的例子,来看看用它来写数据库扩展是有多简单,比如要复述上面这个用了100多行的C语言来写的扩展,来创建一个可以生成一个整数序列的数据库扩展函数,在rust里面怎么写呢?
#[pg_extern] fn my_generate_series(start:i64,end:i64,step:i64) ->SetOfIterator<'static, i64>{ SetOfIterator::new((start..=end).step_by(step as usize).into_iter()) }
从代码上看,你几乎不需要有任何与数据库有关的系统知识,只需要编写业务逻辑代码就行,而且Rust的语法逻辑相对C来说,还是比较简单的……只要是个人,有个手就能看懂学会……
先来看看执行效果:
生成0-10的序列:
生成0-20的偶数序列:
然后在来换一个功能,比如我要生成一个随机表格,由name和value组成,name是随机的字符串,value是随机的浮点数,怎么写呢?
代码如下,全部加起来(不算回车的话,只要4行)
#[pg_extern] fn random_values2(num_rows: i32) -> TableIterator<'static, (name!(id,i32),name!(name, String), name!(value, f64))> { let mut rd = thread_rng(); TableIterator::new((1..=num_rows).map(move |i| (i, Alphanumeric.sample_iter(&mut rd).take(8).map(char::from).collect::<String>(), rand::random::<f64>()))) }
执行效果如下:
这个函数可以直接当成一个表格来用:
该有的查询能力,也是具备的:
用一个词来形容,简直就是:
对于还在用C来写扩展的程序员来说,简直就是降维打击……那么这个神奇的pgx到底是怎么用呢?
请听下回分解……
(不是我想中断,是因为写到这里,没纸了……或者墨水用完了……你们一定要相信我……)
这篇关于PGX:Rust的postgresql扩展开发框架:1何为数据库扩展的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!