Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

PREPARE

PREPARE — 准备语句以便执行

概要

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

描述

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

预准备好的语句可以获取参数:在该语句执行时替换为该语句的值。在创建预准备好的语句时,使用位置引用参数,如 $1$2 等。可以根据需要指定相应参数数据类型列表。当参数数据类型未指定或声明为 unknown 时,会根据参数首个引用的上下文判断类型(如果可能的话)。在执行语句时,在 EXECUTE 语句中指定这些参数的实际值。有关此内容的详细信息,请参阅 EXECUTE

预准备好的语句仅在当前数据库会话期间有效。当会话结束时,系统将忘记预准备好的语句,因此必须在再次使用前重新创建该语句。这也意味着单个预准备好的语句不能被多个并发数据库客户端使用;但是,每个客户端都可以创建自己的预准备好的语句使用。可以使用 DEALLOCATE 命令手动清除预准备好的语句。

在使用单个会话执行大量类似语句时,预准备好的语句可能具有最大的性能优势。如果计划语句或重写语句很复杂,例如查询涉及多个表的连接或要求应用多个规则,则性能差异尤其明显。如果计划语句和重写语句相对简单,但执行相对昂贵,则预准备好的语句的性能优势将不那么明显。

参数

name

赋予此特定预准备好的语句的任意名称。它在单个会话中必须是唯一的,并随后用于执行或清除之前准备好的语句。

data_type

预准备好的语句参数的数据类型。如果特定参数的数据类型未指定或指定为 unknown,则会根据参数首个引用的上下文判断类型。要引用预准备好的语句本身中的参数,请使用 $1$2 等。

statement

任何 SELECTINSERTUPDATEDELETEMERGEVALUES 语句。

备注

一个已准备的语句可以用一个 通用计划 或一个 自定义计划 来执行。一个通用计划在所有执行中都是一样的,而自定义计划则是使用给定该调用中参数值的一个特定执行生成的。使用一个通用计划避免了计划开销,但在某些情况下执行自定义计划将更有效,因为规划器利用了参数值。当然,如果准备语句没有参数,那么这是有争议的,总是使用一个通用计划。

默认地(即,当 plan_cache_mode 设置为 auto 时),服务器将自动选择是为带有参数的准备语句使用通用计划还是自定义计划。目前的规则是前五次执行是通过自定义计划完成的,并且计算了这些计划的平均估计成本。然后创建了一个通用计划并将其估计成本与自定义计划平均成本进行比较。后续执行使用通用计划,如果它的开销没有如此高于平均的自定义计划成本以至于使重复重新计划看起来更可取。

可以通过设置 plan_cache_mode 分别为 force_generic_planforce_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 语句还使用与之稍有不同的语法。

另请参阅

DEALLOCATE, EXECUTE