↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

百科 / SQL 命令 / 游标与预备语句

SQL COMMAND · 游标与预备语句

PREPARE

预备一个语句以供执行

PREPARE游标与预备语句引入 10(基线)现存至 20 devel0 次语法变更

动词
PREPARE
对象
—
引入版本
10(基线)
状态
现存
语法变更次数
0
手册小节数
6

本站手册 · 18官方文档 ↗

版本轨迹

相对 PostgreSQL 17 无变化。

语法铁道图 PostgreSQL 18

沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。

PREPARE name ( data_type , ) AS statement

语法概要

PREPARE name [ ( data_type [, ...] ) ] AS statement

PostgreSQL 18 手册 · 查看完整参考页

描述

PREPARE 创建一个预备语句。预备语句是一种服务器端对象,可用于优化性能。执行 PREPARE 语句时,指定的语句会被解析、分析并重写。随后发出 EXECUTE 命令时,该预备语句会被规划并执行。这种分工避免了重复的解析分析工作,同时又允许执行计划依赖于所提供的特定参数值。

预备语句可以带参数,也就是在执行时会代入语句中的值。创建预备语句时,可以按位置引用参数,例如 $1、$2 等。也可以选择指定相应的参数数据类型列表。如果某个参数的数据类型未指定,或被声明为 unknown,则其类型会从该参数第一次被引用时所在的上下文中推断出来(如果可能)。执行该语句时,需要在 EXECUTE 语句中为这些参数提供实际值。有关详情,参见EXECUTE。

预备语句只在当前数据库会话期间存在。会话结束时,预备语句就会被遗忘,因此再次使用前必须重新创建。这也意味着单个预备语句不能由多个并发的数据库客户端共用;不过,每个客户端都可以创建自己要使用的预备语句。预备语句也可以用DEALLOCATE 命令手工释放。

当单个会话要执行大量相似语句时,预备语句可能带来最大的性能优势。如果语句在规划或重写时比较复杂,例如查询涉及许多表的连接,或者需要应用多条规则,那么这种性能差异会特别明显。如果语句相对容易规划和重写,但执行本身代价较高,则预备语句带来的性能优势就不那么明显。

参数

name

为这个特定预备语句指定的任意名称。它在单个会话内必须唯一,随后用于执行或释放先前已准备的语句。

data_type

预备语句中某个参数的数据类型。如果某个参数的数据类型未指定,或被指定为 unknown,则其类型会从该参数第一次被引用时所在的上下文中推断出来。要在预备语句本身中引用参数,可使用 $1、$2 等。

statement

任何SELECT、INSERT、UPDATE、DELETE、MERGE或VALUES语句。

注解

预备语句既可以用通用计划执行,也可以用自定义计划执行。通用计划在所有执行中都相同,而自定义计划则是针对某次特定执行、根据该次调用给出的参数值生成的。使用通用计划可以避免规划开销,但在某些情况下,自定义计划的执行效率会高得多,因为规划器可以利用参数值信息。(当然,如果预备语句没有参数,这一点就无从谈起,并且总是会使用通用计划。)

默认情况下,也就是当plan_cache_mode设置为 auto 时,服务器会自动为带参数的预备语句选择使用通用计划还是自定义计划。当前规则是:前五次执行使用自定义计划,并计算这些计划的平均估计代价;然后创建一个通用计划,并将其估计代价与自定义计划的平均代价比较。如果通用计划的代价没有比自定义计划的平均代价高到足以让反复重新规划显得更可取的程度,那么后续执行就会使用通用计划。

这种启发式规则可以被覆盖。将 plan_cache_mode 分别设置为 force_generic_plan 或 force_custom_plan,即可强制服务器使用通用计划或自定义计划。如果由于某种原因,通用计划的代价估计严重失真,导致它虽然被选中但实际代价远高于自定义计划,那么这个设置就尤其有用。

要查看 PostgreSQL 为预备语句使用的查询计划,可以使用EXPLAIN,例如:

EXPLAIN EXECUTE name(parameter_values);

如果使用的是通用计划,其中会包含参数符号 $n;而自定义计划则会把提供的参数值代入其中。

有关查询规划以及 PostgreSQL 为此收集的统计信息的更多内容,请参见ANALYZE文档。

尽管预备语句的主要目的在于避免对语句重复进行解析分析和规划,但只要语句中使用的数据库对象自上次使用该预备语句以来发生了定义(DDL)变更,或者它们的规划器统计信息已被更新,PostgreSQL 就会在再次使用前强制重新分析并重新规划该语句。此外,如果search_path的值在两次使用之间发生变化,该语句也会基于新的 search_path 重新解析。(后一种行为是从 PostgreSQL 9.3 开始引入的。)这些规则使得使用预备语句在语义上几乎等同于反复重新提交同一段查询文本,同时在对象定义未改变时仍能获得性能收益,特别是在跨多次使用时最佳计划保持不变的情况下。这种语义等价性并不完全成立。举例来说,如果语句以未限定名引用某个表,随后又在 search_path 中更靠前的某个模式里创建了一个同名新表,那么不会自动触发重新解析,因为语句所使用的对象本身并未改变。不过,如果后来由于其他变更而触发了重新解析,后续使用中引用的就会是这个新表。

可以通过查询pg_prepared_statements 系统视图,查看当前会话中所有可用的预备语句。

示例

为一个INSERT语句创建一个预备语句,然后执行它:

PREPARE fooplan (int, text, bool, numeric) AS
    INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);

为一个SELECT语句创建一个预备语句,然后执行它:

PREPARE usrrptplan (int) AS
    SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid
    AND l.date = $2;
EXECUTE usrrptplan(1, current_date);

在这个示例中,第二个参数的数据类型没有指定,因此会从 $2 的使用上下文中推断出来。

兼容性

SQL 标准包含PREPARE语句,但它只用于嵌入式 SQL。这里的PREPARE语句在语法上也略有不同。

另见

语法演化

相邻大版本之间的差异,新的在前。版本号链接到对应快照。

  1. PostgreSQL 15← 14正文更新

    正文更新
  2. PostgreSQL 14← 13正文更新

    正文更新
  3. PostgreSQL 12← 11正文更新

    正文更新
  4. PostgreSQL 11← 10正文更新

    正文更新

同组命令

命令动词对象版本变动最近变更
CURSORS & PREPARED STATEMENTS游标与预备语句7 条↑
CLOSECLOSE— —
关闭一个游标现存
DEALLOCATEDEALLOCATE— —
释放一个预备语句现存
DECLAREDECLARE— 141 次
定义一个游标现存
EXECUTEEXECUTE— —
执行一个预备语句现存
FETCHFETCH— —
使用游标从查询中检索行现存
MOVEMOVE— —
定位游标现存
PREPAREPREPARE— —
预备一个语句以供执行现存