# `AshScylla.DataLayer.QueryOptimizer`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/data_layer/query_optimizer.ex#L15)

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
    ])

## Valid Consistency Levels

`:any`, `:one`, `:two`, `:three`, `:quorum`, `:all`,
`:local_quorum`, `:each_quorum`, `:serial`, `:local_serial`, `:local_one`

## Speculative Retry Policies

`:none`, `:99percentile`, `:custom`

# `analyze`

```elixir
@spec analyze(AshScylla.Query.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`

```elixir
@spec estimate_cost(AshScylla.Query.t()) :: atom()
```

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

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

# `optimal_page_size`

```elixir
@spec optimal_page_size(AshScylla.Query.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`

```elixir
@spec optimize(
  AshScylla.Query.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)

# `profile_query`

```elixir
@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"

# `recommended_consistency`

```elixir
@spec recommended_consistency(atom()) :: atom()
```

Returns recommended consistency level based on query type.

- Read-heavy, low-latency: `:one`
- Balanced: `:local_quorum`
- Strong consistency: `:quorum`
- Critical writes: `:all`

# `speculative_retry_cql`

```elixir
@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`

```elixir
@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`

```elixir
@spec token_aware_hint(AshScylla.Query.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`

```elixir
@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"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
