---
title: "Prepared statements"
sidebarTitle: "Prepared Statements"
description: "Preparing a statement once and executing it many times, over the Flight SQL protocol."
icon: bolt
keywords: ["prepared statement", "flight sql", "parameters", "bind"]
---
Enterprise [SQL runs on a deployment.](/sql)
A prepared statement is planned once and executed many times, which saves
re-planning a statement whose shape does not change between runs.
## It is a protocol feature, not a statement {#protocol}
There is no SQL `PREPARE` / `EXECUTE` here. Preparation is part of the
**Arrow Flight SQL protocol**, so you reach it through your client rather than
by sending a statement.
That distinction matters when porting SQL from another engine: a script
containing `PREPARE name AS SELECT ...` will not run, while the same intent
expressed through a Flight SQL client will.
## The flow {#flow}
Every Flight SQL client exposes the same three steps, whatever it calls them:
1. **Prepare** — send the SQL, get back a handle and the result schema. The
statement is parsed and planned at this point, so a syntax or name error
surfaces here rather than at execution.
2. **Bind and execute** — supply parameter values for the handle and read the
result. Repeat as often as you like.
3. **Close** — release the handle. Servers do not hold them forever.
Knowing that the plan is built at step 1 is the practical part: if a statement
is slow to prepare and fast to execute, the cost is planning, and reusing the
handle is exactly the right fix.
## Parameters {#parameters}
Parameters are placeholders in the SQL text, bound to an Arrow record batch at
execution. Binding rather than interpolating is worth doing for the usual two
reasons — the value cannot change the statement's meaning, and the plan is
reused across values.
```sql
SELECT id, title FROM documents WHERE category = $1 AND score > $2
```
The exact placeholder spelling and the binding call belong to your client; see
[connecting a client](/sql#connecting).
## When it helps {#when}
| | |
| --- | --- |
| The same query with different values, many times | prepare once, bind per execution |
| A complex plan — several joins, window functions | planning dominates; reuse it |
| A one-off analytical query | no benefit; just execute it |
For a statement you want to keep rather than re-prepare, a
[view](/management/view) stores the query server-side, and a
[materialized view](/management/materialized-view) stores its rows.