PREPARE

PREPARE-准备要执行的语句

Synopsis

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

Description

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

准备好的语句可以带有参数:执行语句时将替换为语句的值。创建准备好的语句时,请使用$1$2等按位置引用参数。可以选择指定对应的参数数据类型列表。如果未指定参数的数据类型或将其声明为unknown,则从首次使用该参数的上下文(如果可能)中推断出该类型。执行该语句时,请在EXECUTE语句中指定这些参数的实际值。有关此信息,请参阅EXECUTE

准备的语句仅在当前数据库会话期间持续。会话结束时,准备好的语句将被遗忘,因此必须在重新使用之前重新创建它。这也意味着单个准备好的语句不能同时被多个数据库 Client 端使用。但是,每个 Client 端可以创建自己准备好的语句来使用。可以使用DEALLOCATE命令手动清除准备好的语句。

当使用单个会话执行大量相似的语句时,预准备的语句可能具有最大的性能优势。如果语句计划或重写很复杂,例如如果查询涉及多个表的联接或需要应用多个规则。如果该语句的计划和重写相对简单,但执行成本相对较高,则预备语句的性能优势将不太明显。

Parameters

  • name

    • 为此特定的准备好的语句提供的任意名称。它在单个会话中必须是唯一的,并随后用于执行或取消分配先前准备好的语句。
  • data_type

    • 准备好的语句的参数的数据类型。如果未指定特定参数的数据类型或将其指定为unknown,则将从首次使用该参数的上下文中进行推断。要在准备好的语句本身中引用参数,请使用$1$2等。
  • statement

    • 任意SELECTINSERTUPDATEDELETEVALUES语句。

Notes

准备好的语句可以使用通用计划,而不必对每个提供的EXECUTE值进行重新计划。对于没有参数的准备好的语句,这种情况立即发生;否则,只有在五个或更多执行生成的计划平均成本(包括计划间接费用)比通用计划成本估计值昂贵的计划之后,才会发生这种情况。一旦选择了通用计划,它将用于准备好的语句的剩余生命周期。使用EXECUTE值(在许多重复项的列中很少见)可以生成比通用计划便宜得多的自定义计划,即使在增加了计划开销之后,也可能永远不会使用通用计划。

通用计划假定提供给EXECUTE的每个值都是列的不同值之一,并且列值是均匀分布的。例如,如果统计信息记录了三个不同的列值,则通用计划假定列相等性比较将匹配 33%的已处理行。色谱柱统计信息还允许通用计划准确计算唯一色谱柱的选择性。非均匀分布列的比较和不存在值的指定会影响平均计划成本,因此会影响是否以及何时选择通用计划。

要检查 PostgreSQL 用于准备语句的查询计划,请使用EXPLAIN,例如EXPLAIN EXECUTE。如果正在使用通用计划,它将包含参数符号$n,而自定义计划将替换提供的参数值。通用计划中的行估计值反映了为参数计算的选择性。

有关查询计划和 PostgreSQL 为此目的收集的统计信息的更多信息,请参见ANALYZE文档。

尽管准备好的语句的主要目的是避免重复分析和计划语句,但只要语句中使用的数据库对象发生了定义(DDL)更改,PostgreSQL 都会在使用前强制重新分析和重新计划语句自上次使用预处理语句以来。同样,如果search_path的值从一种用法更改为另一种用法,则将使用新的search_path重新解析该语句。 (从 PostgreSQL 9.3 开始,后一种行为是新的.)这些规则在语义上几乎等同于一次又一次地重新提交相同的查询文本,这在语义上几乎等效,但是如果没有更改对象定义,则可以提高性能,特别是如果最佳计划在不同用途之间保持不变。语义对等不完美的情况的一个示例是,如果该语句使用不合格的名称引用一个表,然后在search_path之前出现的模式中创建了一个具有相同名称的新表,则不会自动重新由于语句中使用的对象未更改,因此将进行解析。但是,如果其他一些更改强制重新解析,则在随后的使用中将引用新表。

您可以通过查询pg_prepared_statements系统视图来查看会话中所有可用的准备好的语句。

Examples

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的上下文中推断出它。

Compatibility

SQL 标准包含一个PREPARE语句,但仅用于嵌入式 SQL。此版本的PREPARE语句还使用了一些不同的语法。

See Also

DEALLOCATE, EXECUTE