AshScylla.DataLayer.QueryOptimizer (AshScylla v0.9.0)

Copy Markdown View Source

Query optimization hints for ScyllaDB.

Provides:

  • Per-query consistency level overrides
  • Query-level timeouts
  • Paging hints for large result sets
  • Token range optimization for partition-aware queries
  • Speculative retry policy configuration
  • Query profiling helpers

Usage

# Build an optimized query
query = AshScylla.DataLayer.QueryOptimizer.optimize(query, [
  consistency: :one,
  timeout: 5_000,
  page_size: 100,
  speculative_retry: :99percentile
])

Summary

Functions

Analyzes a query and returns optimization suggestions.

Estimates query cost based on filters, sorts, and limit.

Determines the optimal page size for a query based on result set estimation.

Applies optimization hints to a DataLayer query struct.

Wraps a query with profiling enabled.

Returns recommended consistency level based on query type.

Generates CQL for speculative retry policy at session level.

Generates CQL query options for Xandra execution.

Generates a token-aware routing hint for the query.

Generates a token range query for partition-aware scanning.

Functions

analyze(query)

@spec analyze(AshScylla.DataLayer.t()) :: [String.t()]

Analyzes a query and returns optimization suggestions.

Returns a list of suggestion strings like:

  • "Consider adding secondary index on :email for faster lookups"
  • "Query performs full table scan - add partition key filter"
  • "Use token-based pagination for large result sets"

estimate_cost(data_layer)

@spec estimate_cost(AshScylla.DataLayer.t()) :: atom()

Estimates query cost based on filters, sorts, and limit.

Returns :low, :medium, :high, or :full_scan.

optimal_page_size(data_layer)

@spec optimal_page_size(AshScylla.DataLayer.t()) :: non_neg_integer()

Determines the optimal page size for a query based on result set estimation.

Uses heuristics based on:

  • Whether the query has a partition key filter (small page)
  • Whether the query is a full table scan (large page)
  • The number of clustering columns

optimize(data_layer_query, opts \\ [])

@spec optimize(
  AshScylla.DataLayer.t(),
  keyword()
) :: keyword()

Applies optimization hints to a DataLayer query struct.

Returns a keyword list of Xandra execution options that can be merged into the repo.query/3 call.

Options

  • :consistency - Override consistency level for this query
  • :timeout - Query timeout in milliseconds
  • :page_size - Number of rows per page for token-based pagination
  • :speculative_retry - Speculative retry policy (:none, :"99percentile", :custom)
  • :speculative_retry_delay_ms - Custom delay for speculative retry (ms)
  • :serial_consistency - Serial consistency for LWT (:serial, :local_serial)
  • :profiling - Enable query profiling (default: false)
  • :allow_filtering - Allow filtering (default: false, not recommended)

profile_query(query)

@spec profile_query(String.t()) :: String.t()

Wraps a query with profiling enabled.

ScyllaDB supports the PROFILE prefix for query profiling. This returns the query wrapped for profiling.

Examples

iex> AshScylla.DataLayer.QueryOptimizer.profile_query("SELECT * FROM users")
"PROFILE SELECT * FROM users"

speculative_retry_cql(policy, delay_ms)

@spec speculative_retry_cql(atom(), non_neg_integer() | nil) :: String.t()

Generates CQL for speculative retry policy at session level.

Examples

iex> AshScylla.DataLayer.QueryOptimizer.speculative_retry_cql(:99percentile, nil)
"USING SPECULATIVE_RETRY '99percentile'"

iex> AshScylla.DataLayer.QueryOptimizer.speculative_retry_cql(:none, nil)
"USING SPECULATIVE_RETRY 'NONE'"

iex> AshScylla.DataLayer.QueryOptimizer.speculative_retry_cql(:custom, 500)
"USING SPECULATIVE_RETRY '500ms'"

to_xandra_opts(opts)

@spec to_xandra_opts(keyword()) :: keyword()

Generates CQL query options for Xandra execution.

Converts optimization hints into Xandra execute options. This is an alias for optimize/2 that makes the intent explicit when building Xandra calls directly.

token_aware_hint(data_layer)

@spec token_aware_hint(AshScylla.DataLayer.t()) :: keyword()

Generates a token-aware routing hint for the query.

When the partition key is known, this enables Xandra to route the query directly to the correct node.

Returns [token: partition_key_value] for Xandra's token-aware routing, or an empty keyword list if no partition key can be determined.

token_range_query(table, partition_key, start_token, end_token)

@spec token_range_query(String.t(), String.t(), String.t(), String.t()) :: String.t()

Generates a token range query for partition-aware scanning.

Useful for parallel data processing where you want to split the token range across workers.

Parameters

  • table - The table name
  • partition_key - The partition key column name
  • start_token - Start of token range (inclusive)
  • end_token - End of token range (exclusive)

Examples

iex> AshScylla.DataLayer.QueryOptimizer.token_range_query("users", "id", "-9223372036854775808", "0")
"SELECT * FROM users WHERE token(id) > -9223372036854775808 AND token(id) <= 0"