| The PostgreSQL 9.0 Reference Manual - Volume 2 - Programming Guide
by The PostgreSQL Global Development Group Paperback (6"x9"), 478 pages ISBN 9781906966065 RRP £14.95 ($19.95) Sales of this book support the PostgreSQL project! Get a printed copy>>> |
9.10.2 Plan Caching
The PL/pgSQL interpreter parses the function's source text and produces an internal binary instruction tree the first time the function is called (within each session). The instruction tree fully translates the PL/pgSQL statement structure, but individual SQL expressions and SQL commands used in the function are not translated immediately.
As each expression and SQL command is first
executed in the function, the PL/pgSQL interpreter
creates a prepared execution plan (using the
SPI manager's SPI_prepare
and SPI_saveplan
functions).
Subsequent visits to that expression or command
reuse the prepared plan. Thus, a function with conditional code
that contains many statements for which execution plans might be
required will only prepare and save those plans that are really
used during the lifetime of the database connection. This can
substantially reduce the total amount of time required to parse
and generate execution plans for the statements in a
PL/pgSQL function. A disadvantage is that errors
in a specific expression or command cannot be detected until that
part of the function is reached in execution. (Trivial syntax
errors will be detected during the initial parsing pass, but
anything deeper will not be detected until execution.)
A saved plan will be re-planned automatically if there is any schema change to any table used in the query, or if any user-defined function used in the query is redefined. This makes the re-use of prepared plans transparent in most cases, but there are corner cases where a stale plan might be re-used. An example is that dropping and re-creating a user-defined operator won't affect already-cached plans; they'll continue to call the original operator's underlying function, if that has not been changed. When necessary, the cache can be flushed by starting a fresh database session.
Because PL/pgSQL saves execution plans
in this way, SQL commands that appear directly in a
PL/pgSQL function must refer to the
same tables and columns on every execution; that is, you cannot use
a parameter as the name of a table or column in an SQL command. To get
around this restriction, you can construct dynamic commands using
the PL/pgSQL EXECUTE
statement--at the price of constructing a new execution plan on
every execution.
Another important point is that the prepared plans are parameterized to allow the values of PL/pgSQL variables to change from one use to the next, as discussed in detail above. Sometimes this means that a plan is less efficient than it would be if generated for a specific variable value. As an example, consider
SELECT * INTO myrec FROM dictionary WHERE word LIKE search_term;
where search_term is a PL/pgSQL
variable. The cached plan for this query will never use an index on
word, since the planner cannot assume that the
LIKE pattern will be left-anchored at run time. To use
an index the query must be planned with a specific constant
LIKE pattern provided. This is another situation where
EXECUTE can be used to force a new plan to be
generated for each execution.
The mutable nature of record variables presents another problem in this
connection. When fields of a record variable are used in
expressions or statements, the data types of the fields must not
change from one call of the function to the next, since each
expression will be planned using the data type that is present
when the expression is first reached. EXECUTE can be
used to get around this problem when necessary.
If the same function is used as a trigger for more than one table,
PL/pgSQL prepares and caches plans
independently for each such table--that is, there is a cache
for each trigger function and table combination, not just for each
function. This alleviates some of the problems with varying
data types; for instance, a trigger function will be able to work
successfully with a column named key even if it happens
to have different types in different tables.
Likewise, functions having polymorphic argument types have a separate plan cache for each combination of actual argument types they have been invoked for, so that data type differences do not cause unexpected failures.
Plan caching can sometimes have surprising effects on the interpretation of time-sensitive values. For example there is a difference between what these two functions do:
CREATE FUNCTION logfunc1(logtxt text) RETURNS void AS $$
BEGIN
INSERT INTO logtable VALUES (logtxt, 'now');
END;
$$ LANGUAGE plpgsql;
and:
CREATE FUNCTION logfunc2(logtxt text) RETURNS void AS $$
DECLARE
curtime timestamp;
BEGIN
curtime := 'now';
INSERT INTO logtable VALUES (logtxt, curtime);
END;
$$ LANGUAGE plpgsql;
In the case of logfunc1, the
PostgreSQL main parser knows when
preparing the plan for the INSERT that the
string 'now' should be interpreted as
timestamp, because the target column of
logtable is of that type. Thus,
'now' will be converted to a constant when the
INSERT is planned, and then used in all
invocations of logfunc1 during the lifetime
of the session. Needless to say, this isn't what the programmer
wanted.
In the case of logfunc2, the
PostgreSQL main parser does not know
what type 'now' should become and therefore
it returns a data value of type text containing the string
now. During the ensuing assignment
to the local variable curtime, the
PL/pgSQL interpreter casts this
string to the timestamp type by calling the
text_out and timestamp_in
functions for the conversion. So, the computed time stamp is updated
on each execution as the programmer expects.
| ISBN 9781906966065 | The PostgreSQL 9.0 Reference Manual - Volume 2 - Programming Guide | See the print edition |