如何让 PostgresQL 优化器在绑定参数之后构建执行计划?
Posted
技术标签:
【中文标题】如何让 PostgresQL 优化器在绑定参数之后构建执行计划?【英文标题】:How to make PostgresQL optimizer to build execution plan AFTER binding parameters? 【发布时间】:2012-09-11 11:09:06 【问题描述】:我正在为 PostgresQL 9.1 开发 Pg/PLSQL 函数。当我在 SQL 查询中使用变量时,优化器会构建一个错误的执行计划。但是,如果我用它的值替换一个变量,那么计划就可以了。 例如:
v_param := 100;
select count(*)
into result
from <some tables>
where <some conditions>
and id = v_param
在 3 秒内完成
和
select count(*)
into result
from <some tables>
where <some conditions>
and id = 100
在 300 毫秒内执行
在第一种情况下,优化器为 v_param 的任何值生成一个固定计划。
在第二种情况下,优化器会根据指定的值生成一个计划,尽管不使用计划缓存,但它的效率要高得多。
是否可以让优化器在不使用动态绑定的情况下生成计划,并且每次执行查询时都生成计划?
【问题讨论】:
【参考方案1】:Tom Lane 在just-released PostgreSQL 9.2 中显着改善了这一点;见What's new in PostgreSQL 9.2 特别是:
Prepared statements 曾经被优化过一次,没有任何知识 的参数值。在 9.2 中,规划器将使用特定的 关于发送参数的计划(查询将计划在 执行),除非查询被执行多次并且 计划员认为通用计划不会贵太多 比具体的计划。
这是一个长期存在且痛苦的疣,以前需要SET enable_...
参数,使用EXECUTE
使用包装函数,或其他丑陋的黑客。现在它应该“正常工作”。
升级。
对于阅读本文的其他人,您可以判断此问题是否困扰您,因为 auto_explain
参数化/准备好的查询计划与您在 explain
自己查询时获得的计划不同。要验证,请尝试PREPARE ... SELECT
然后EXPLAIN EXECUTE
看看您是否有与EXPLAIN SELECT
不同的计划。
另见this prior answer。
【讨论】:
+1 用于在“最新消息”文档中找到一个完美的真实世界示例,该示例可能并未引起所有人的注意。并且几乎可笑地迅速(自 9.2 GA 起不到 24 小时)。 @mdahlman 我对 since Tom implemented it 和 pointing it out for a while 的这个功能感到很兴奋。这是一个很小但很棒的改进,应该有助于在未来透明地解决this 等问题。【参考方案2】:动态查询不使用缓存计划 - 因此您可以在 9.1 及更早版本中使用 EXECUTE USING 语句。正如 Craig 所写,9.2 应该可以在没有这种解决方法的情况下工作。
v_param := 100;
EXECUTE 'select count(*) into result from <some tables> where <some conditions>
and id = $1' USING v_param;
【讨论】:
+1 是一种不需要升级到 9.2 的解决方法。不错。 请注意,这只适用于 PL/PgSQL 函数。普通 SQLEXECUTE
用于调用准备好的语句。我在“使用EXECUTE
的包装函数”中提到了这一点,但应该更具体;谢谢帕维尔。
当然,SQL EXECUTE 和 PL/pgSQL EXECUTE 是两个不同的语句 - 这种技术对于准备好的语句是不可能的,在某些环境中应该是问题 - PostgreSQL 有很好的一次执行功能 PQexecParams,在几乎所有情况下都可以用来代替prepared statements,但它仅在某些接口中可用以上是关于如何让 PostgresQL 优化器在绑定参数之后构建执行计划?的主要内容,如果未能解决你的问题,请参考以下文章