PREPARE创建一个预备语句。一个预备语句是服务器端的对象, 可以用于优化性能。在执行PREPARE语句的时候,指定的查询被解析、分析、 重写。当随后发出EXECUTE语句的时候,预备语句被规划和执行。 这种分工避免了重复解析分析工作,允许执行计划依赖于所提供的特定的参数值。
预备语句可以接受参数:在它执行的时候替换到查询中的数值。可以在一个预备语句里按照位置来引用参数, 比如$1, $2等。可以指定一个相应的参数数据类型列表。 如果一个参数的数据类型没有被指定或声明为unknown, 那么其类型将根据该参数所使用的实际上下文环境进行推测(如果有可能的话)。当执行该语句的时候, 将在EXECUTE语句中为这些参数指定实际值。参见EXECUTE获取更多信息。
预备语句只是在当前数据库会话的过程中存在。如果客户端退出,那么预备语句就会被遗忘, 因此必须在被重新使用之前重新创建。这也意味着一个预备语句不能被多个数据库客户端同时使用; 但是,每个客户端可以创建它们自己的预备语句来使用。预备语句可以用 DEALLOCATE命令手工清除。
如果一个会话准备用于执行大量类似的查询,那么预备语句可以获得最大限度的性能优势。 如果查询非常复杂,需要复杂的规划或者重写,那么性能差距将更加明显。比如, 如果查询涉及许多表的连接,或者有多种规则要求应用。如果查询的规划和重写相对简单, 而执行起来开销相当大,那么预备语句的性能优势就不那么明显。
给予这个特定的预备语句任意名字。它必须在一个会话中是唯一的, 并且用于执行或者删除一个预备语句。
预备语句的某个参数的数据类型。如果某个参数的数据类型未指定或指定为unknown, 那么将根据该参数使用的上下文环境进行推断。可以使用$1, $2 等等在预备语句内部引用这个参数。
SELECT, INSERT, UPDATE, DELETE, 或 VALUES 语句之一。
如果预备语句执行了足够长的时间,服务器可能最终决定保存并重新使用一个一般的计划, 而不是每次重新计划。如果预备语句没有参数,那么将立即发生; 否则只在一般计划看起来不比依赖于特定参数值的计划昂贵时发生。 典型的,只有查询的性能对提供的特定的参数值相当迟钝时选择一般的计划。
为了查询PostgreSQL用于预备语句的查询计划,使用EXPLAIN。 如果正在使用一个一般的计划,它将包含参数符号$n, 此时定制计划将有代入的当前实际参数的值。
有关查询规划和PostgreSQL为查询优化的目的收集统计的更多信息, 参阅ANALYZE文档。
尽管预备语句的重点是避免重复分析和规划语句,但PostgreSQL 在使用它之前强制重复分析和重复计划语句, 每当在语句中使用的数据库对象自前一次使用预备语句后经历了明确(DDL)的变化时。 还有,如果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的类型。