pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
目录
PL/pgSQL 是一种用于 PostgreSQL 数据库系统的可载入过程语言。 PL/pgSQL 的设计目标是创建一种具备以下特性的 可载入过程语言:
可以用于创建函数和触发器过程,
为 SQL 语言增加控制结构,
可以执行复杂计算,
继承所有用户定义的类型、函数和操作符,
可以定义为被服务器信任,
易于使用。
PL/pgSQL 调用处理器在函数第一次被调用时(在每个 会话内)解析函数的源文本,并生成一棵内部二进制指令树。这棵指令树完整地 翻译了 PL/pgSQL 的语句结构,但函数中使用的 各个 SQL 表达式和 SQL 命令并不会 立即翻译。
当每个表达式和 SQL 命令在函数中第一次被使用时, PL/pgSQL 解释器会创建一个预备执行计划(使用 SPI 管理器的 SPI_prepare 和 SPI_saveplan 函数)。 之后对该表达式或命令的访问会重用这个预备计划。这样,一个包含条件代码、 其中含有许多可能需要执行计划的语句的函数,只会预备并保存那些在数据库 连接的生命周期内真正用到的计划。这可以大大减少为一个 PL/pgSQL 函数中的语句解析和生成执行计划所需 的总时间。一个缺点是,某个特定表达式或命令中的错误可能要到执行到函数的 那一部分时才会被发现。
一旦 PL/pgSQL 为函数中的某个特定命令生成了 执行计划,它就会在数据库连接的生命周期内一直重用该计划。这通常对性能 有利,但如果你动态地更改数据库模式,也可能引发一些问题。例如:
CREATE FUNCTION populate() RETURNS integer AS '
DECLARE
-- declarations
BEGIN
PERFORM my_function();
END;
' LANGUAGE plpgsql;
如果你执行上面的函数,它会在为 PERFORM 语句生成的 执行计划中引用 my_function() 的 OID。之后,如果你 删除并重新创建 my_function(),那么 populate() 将再也找不到 my_function() 了。此时你必须重新创建 populate(),或者至少启动一个新的数据库会话,使它 得以重新编译。避免这一问题的另一种方法是,在更新 my_function() 的定义时使用 CREATE OR REPLACE FUNCTION(函数被“替换”时, 其 OID 不会改变)。
由于 PL/pgSQL 以这种方式保存执行计划,直接 出现在 PL/pgSQL 函数中的 SQL 命令在每次执行时 都必须引用相同的表和列;也就是说,你不能在 SQL 命令中把参数用作表名或 列名。要绕过这一限制,可以用 PL/pgSQL 的 EXECUTE 语句构造动态命令——代价是每次执行都要构造 一个新的执行计划。
PL/pgSQL 的 EXECUTE 语句与 PostgreSQL 服务器支持的 EXECUTE 语句无关。服务器的 EXECUTE 语句不能在 PL/pgSQL 函数中使用(也不需要)。
除了用户定义类型的输入/输出转换和计算函数之外,凡是可以用 C 语言函数 定义的事情,也都可以用 PL/pgSQL 完成。例如, 可以创建复杂条件计算函数,之后用它们定义操作符或在索引表达式中使用。
SQL 是 PostgreSQL(以及大多数其他 关系数据库)用作查询语言的语言。它可移植且易学。但每条 SQL 语句都必须由数据库服务器逐条执行。
这意味着你的客户端应用程序必须把每个查询发送到数据库服务器,等待其 处理,接收结果,做一些计算,然后再向服务器发送其他查询。所有这些都会 产生进程间通信开销;如果你的客户端与数据库服务器不在同一台机器上, 还会产生网络开销。
使用 PL/pgSQL,你可以把一块计算和一系列 查询组合在数据库服务器内部,从而既拥有过程语言的 能力,又拥有 SQL 的易用性,同时因为省去了整个客户端/服务器通信开销而 节省大量时间。这可以带来可观的性能提升。
此外,使用 PL/pgSQL 可以使用 SQL 的所有 数据类型、操作符和函数。
用 PL/pgSQL 编写的函数可以接受服务器支持的 任何标量或数组数据类型作为参数,也可以返回这些类型中任何一种的结果。 它们还可以接受或返回任何按名称指定的复合类型(行类型)。也可以把 PL/pgSQL 函数声明为返回 record, 这表示结果是一个其列由调用查询中的规范确定的行类型,如 第 7.2.1.4 节 所述。
PL/pgSQL 函数还可以声明为接受和返回多态类型 anyelement 和 anyarray。多态函数实际处理的 数据类型可以随调用而变化,如 第 33.2.5 节 所述。示例见 第 37.4.1 节。
PL/pgSQL 函数还可以声明为返回它们能返回 单个实例的任何数据类型的“集合”(即表)。这样的函数通过对结果 集中每个想要的元素执行 RETURN NEXT 来生成输出。
最后,如果 PL/pgSQL 函数没有有用的返回值, 可以声明为返回 void。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。