PREPARE(7)
๐ PREPARE โ bestie, let's pre-game your statements (PostgreSQL 18.6)
okay so. this is PREPARE(7) from the PostgreSQL 18.6 docs, and it's literally one of my fave pages because it's giving main character optimization energy. sit down, grab a strawberry drink ๐, and let's get into it.
โจ SYNOPSIS โจ
PREPARE name [ ( data_type [, ...] ) ] AS statement
๐ฆ DESCRIPTION ๐ฆ
PREPARE creates a prepared statement. and what is that, you ask? it's a server-side object that can be used to optimize performance. no cap. when the PREPARE statement gets executed, the statement you specified is parsed, analyzed, and rewritten. then when you hit it with an EXECUTE command later, the prepared statement gets planned and executed. this division of labor avoids repetitive parse analysis work, while still letting the execution plan depend on the specific parameter values you supply. it's giving smart girl efficiency. ๐
prepared statements can take parameters โ values that get substituted into the statement when it's executed. when you're creating the prepared statement, you refer to parameters by position, using $1, $2, etc. you can optionally specify a corresponding list of parameter data types. when a parameter's data type isn't specified or is declared as unknown, the type gets inferred from the context in which the parameter is first referenced (if possible). when executing the statement, you specify the actual values for those parameters in the EXECUTE statement. go read EXECUTE(7) for more on that part, bestie.
prepared statements only last for the duration of the current database session. when the session ends, the prepared statement is forgotten, so it must be recreated before being used again. this also means a single prepared statement cannot be used by multiple simultaneous database clients โ but each client can create their own prepared statement to use. ๐ซถ you can manually clean up prepared statements with the DEALLOCATE command.
prepared statements potentially have the largest performance advantage when a single session is being used to execute a large number of similar statements. the performance difference will be particularly significant if the statements are complex to plan or rewrite โ e.g., if the query involves a join of many tables or requires the application of several rules. if the statement is relatively simple to plan and rewrite but relatively expensive to execute, the performance advantage of prepared statements will be less noticeable. it's giving "depends on the vibe of your query". โจ
๐ PARAMETERS ๐
nameโ an arbitrary name given to this particular prepared statement. it must be unique within a single session, and it's subsequently used to execute or deallocate a previously prepared statement. pick something cute but make sure it doesn't clash. ๐data_typeโ the data type of a parameter to the prepared statement. if the data type of a particular parameter is unspecified or is specified asunknown, it will be inferred from the context in which the parameter is first referenced. to refer to the parameters in the prepared statement itself, use$1,$2, etc.statementโ anySELECT,INSERT,UPDATE,DELETE,MERGE, orVALUESstatement. that's the whole guest list, no plus-ones beyond that. ๐
๐ฅ NOTES ๐ฅ
a prepared statement can be executed with either a generic plan or a custom plan. a generic plan is the same across all executions, while a custom plan is generated for a specific execution using the parameter values given in that call. using a generic plan avoids planning overhead, but in some situations a custom plan will be much more efficient to execute because the planner can make use of knowledge of the parameter values. (of course, if the prepared statement has no parameters, then this is moot and a generic plan is always used.) moot! love that word. ๐
by default โ that is, when plan_cache_mode is set to auto โ the server will automatically choose whether to use a generic or custom plan for a prepared statement that has parameters. the current rule for this is that the first five executions are done with custom plans and the average estimated cost of those plans is calculated. then a generic plan is created and its estimated cost is compared to the average custom-plan cost. subsequent executions use the generic plan if its cost is not so much higher than the average custom-plan cost as to make repeated replanning seem preferable. it's literally a little cost-based vibe check. โญ
this heuristic can be overridden โ forcing the server to use either generic or custom plans โ by setting plan_cache_mode to force_generic_plan or force_custom_plan respectively. this setting is primarily useful if the generic plan's cost estimate is badly off for some reason, allowing it to be chosen even though its actual cost is much more than that of a custom plan.
to examine the query plan PostgreSQL is using for a prepared statement, use EXPLAIN, for example
EXPLAIN EXECUTE name(parameter_values);
if a generic plan is in use, it will contain parameter symbols $n, while a custom plan will have the supplied parameter values substituted into it. ๐
for more information on query planning and the statistics collected by PostgreSQL for that purpose, see the ANALYZE(7) documentation.
although the main point of a prepared statement is to avoid repeated parse analysis and planning of the statement, PostgreSQL will force re-analysis and re-planning of the statement before using it whenever database objects used in the statement have undergone definitional (DDL) changes or their planner statistics have been updated since the previous use of the prepared statement. also, if the value of search_path changes from one use to the next, the statement will be re-parsed using the new search_path. (this latter behavior is new as of PostgreSQL 9.3.) these rules make use of a prepared statement semantically almost equivalent to re-submitting the same query text over and over, but with a performance benefit if no object definitions are changed โ especially if the best plan remains the same across uses.
an example of a case where the semantic equivalence is not perfect: if the statement refers to a table by an unqualified name, and then a new table of the same name is created in a schema appearing earlier in the search_path, no automatic re-parse will occur since no object used in the statement changed. however, if some other change forces a re-parse, the new table will be referenced in subsequent uses. sneaky. ๐ญ
you can see all prepared statements available in the session by querying the pg_prepared_statements system view. iconique. ๐
๐ธ EXAMPLES ๐ธ
create a prepared statement for an INSERT statement, and then execute it:
PREPARE fooplan (int, text, bool, numeric) AS
INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);
create a prepared statement for a SELECT statement, and then execute it:
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);
in this example, the data type of the second parameter is not specified, so it is inferred from the context in which $2 is used. she figured it out herself, we love a self-sufficient queen. ๐ง
๐ COMPATIBILITY ๐
the SQL standard includes a PREPARE statement, but it is only for use in embedded SQL. this version of the PREPARE statement also uses a somewhat different syntax. so likeโฆ related, but not twins. ๐
๐ SEE ALSO ๐
okay that's the whole page, you ate that. this was pulled from the PostgreSQL 18.6 documentation, dated 2026, and it's the PREPARE(7) page โ so go forth, prepare your statements, and slay. periodt. ๐โจ๐
๐ฆ where this page comes from
- alpine 3.23: postgresql18-doc 18.6-r0 ยท PostgreSQL
- alpine 3.24: postgresql18-doc 18.6-r0 ยท PostgreSQL
- arch rolling: postgresql 18.6-4 ยท PostgreSQL
- fedora 43: postgresql 18.6-1.fc43 ยท PostgreSQL
- fedora 43: postgresql 18.6-1.fc43 ยท PostgreSQL
- fedora 44: postgresql 18.6-1.fc44 ยท PostgreSQL
- fedora 44: postgresql 18.6-1.fc44 ยท PostgreSQL
- nixos 26.05: postgresql 18.6
- ubuntu resolute: postgresql-client-18 18.6-0ubuntu0.26.04.1 ยท PostgreSQL
- ubuntu stonking: postgresql-client-18 18.6-3build2 ยท PostgreSQL
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms