# Batch statement

A batch statement allows to execute many data-modifying statements at once.<br />
\\\\
These statements can be [unprepared](https://rust-driver.docs.scylladb.com/stable/statements/unprepared.md) or [prepared](https://rust-driver.docs.scylladb.com/stable/statements/prepared.md).<br />
\\\\
Only `INSERT`, `UPDATE` and `DELETE` statements are allowed.

```rust
use scylla::statement::batch::Batch;
use scylla::statement::unprepared::Statement;
use scylla::statement::prepared::PreparedStatement;

// Create a batch statement
let mut batch: Batch = Default::default();

// Add an unprepared statement to the batch using its text
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(1, 2)");

// Add an unprepared statement created manually to the batch
let unprepared: Statement = Statement::new("INSERT INTO ks.tab (a, b) VALUES(3, 4)");
batch.append_statement(unprepared);

// Add a prepared statement to the batch
let prepared: PreparedStatement = session
    .prepare("INSERT INTO ks.tab (a, b) VALUES(?, 6)")
    .await?;
batch.append_statement(prepared);

// Specify bound values to use with each statement
let batch_values = ((),
                    (),
                    (5_i32,));

// Run the batch
session.batch(&batch, batch_values).await?;
```

>  ***Warning***<br />
> \\\\
> Using unprepared statements with bind markers in batches is strongly discouraged.
> For each unprepared statement with a non-empty list of values in the batch,
> the driver will send a prepare request, and it will be done **sequentially**.
> Results of preparation are not cached between `Session::batch` calls.
> Consider preparing the statements before putting them into the batch.

The full [example](https://github.com/scylladb/scylla-rust-driver/tree/main/examples/batch.rs) is available in the `examples` folder.
You can run it from main folder of driver repository using `cargo run --example batch` after starting our docker cluster with `make up`.

## Preparing a batch

Instead of preparing each statement individually, it’s possible to prepare a whole batch at once:

```rust
use scylla::statement::batch::Batch;

// Create a batch statement with unprepared statements
let mut batch: Batch = Default::default();
batch.append_statement("INSERT INTO ks.simple_unprepared1 VALUES(?, ?)");
batch.append_statement("INSERT INTO ks.simple_unprepared2 VALUES(?, ?)");

// Prepare all statements in the batch at once
let prepared_batch: Batch = session.prepare_batch(&batch).await?;

// Specify bound values to use with each statement
let batch_values = ((1_i32, 2_i32),
                    (3_i32, 4_i32));

// Run the prepared batch
session.batch(&prepared_batch, batch_values).await?;
```

## Batch options

You can set various options by operating on the `Batch` object.<br />
\\\\
For example to change consistency:

```rust
use scylla::statement::batch::Batch;
use scylla::statement::Consistency;

// Create a batch
let mut batch: Batch = Default::default();
batch.append_statement("INSERT INTO ks.tab(a) VALUES(16)");

// Set batch consistency to One
batch.set_consistency(Consistency::One);

// Run the batch
session.batch(&batch, ((), )).await?;
```

See [Batch API documentation](https://docs.rs/scylla/latest/scylla/statement/batch/struct.Batch.html)
for more options

## Batch values

Batch takes a tuple of values specified just like in [unprepared](https://rust-driver.docs.scylladb.com/stable/statements/unprepared.md) or [prepared](https://rust-driver.docs.scylladb.com/stable/statements/prepared.md) statements.

Length of batch values must be equal to the number of statements in a batch.<br />
\\\\
Each statement must have its values specified, even if they are empty.

Values passed to `Session::batch` must implement the trait `BatchValues`.<br />
\\\\
By default this includes tuples `()` and slices `&[]` of tuples and slices which implement `SerializeRow`.

Example:

```rust
use scylla::statement::batch::Batch;

let mut batch: Batch = Default::default();

// A statement with two bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(?, ?)");

// A statement with one bound value
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(3, ?)");

// A statement with no bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(5, 6)");

// Batch values is a tuple of 3 tuples containing values for each statement
let batch_values = ((1_i32, 2_i32), // Tuple with two values for the first statement
                    (4_i32,),       // Tuple with one value for the second statement
                    ());            // Empty tuple/unit for the third statement

// Run the batch
// Note that the driver will prepare the first two statements, due to them
// not being prepared and having a non-empty list of values.
session.batch(&batch, batch_values).await?;
```

For more information about sending values in a statement see [Statement values](https://rust-driver.docs.scylladb.com/stable/statements/values.md)

## Performance

A batch is sent to a single coordinator, which then has to fan its statements
out to the replicas of each partition.
Driver routes the batch exactly the same way it would route the first statement
of the batch. That means if you use our DefaultPolicy (with token awareness enabled),
the first statement is prepared and token-aware, then driver will try to route
the batch to a replica for this first statement.
Grouping the statements of a batch by partition is therefore what makes it
cheaper - the replica used by the driver will be a replica for all statements in the batch.

Note that a batch is not a way to make many independent writes faster - sending
them as separate concurrent requests lets each one go straight to a replica of
its own partition. Use [prepared statements](https://rust-driver.docs.scylladb.com/stable/statements/prepared.md) for best performance.
