Greenplum中的过程化编程语言(1)

目录

一、什么是过程化变成语言?

1.1 特殊的过程化变成语言

1.2 创建过程化编程语言

1.3 pg和gp处理PL/lau的差别

二、PL/Python

2.1 简介

2.2 如何创建和运行PL/Python函数

2.3 plpythonu结尾的字符为什么是u

2.3.1 受信任的过程化编程语言

三、类型转换

四、PL/Python函数中的数据共享

五、安装Greenplum数据计算Python包集合


PostgreSQL支持过程化编程语言(Procedural Language),用户可以通过在psql客户端上运行create language(早期版本)或者create extension(PostgreSQL 9.1及以后)命令在一个数据库中创建指定的过程化编程语言。用户可以使用这种语言编写自定义功能的函数(即用户定义的函数,英文缩写为UDF),然后在SQL中执行。

过程化编程语言本质上也可以视为一种扩展,熟悉某种编程语言(比如Python、R、Java等)的开发人员可以调用该语言丰富的开发库来快速实现具有所需功能的函数,同时由于数据库中的数据装载写入和用户的代码执行在一个进程中,计算的性能也得到了保证。PostgreSQL支持多种过程化编程语言,包括官方和非官方的,而Greenplum对其中主流的几种过程化编程语言能够实现无缝使用(编程语法相同)。

一、什么是过程化变成语言?

过程化编程语言是指用户可以使用非C语言的编程语言来编写UDF。对于不同的语言,PostgreSQL/Greenplum需要有不同的嵌入式解释器或者执行器来运行基于这些编程语言的函数。在PostgreSQL/Greenplum中,每种语言的解释器被编译生成动态链接库,在需要的时候被当前会话动态装载。

Greenplum支持PostgreSQL中常见的

  • PL/Python
  • PL/R
  • PL/pgSQL
  • PL/Java
  • PL/Perl

等过程化编程语言,功能和对应的PostgreSQL版本的功能基本一致。

1.1 特殊的过程化变成语言

Greenplum也支持一种特殊的过程化编程语言PL/Container。

PL/Container不是对应于某一种编程语言,而是通过对处理代码容器化,实现和Greenplum集群计算的隔离,使过程化编程语言的计算具有更高安全性,保证了在某些异常情况下Greenplum集群的稳定性,同时在支持多版本的编程语言或者多操作系统方面具有更好的灵活性。

PL/Container当前支持R和Python这两种语言,是因为它们是大数据分析领域中使用最广泛的两种编程语言。

1.2 创建过程化编程语言

  • 在psql会话上运行create extension命令来创建PL/Container语言
  • 其他的过程化编程语言(比如PL/Python、PL/R、PL/Java)暂时还是要通过传统的create language的psql命令来管理

1.3 pg和gp处理PL/lau的差别

相比PostgreSQL,分布式数据库Greenplum可以在所有的机器节点上并行地用过程化编程语言进行查询计算,然后汇总输出,从而满足大数据快速分析处理的需求。如下图

二、PL/Python

2.1 简介

Greenplum PL/Python继承自PostgreSQL PL/Python,因此GreenplumPL/Python也支持PostgreSQL PL/Python中的大部分功能,比如丰富的数据类型支持、各种内置的PL/Python函数、共享数据、内部事务等。极少数的PostgreSQL PL/Python功能Greenplum PL/Python暂不支持,比如触发器(trigger)等。

要在一个数据库上使用PL/Python,首先要在这个数据库上创建对应的过程化编程语言。下面的命令使用Greenplum自带的createlang应用程序在postgres数据库(可以替换为其他数据库。本章后面的例子都以postgres这个数据库为例)创建PL/Python过程化编程语言,只有在完成创建这个步骤以后,才能创建基于Python的函数。

2.2 如何创建和运行PL/Python函数

首先使用createlang创建对应的语言。createlang是一个用C语言实现的应用,它通过连接数据库然后调用createlanguage来创建过程化编程语言。

PL/Python使用的Python解释器是Greenplum自带的,位于目录$GPHOME/ext/python下面,版本为2.7.12。

~]$ createlang plpythonu -d postgres
createlang: language "plpythonu" is already installed in database "postgres"

现在可以创建和运行PL/Python函数了

postgres=# create function pyinc(a integer)returns int as
$$ return a+1 
$$ language plpythonu;
CREATE FUNCTION

postgres=# create table test(a int);
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
CREATE TABLE
postgres=# insert into test values(1),(2),(3);
INSERT 0 3
postgres=# select pyinc(a) from test;
 pyinc 
-------
     2
     4
     3
(3 rows)

在postgres这个数据库上不再需要这个过程化编程语言了,可以通过下面的命令删除。 

 ~]$ droplang plpythonu -d postgres

2.3 plpythonu结尾的字符为什么是u

注意,对于上面命令行中的plpythonu结尾的字符u,你可能会问为什么不直接命名为plpython呢?PL/Python的实现中,在语言名字最后加上一个u,实际上是告诉用户这个PL/Python实现不是一种受信任的过程化编程语言(untrustedlanguage)。出于安全考虑,Greenplum只允许数据库的超级用户启用PL/Python并编写PL/Python函数,普通用户则只能运行PL/Python函数。当然,在非受信任语言名字后面加上一个u字符并不是PostgreSQL或者Greenplum必需的,但是加上后会方便用户快速了解这种语言的安全性属性。

2.3.1 受信任的过程化编程语言

