PREPARE(7)
π PREPARE(7) β the PostgreSQL 15.19 docs, but make it make sense π
okay bestie, so this is the page for PREPARE, from the PostgreSQL 15.19 documentation. it's genuinely one of the good ones β like lowkey the glow-up your queries deserve. let's get into it π«Ά
β¨ NAME β¨
PREPARE β prepare a statement for execution. that's it. that's the whole vibe. it's giving "get ready in advance" main character energy π
π SYNOPSIS π
PREPARE name [ ( data_type [, ...] ) ] AS statement
yes she's short, she's iconic, she ate π
π¦ DESCRIPTION π¦
So PREPARE creates a prepared statement, and no cap, a prepared statement is a server-side object that you can use to optimize performance. literally the whole point. π₯
Here's the tea on how it works: when the PREPARE statement gets executed, the statement you specified is parsed, analyzed, and rewritten. Then later, when you issue an EXECUTE command, that prepared statement gets planned and executed. this division of labor is the moment β it avoids repetitive parse analysis work, while still letting the execution plan depend on the specific parameter values you supply. best of both worlds fr fr π
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. if 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, anyway π). when you execute the statement, you specify the actual values for those parameters in the EXECUTE statement. more deets on that over in EXECUTE(7).
Prepared statements only last for the duration of the current database session β like, they're not forever girls. when the session ends, the prepared statement is forgotten, so it has to be recreated before you can use it again π. this also means a single prepared statement cannot be used by multiple simultaneous database clients; however, each client can create their own prepared statement to use. and you can manually clean them up with the DEALLOCATE command, which is the tidy-girl move π§
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. conversely, 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. so like, know your context, yk? π
πΈ PARAMETERS πΈ
nameβ an arbitrary name you give 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. so like, pick something cute but also unique, bestie π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 roster π
π₯ NOTES π₯
okay this is the part where it gets juicy. a prepared statement can be executed with either a generic plan or a custom plan π
- a generic plan is the same across all executions
- 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. (and of course, if the prepared statement has no parameters, then this is all moot and a generic plan is always used. moot. love that word. moot.) π
By default β that is, when plan_cache_mode is set to auto β the server will automatically choose whether to use a generic or a 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. math! she's mathing! π
This heuristic can be overridden tho β 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. so like, a manual override when the auto-picker is being delulu π
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. easy way to spot which one you're dealing with π
For more information on query planning and the statistics collected by PostgreSQL for that purpose, see the ANALYZE(7) documentation. go read it, she's worth it π
Now β this part is highkey important. 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, fyi π)
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. cute little inventory, love that for you π
π 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. see? she figures it out herself, we love an independent 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 β same name, different girl π
β SEE ALSO β
k bye bestie, go prepare something iconic π¦πβ¨
mwah π β with love from the PostgreSQL 15.19 docs, dated 2026, and signed PREPARE(7) π
π¦ where this page comes from
- opensuse-leap 16.0: postgresql15 15.19-160000.1.1 Β· PostgreSQL
- opensuse-leap 16.0: postgresql15 15.19-160000.1.1 Β· PostgreSQL
- opensuse-leap 16.0: postgresql15 15.19-160000.1.1 Β· PostgreSQL
- opensuse-leap 16.0: postgresql15 15.19-160000.1.1 Β· PostgreSQL
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms