1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Invent a "one-shot" variant of CachedPlans for better performance.

SPI_execute() and related functions create a CachedPlan, execute it once,
and immediately discard it, so that the functionality offered by
plancache.c is of no value in this code path.  And performance measurements
show that the extra data copying and invalidation checking done by
plancache.c slows down simple queries by 10% or more compared to 9.1.
However, enough of the SPI code is shared with functions that do need plan
caching that it seems impractical to bypass plancache.c altogether.
Instead, let's invent a variant version of cached plans that preserves
99% of the API but doesn't offer any of the actual functionality, nor the
overhead.  This puts SPI_execute() performance back on par, or maybe even
slightly better, than it was before.  This change should resolve recent
complaints of performance degradation from Dong Ye, Pavel Stehule, and
others.

By avoiding data copying, this change also reduces the amount of memory
needed to execute many-statement SPI_execute() strings, as for instance in
a recent complaint from Tomas Vondra.

An additional benefit of this change is that multi-statement SPI_execute()
query strings are now processed fully serially, that is we complete
execution of earlier statements before running parse analysis and planning
on following ones.  This eliminates a long-standing POLA violation, in that
DDL that affects the behavior of a later statement will now behave as
expected.

Back-patch to 9.2, since this was a performance regression compared to 9.1.
(In 9.2, place the added struct fields so as to avoid changing the offsets
of existing fields.)

Heikki Linnakangas and Tom Lane
This commit is contained in:
Tom Lane
2013-01-04 17:42:25 -05:00
parent 48e0b8a23e
commit a17da19ed9
5 changed files with 329 additions and 57 deletions

View File

@ -326,9 +326,7 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
</para>
<para>
You can pass multiple commands in one string, but later commands cannot
depend on the creation of objects earlier in the string, because the
whole string will be parsed and planned before execution begins.
You can pass multiple commands in one string;
<function>SPI_execute</function> returns the
result for the command executed last. The <parameter>count</parameter>
limit applies to each command separately, but it is not applied to
@ -392,7 +390,8 @@ typedef struct
TupleDesc tupdesc; /* row descriptor */
HeapTuple *vals; /* rows */
} SPITupleTable;
</programlisting><structfield>vals</> is an array of pointers to rows. (The number
</programlisting>
<structfield>vals</> is an array of pointers to rows. (The number
of valid entries is given by <varname>SPI_processed</varname>.)
<structfield>tupdesc</> is a row descriptor which you can pass to
SPI functions dealing with rows. <structfield>tuptabcxt</>,
@ -432,7 +431,8 @@ typedef struct
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>
@ -671,7 +671,8 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>
@ -809,7 +810,8 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>
@ -1452,7 +1454,8 @@ int SPI_execute_plan(SPIPlanPtr <parameter>plan</parameter>, Datum * <parameter>
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>
@ -1569,7 +1572,8 @@ int SPI_execute_plan_with_paramlist(SPIPlanPtr <parameter>plan</parameter>,
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>
@ -1669,7 +1673,8 @@ int SPI_execp(SPIPlanPtr <parameter>plan</parameter>, Datum * <parameter>values<
<term><literal>long <parameter>count</parameter></literal></term>
<listitem>
<para>
maximum number of rows to process or return
maximum number of rows to process or return,
or <literal>0</> for no limit
</para>
</listitem>
</varlistentry>