PREPARE — 准备执行语句
PREPAREname
[ (data_type
[, ...] ) ] ASstatement
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 EXECUTEname
(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
语句也使用略有不同的语法。
如果您在文档中发现任何不正确的内容、与您对特定功能的体验不符或需要进一步说明,请使用 此表格 报告文档问题。