如果一个过程化编程语言是受信任的,意味着具有数据库普通权限的用户也可以创建基于这种语言的函数。从安全角度来说,这意味着函数不能访问数据库机器上的文件系统或者数据库中的敏感数据。通常来说,要实现一个受信任的过程化编程语言,函数的处理代码需要实现一个具有限制特权操作的执行环境(沙盒)。我们说PL/R和PL/Python不是受信任的过程化编程语言,是因为用户的函数通过相应的库函数能轻松地访问这个机器上的文件系统。PL/Java是受信任的过程化编程语言;而PL/Perl语言有点特殊,它拥有plperl和plperlu两种过程化编程语言实现,其中plperl是受信任的,而plperlu是非受信任的。所有的受信任的过程化编程语言有一个共同点,就是其语言解释或者解析实现中都具有沙盒功能。

三、类型转换

在Greenplum中,PL/Python函数定义语法如下:

需要特别注意的是函数入口和出口中Python类型和SQL类型的映射。比如,在入口参数中,SQL中的boolean转换为Python的bool对象,int转换为Python的int对象,数组转换为Python的list,等等;在函数返回的时候,PL/Python也会把Python对象转换为各种SQL类型。我们可以在PostgreSQL的官方文档中看到所有类型的映射细节。以前面提到的pyinc()函数和表test_tbl为例,对于下面的SQL查询,执行器会读取test_tbl中的每个元组中的a那一列,a在test_tbl表中定义为int格式,那么执行器在调用Python解释器来执行pyinc()函数中的Python代码之前,会把a这一列的数据转换成Python的int对象。

postgres=# select pyinc(a) from test;

PL/Python函数也支持set returning函数。可以把set returning函数简单地理解为一个迭代器。函数的一次调用会返回一组数据,最终查询输出会把每一组数据展开或者输出为多行,因此这种函数在性能方面会有一定的优势。

set returning函数例子:

postgres=# create or replace function pyreturnsetofint(num int) returns setof int as $BODY$
postgres$# return [x for x in range(num)]
postgres$# $BODY$ language plpythonu;
CREATE FUNCTION
postgres=# select pyreturnsetofint(10);
 pyreturnsetofint 
------------------
                0
                1
                2
                3
                4
                5
                6
                7
                8
                9
(10 rows)

postgres=# select pyreturnsetofint(6);
 pyreturnsetofint 
------------------
                0
                1
                2
                3
                4
                5
(6 rows)

四、PL/Python函数中的数据共享

PL/Python支持函数级别和会话级别的数据共享,即允许在函数调用时候把一些数据保存在内存,供这个函数调用或者这个会话中的其他函数使用。函数级别的数据共享是通过SD词典实现的,而会话级别的数据共享是通过GD词典实现的。使用这两个词典有时候会大幅提升性能。我们以下面的函数为例解释SD和GD的使用。

postgres=# create function pylog(a integer,b integer) returns double precision as $$
postgres$# import math
postgres$# return math.log(a,b)
postgres$# $$ language plpythonu;
CREATE FUNCTION

postgres=# create table test1(a int,b int);
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table.
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.
CREATE TABLE

postgres=# insert into test1 values(8,2),(64,2);
INSERT 0 2
postgres=# select pylog(a,b) from test1;
       pylog       
-------------------
                 6
                 3

这个函数的功能是对于test2表中的每一行计算一个log函数,其中用到了math这个Python包。Greenplum执行器在处理tbl表的每一行时会运行这个函数,而每次运行都要导入math这个Python包,这样会影响性能。但是如果把函数修改为下面这样: 

postgres=# create or replace function pylog1(a integer,b integer) returns double precision as $$
if 'math' not in GD:
  import math
  GD['math']
return GD['math'].log(a,b)
$$ language plpythonu;
CREATE FUNCTION

由于有了全局词典GD, math包在这个会话中只需一次import操作,后续其他函数也可以继续使用这个词典项。当然,如果不考虑其他函数的使用,这里也可以使用SD词典。SD词典是函数级别的,只能在这个函数的多次调用中被共享使用。下面是一个常用的SD例子(注意,GD是会话级别的,会话中别的函数也可以使用,因此使用的时候要注意安全性)。

在上面这个例子中,我们使用了SPI对一个SQL查询语句预先做计划(Plan),并预先存储,避免每一行都要做计划,通常能显著地提高性能。PL/Python还提供多种级别的信息日志功能函数

  • ❏plpy.debug(msg)
  • ❏plpy.log(msg)
  • ❏plpy.info(msg)
  • ❏plpy.notice(msg)
  • ❏plpy.warning(msg)
  • ❏plpy.error(msg)
  • ❏plpy.fatal(msg)

这些函数的级别定义逻辑和Greenplum代码中广泛使用的信息输出函数elog()的级别定义一样。事实上,这些函数的内部实现就是通过elog()函数来完成的,因此Greenplum中信息日志相关的GUC也适用于这些函数。比如,log_min_messages和client_min_messages分别控制系统日志文件和客户端信息输出级别。注意,plpy.error和plpy.fatal较为特殊,因为这二者会抛出不同的Python异常,而其他函数只是打印日志。PL/Python支持的功能不限于此,比如PL/Python还支持子事务等

五、安装Greenplum数据计算Python包集合

在安装这个Python包之前,要先从Pivotal官网下载这个包,包的格式是Greenplum自定义的gppkg格式。官网目录层级如下

安装命令如下:

gppkg将会在所有节点上安装这些包。注意,在安装这些包后需要用source命令来重新装载环境变量并重启Greenplum集群,这是因为这些Python包放在一个$GPHOME/ext/DataSciencePython/目录下面,所以必须修改PYTHONPATH、LD_LIBRARY_PATH环境变量,以便PL/Python能调用到这些包,而这些环境变量的变动保存在greenplum_path.sh文件中。同样,如果需要卸载的话,也要用source命令重新装载新的环境变量脚本并重启集群。

猜你喜欢

转载自blog.csdn.net/MyySophia/article/details/113832218