Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make PostgresQL optimizer to build execution plan AFTER binding parameters?

I'm developing Pg/PLSQL function for PostgresQL 9.1. When I use variables in a SQL query, optimizer build a bad execution plan. But if I replace a variable by its value the plan is ok. For instance:

v_param := 100;
select count(*)
  into result
  from <some tables>
 where <some conditions>
       and id = v_param

performed in 3s

and

select count(*)
  into result
  from <some tables>
 where <some conditions>
       and id = 100

performed in 300ms

In first case optimizer generate a fixed plan for any value of v_param.

In second case optimizer generate a plan based on specified value and it's significantly more efficient despite not using plan caching.

Is it possible to make optimizer to generate plan without dynamic binding and generate a plan every time when I execute the query?

like image 760
a.oberon Avatar asked Dec 26 '22 18:12

a.oberon


2 Answers

This has been dramatically improved by Tom Lane in the just-released PostgreSQL 9.2; see What's new in PostgreSQL 9.2 particularly:

Prepared statements used to be optimized once, without any knowledge of the parameters' values. With 9.2, the planner will use specific plans regarding to the parameters sent (the query will be planned at execution), except if the query is executed several times and the planner decides that the generic plan is not too much more expensive than the specific plans.

This has been a long-standing and painful wart that's previously required SET enable_... params, the use of wrapper functions using EXECUTE, or other ugly hacks. Now it should "just work".

Upgrade.

For anyone else reading this, you can tell if this problem is biting you because auto_explain plans of parameterised / prepared queries will differ from those you get when you explain the query yourself. To verify, try PREPARE ... SELECT then EXPLAIN EXECUTE and see if you get a different plan to EXPLAIN SELECT.

See also this prior answer.

like image 87
Craig Ringer Avatar answered Dec 29 '22 12:12

Craig Ringer


Dynamic queries doesn't use cached plans - so you can use EXECUTE USING statement in 9.1 and older. 9.2 should to work without this workaround as Craig wrote.

v_param := 100;
EXECUTE 'select count(*) into result from <some tables> where <some conditions>
   and id = $1' USING v_param;
like image 26
Pavel Stehule Avatar answered Dec 29 '22 12:12

Pavel Stehule