PREPARE(7)

πŸ“¦ version 13.23, in opensuse-leap 16.0

✨ PREPARE(7) β€” the "let's pre-game your SQL" glow-up ✨

okay bestie, listen up πŸ’… this is the PREPARE page from the PostgreSQL 13.23 docs, and honestly? it's giving "plan ahead and slay." let me break it down for u 🫢


🌸 SYNOPSIS 🌸

PREPARE name [ ( data_type [, ...] ) ] AS statement

πŸ’– DESCRIPTION πŸ’–

So PREPARE creates a prepared statement. what even is that? it's a server-side object that u can use to optimize performance β€” like prepping your outfit the night before so the morning is a breeze, ykwim? 🌈

when the PREPARE statement runs, the statement u specified gets parsed, analyzed, and rewritten. then later when u fire off an EXECUTE command, that prepared statement gets planned and executed. this division of labor (iconic teamwork fr fr) avoids repetitive parse analysis work, while still letting the execution plan depend on the specific parameter values u supply. πŸŽ€

prepared statements can take parameters: values that get substituted into the statement when it's executed. when ur creating the prepared statement, u refer to parameters by position using $1, $2, etc. u 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 is inferred from the context in which the parameter is first referenced (if possible). when executing, u specify the actual values for these parameters in the EXECUTE statement. more on that over in EXECUTE(7) β€” go read it bestie, iykyk πŸ“–

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 can't be used by multiple simultaneous database clients β€” however, each client can create their own prepared statement to use. prepared statements can be manually cleaned up using the DEALLOCATE(7) command. bye bestie πŸ‘‹

prepared statements potentially have the largest performance advantage when a single session is 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, then the performance advantage of prepared statements will be less noticeable. it's giving "depends on the vibe" ngl.


πŸ¦‹ PARAMETERS πŸ¦‹

  • name β€” an arbitrary name u give to this particular prepared statement. it must be unique within a single session and is subsequently used to execute or deallocate a previously prepared statement. pick something cute and memorable πŸŽ€
  • 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 as unknown, 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 β€” any SELECT, INSERT, UPDATE, DELETE, or VALUES statement. that's the whole menu, bestie πŸ“

πŸ‘‘ NOTES πŸ‘‘

okay this part is lowkey the main character of the whole page, so pay attention ✨

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. use of 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 β€” no thoughts, head empty πŸ™ˆ)

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 basically the server doing a vibe check on ur query πŸ”

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. use it wisely bestie, it's a power move ⚑

to examine the query plan PostgreSQL is using for a prepared statement, use EXPLAIN(7), 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. slay, now u can actually see what's happening πŸ‘€

for more information on query planning and the statistics collected by PostgreSQL for that purpose, see the ANALYZE(7) documentation. homework assignment, go read it πŸ“š

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 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 β€” vintage lore 🏺) 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 sneaky πŸ’€

u can see all prepared statements available in the session by querying the pg_prepared_statements system view. cute little roster of everything u prepped πŸ’–


🌟 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? the inference thing in action, iconic 🧚


πŸ’œ 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 energy β€” don't get it twisted πŸ™…β€β™€οΈ


πŸŽ€ SEE ALSO πŸŽ€

DEALLOCATE(7), EXECUTE(7)


and that's the whole page bestie!! πŸ’– this was PostgreSQL 13.23 documentation, dated 2025, and the original source is the PostgreSQL 13.23 Documentation set β€” go off and prep those statements, u got this fr fr 🫢✨🌸

πŸ“¦ where this page comes from