第 24 章 PL/pgSQL - SQL 过程语言
目录
PL/pgSQL 是Postgres数据库系统的一个可装载过程语言。
这个软件包最初由 Jan Wieck 编写。本文档的一部分由
Roberto Mello(<rmello@fslc.usu.edu>)撰写。
24.1. 概述 #
PL/pgSQL 的设计目标是创建一种可装载的过程语言,它
可以用来创建函数和触发器过程,
向SQL语言中增加控制结构,
能执行复杂的计算,
继承所有用户定义的类型、函数和操作符,
可以被定义为服务器所信任,
易于使用。
PL/pgSQL 调用处理器在函数第一次被调用时解析函数的源文本并生成一棵内部二进制指令树。生成的字节码在调用处理器中通过函数的对象 ID 来标识。这确保了通过 DROP/CREATE 序列更改函数会立即生效,而不需要建立新的数据库连接。
对于函数中使用的所有表达式和SQL语句,PL/pgSQL 字节码解释器都会使用SPI管理器的
SPI_prepare()和
SPI_saveplan()函数创建一个预备好的执行计划。这是在该语句第一次在 PL/pgSQL 函数中被处理时完成的。因此,一个包含大量可能需要执行计划的条件语句的函数,只会准备和保存那些在数据库连接生命期内真正被用到的计划。
这意味着你必须小心对待你的用户自定义函数。例如:
CREATE FUNCTION populate() RETURNS INTEGER AS '
DECLARE
-- Declarations
BEGIN
PERFORM my_function();
END;
' LANGUAGE 'plpgsql';
如果你创建上面的函数,它的字节码会引用
my_function()的 OID。之后如果你删除并重建my_function(),那么
populate()将再也无法找到
my_function()。此时你必须重建
populate()。
由于 PL/pgSQL 以这种方式保存执行计划,直接出现在 PL/pgSQL 函数中的查询在每次执行时必须引用相同的表和字段;也就是说,你不能在查询中把参数用作表名或字段名。要绕开这一限制,你可以使用 PL/pgSQL 的 EXECUTE 语句构造动态查询——代价是每次执行都要构造一个新的查询计划。
除了用户定义类型的输入/输出转换和计算函数之外,凡是能用 C 语言函数定义的东西也都可以用 PL/pgSQL 完成。你可以创建复杂条件计算函数,之后用它们来定义操作符,或在函数索引中使用它们。
24.1.1. 使用 PL/pgSQL 的优势 #
更好的性能(参见第 24.1.1.1 节)
SQL 支持(参见第 24.1.1.2 节)
可移植性(参见第 24.1.1.3 节)
24.1.1.1. 更好的性能 #
SQL是 PostgreSQL(以及大多数其他关系数据库)用作查询语言的语言。它可移植且易于学习。但每条 SQL语句都必须由数据库服务器逐条执行。
这意味着你的客户端应用必须把每个查询发送到数据库服务器,等待它处理,接收结果,做一些计算,然后再把其他查询发送给服务器。所有这些都会带来进程间通信开销,而且如果你的客户端与数据库服务器不在同一台机器上,还会带来网络开销。
使用 PL/pgSQL,你可以把一块计算和一系列查询封装在数据库服务器内部,从而既拥有过程语言的能力又拥有 SQL 的易用性,同时因为省去了整个客户端/服务器通信开销而节省大量时间。你的应用将通过使用 PL/pgSQL 获得相当可观的性能提升。
24.1.1.2. SQL 支持 #
PL/pgSQL 把过程语言的能力加到了SQL的灵活和易用之上。使用 PL/pgSQL,你可以使用 SQL 的所有数据类型、列、操作符和函数。
24.1.1.3. 可移植性 #
由于 PL/pgSQL 函数运行在 PostgreSQL 内部,这些函数可以在 PostgreSQL 运行的任何平台上运行。因此你可以重用代码并降低开发成本。
24.1.2. 用 PL/pgSQL 开发 #
用 PL/pgSQL 开发相当直接,尤其是如果你曾经用其他数据库过程语言(例如 Oracle 的 PL/SQL)开发过。用 PL/pgSQL 开发的两个好办法是:
使用文本编辑器并用
psql重新装载文件使用 PostgreSQL 的 GUI 工具:pgaccess
用 PL/pgSQL 开发的一个好办法就是用你喜欢的文本编辑器创建函数,然后在另一个控制台用psql(PostgreSQL
的交互监视器)装载这些函数。如果你采用这种方式(而且如果你是 PL/pgSQL 新手或正处于调试阶段),一个好主意是在创建函数之前总是先DROP它。这样当你重新装载文件时,它会先删除你的函数然后再重建它们。例如:
drop function testfunc(integer);
create function testfunc(integer) return integer as '
....
end;
' language 'plpgsql';
当你第一次装载该文件时,PostgreSQL 会发出一个警告说该函数不存在,然后继续创建它。要把一个 SQL 文件(filename.sql)装载到名为"dbname"的数据库中,使用命令:
psql -f filename.sql dbname
用 PL/pgSQL 开发的另一个好办法是使用 PostgreSQL的 GUI 工具 pgaccess。它会替你做一些好事,比如转义单引号,并且让重建和调试函数变得容易。