PostgreSQL 的一大特点是它的可扩展性。我的同事和高级PostgreSQL开发者Ibar在博客上发表了关于开发具有更广泛的功能(包括回调功能)的扩展的博客。在这个博客文章,我试图解决一个完整的新手用户谁从来没有尝试过,但想开发一个简单的函数与业务逻辑。在博客文章的结尾,我想通过执行简单的基准测试来说明函数的轻量级程度,这是可重复的,应该作为最终用户为什么要进行此类开发的有力理由。
通常,PostgreSQL 和扩展开发人员使用 PostgreSQL 源生成。对于新手用户,这可能不需要。相反,为 Linux 发行版提供的开发/开发包就足够了。假设您已经安装了 PostgreSQL,以下步骤可以为您提供所需的其他开发库。
在乌本图/德比亚
$ sudo apt install postgresql-server-dev-11
在 RHEL/CentOS 上
sudo yum install postgresql11-devel
下一步是将 PostgreSQL 二进制路径添加到您的环境中,以确保 pg_config 位于路径中5雷姆;边距顶部: 1.5rem;字体系列:《ITC 章程》;无衬线;字体样式:正常;字体变异连字:正常;字体-变量-大写:正常;字体重: 400;字母间距:正常;孤儿: 2;文本对齐:开始;文本缩进: 0px;文本转换:无;空白:正常;寡妇: 2;字间距: 0px;-webkit-文本-描边宽度:0px;背景色: rgb (255, 255, 255);文字装饰风格:首字母;文本装饰颜色:首字母;”*上述路径可能因环境而异。
请确保在未指定路径的情况下执行 pg_config:
$ pg_config
PostgreSQL 安装为扩展提供了一个构建基础结构,称为 PGXS,因此只需根据已安装的服务器即可构建简单的扩展模块。它自动执行简单服务器扩展模块的常见生成规则。
$ pg_config --pgxs
/usr/lib/postgresql/11/lib/pgxs/src/makefiles/pgxs.mk
现在,让我们创建一个目录来开发。我将开发一个简单的扩展,addme,一个函数,addme,添加两个数字。
$ mkdir addme
现在,我们需要创建一个 Makefile,它生成扩展。幸运的是,我们可以使用所有的PGXS宏。
MODULES = addme
EXTENSION = addme
DATA = addme--0.0.1.sql
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
5雷姆;字体系列:《ITC 章程》;无衬线;字体样式:正常;字体变异连字:正常;字体-变量-大写:正常;字体重: 400;字母间距:正常;孤儿: 2;文本对齐:开始;文本缩进: 0px;文本转换:无;空白:正常;寡妇: 2;字间距: 0px;-webkit-文本-描边宽度:0px;背景色: rgb (255, 255, 255);文字装饰风格:首字母;文本装饰颜色:首字母;”*MODULE 指定不带文件扩展名的共享对象,扩展指定扩展名的名称。DATA 定义安装脚本。名称中指定 _0.0.1 的原因是,我应该与我们在控件文件中指定的版本匹配。
现在,我们需要一个包含以下内容的控制文件 addme.control:
comment = 'Simple number add function'
default_version = '0.0.1'
relocatable = true
module_pathname = '$libdir/addme'
我们可以在 C 中准备函数,这将添加 2 个整数:
#include "postgres.h"
#include "fmgr.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(addme);
Datum
addme(PG_FUNCTION_ARGS)
{
int32 arg1 = PG_GETARG_INT32(0);
int32 arg2 = PG_GETARG_INT32(1);
PG_RETURN_INT32(arg1 + arg2);
}
在此阶段,目录中只有 3 个文件。
$ ls
addme.c addme.control Makefile
现在,我们可以制作文件:
$ make
5雷姆;字体系列:《ITC 章程》;无衬线;字体样式:正常;字体变异连字:正常;字体-变量-大写:正常;字体重: 400;字母间距:正常;孤儿: 2;文本对齐:开始;文本缩进: 0px;文本转换:无;空白:正常;寡妇: 2;字间距: 0px;-webkit-文本-描边宽度:0px;背景色: rgb (255, 255, 255);文字装饰风格:首字母;文本装饰颜色:首字母;”•要安装扩展,我们需要一个包含创建函数的 SQL 文件。此 SQL 文件名应与 Makefile 中 DATA 参数中指定的文件名相同,该参数是 addme_0.0.1.sql。
将以下内容添加到此文件中:
CREATE OR REPLACE FUNCTION
addme(int,int) RETURNS int AS 'MODULE_PATHNAME','addme'
LANGUAGE C STRICT;
并安装扩展:
$ sudo make install
现在,我们可以继续创建扩展并对其进行测试:
postgres=# create extension addme;
CREATE EXTENSION
postgres=# select addme(2,3);
addme
-------
5
(1 row)
与任何函数一样,我们可以在针对多个元数的查询中使用它。
postgres=# select 7||'+'||g||'='||addme(7,g) from generate_series(1,10) as g;
?column?
----------
7+1=8
7+2=9
7+3=10
7+4=11
7+5=12
7+6=13
7+7=14
7+8=15
7+9=16
7+10=17
(10 rows)
性能基准测试
5雷姆;字体系列:《ITC 章程》;无衬线;字体样式:正常;字体变异连字:正常;字体-变量-大写:正常;字体重: 400;字母间距:正常;孤儿: 2;文本对齐:开始;文本缩进: 0px;文本转换:无;空白:正常;寡妇: 2;字间距: 0px;-webkit-文本-描边宽度:0px;背景色: rgb (255, 255, 255);文字装饰风格:首字母;文本装饰颜色:首字母;”*现在了解在扩展中调用 C 函数的性能特征非常重要。为了进行比较,我们有两个选项,如:1. 由 SQL 提供的”+”运算符,如
select 1+2;
2. PLpgSQL 功能如下
CREATE FUNCTION addmepl(a integer, b integer)
RETURNS integer
as $$
BEGIN
return a+b;
END;
$$ LANGUAGE plpgsql;
对于此测试/基准,我将调用函数一百万次!
SQL + 运算符
time psql -c "select floor(random() * (100-1+1) + 1)::int+g from generate_series(1,1000000) as g" > out.txt
C 函数调用
$ time psql -c "select addme(floor(random() * (100-1+1) + 1)::int,g) from generate_series(1,1000000) as g" > out.txt
PL 函数调用
$ time psql -c "select addmepl(floor(random() * (100-1+1) + 1)::int,g) from generate_series(1,1000000) as g" > out
5雷姆;边距顶部: 1.5rem;字体系列:《ITC 章程》;无衬线;字体样式:正常;字体变异连字:正常;字体-变量-大写:正常;字体重: 400;字母间距:正常;孤儿: 2;文本对齐:开始;文本缩进: 0px;文本转换:无;空白:正常;寡妇: 2;字间距: 0px;-webkit-文本-描边宽度:0px;背景色: rgb (255, 255, 255);文字装饰风格:首字母;文本装饰颜色:首字母;”*我已针对每个案例执行过 6 次测试,并列出如下。
测试运行
正如我们所看到的,内置”+”运算符和扩展中的自定义 C 函数的性能所花的时间最少,性能几乎相同。但是 PLpgSQL 函数调用很慢,并且显示相当大的开销。希望这能说明为什么那些大量使用的函数需要编写为本机 C 扩展名。