Skip to main content
The ScyllaDB Rust Driver supports three main types of CQL statements for executing queries and commands:

Statement Types

Unprepared Statements (Query)

Unprepared statements are simple CQL query strings that are sent directly to the database. They are easy to use but have performance limitations compared to prepared statements.
use scylla::client::session::Session;

// Execute an unprepared statement
session
    .query_unpaged(
        "INSERT INTO examples_ks.basic (a, b, c) VALUES (?, ?, ?)",
        (3, 4, "def"),
    )
    .await?;
Use unprepared statements for:
  • One-time queries
  • Schema-altering statements (CREATE, ALTER, DROP)
  • Administrative commands
  • Queries without bind values

Prepared Statements

Prepared statements are pre-compiled on the server and offer significant performance benefits. They are the recommended choice for queries that will be executed multiple times.
use scylla::statement::prepared::PreparedStatement;

// Prepare the statement once
let prepared: PreparedStatement = session
    .prepare("INSERT INTO examples_ks.basic (a, b, c) VALUES (?, 7, ?)")
    .await?;

// Execute it multiple times with different values
session.execute_unpaged(&prepared, (42_i32, "I'm prepared!")).await?;
session.execute_unpaged(&prepared, (43_i32, "I'm prepared 2!")).await?;
Benefits of prepared statements:
  • Performance: Database parses the query only once
  • Type safety: Bound values are validated against server metadata
  • Token-aware routing: Driver can compute partition keys for optimal routing
  • Result optimization: Cached metadata can skip result metadata transmission

Batch Statements

Batch statements allow you to execute multiple statements (prepared or unprepared) atomically in a single request.
use scylla::statement::batch::{Batch, BatchType};

let mut batch: Batch = Batch::new(BatchType::Logged);

batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(?, ?)");
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(3, ?)");
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(5, 6)");

let batch_values = (
    (1_i32, 2_i32),  // Values for first statement
    (4_i32,),        // Values for second statement
    (),              // No values for third statement
);

session.batch(&batch, batch_values).await?;

Execution Methods

The driver provides different execution methods depending on whether you’re using unprepared or prepared statements:
OperationUnprepared StatementPrepared Statement
Single unpaged requestquery_unpaged()execute_unpaged()
Single page with manual pagingquery_single_page()execute_single_page()
Automatic paging (iterator)query_iter()execute_iter()
Batch executionbatch() (supports both)

Common Configuration

All statement types support common configuration options:
use scylla::statement::unprepared::Statement;
use scylla::statement::Consistency;
use std::time::Duration;

let mut statement = Statement::new("SELECT * FROM ks.table");

// Set consistency level
statement.set_consistency(Consistency::Quorum);

// Set serial consistency for LWT
statement.set_serial_consistency(Some(SerialConsistency::LocalSerial));

// Set request timeout
statement.set_request_timeout(Some(Duration::from_secs(30)));

// Mark as idempotent for safe retries
statement.set_is_idempotent(true);

// Enable tracing
statement.set_tracing(true);
For queries with bind values, always prefer prepared statements. Using query_unpaged() or query_iter() with values requires the driver to prepare the statement internally, resulting in 2 round trips instead of 1.

Next Steps

Unprepared Statements

Learn about executing unprepared CQL queries

Prepared Statements

Optimize performance with prepared statements

Batch Statements

Execute multiple statements atomically

Paged Queries

Handle large result sets efficiently

Build docs developers (and LLMs) love