---
title: "SQL editor"
subtitle: "Query your spans, traces, and scores with read-only ClickHouse SQL."
---

The SQL editor runs read-only ClickHouse SQL over your project's data. Use it for questions the Logs filters can't answer, such as cost per model or error rate per customer.

## Run a query

<Steps>
<Step title="Open the editor">

Go to **Observability** › **SQL editor**. A new tab offers **Start from a template**: **Cost by day**, **Top models**, **Error rate**, and **Traces overview**. Pick one, or write your own.

</Step>
<Step title="Write the SQL">

The **Tables** panel on the right lists every table and column. Click a column to insert it, or use **Preview rows** on a table. The editor also autocompletes tables, columns, and functions.

This query returns cost and latency per model for the last 7 days:

```sql
SELECT
    model,
    count(*) AS requests,
    round(sum(cost), 2) AS total_cost,
    round(avg(latency), 2) AS avg_latency
FROM logs
WHERE timestamp >= now() - INTERVAL 7 DAY
GROUP BY model
ORDER BY total_cost DESC
LIMIT 20
```

</Step>
<Step title="Run it">

Click **Run** or press **⌘ Enter** (**Ctrl Enter** on Windows and Linux). If the tab has several statements, it runs the one at the cursor. If you select text, it runs the selection.

The results show below the editor, with the row count, duration, and time. Click a column header to sort, or click **Inspect row** to read one row in full.

<img src={"/docs/images/sql-editor/sql-editor-results-light.png"} className="block dark:hidden" alt="The SQL editor with saved query tabs, a cost-by-model query, a five-row result grid, and the Tables panel listing the logs columns" />
<img src={"/docs/images/sql-editor/sql-editor-results-dark.png"} className="hidden dark:block" alt="The SQL editor with saved query tabs, a cost-by-model query, a five-row result grid, and the Tables panel listing the logs columns" />

</Step>
</Steps>

Always filter on the table's time column, such as `timestamp` for `logs`. Queries without one scan more data and are more likely to time out.

## Save and manage queries

Every tab is a saved query. Your SQL saves as you type or run, and the editor shows **Saved** when it's done.

- **New query:** click the button after the last tab. New queries are named **Untitled query**.
- **Rename:** hover the open tab and click the pencil.
- **Delete:** click **×** on the tab, then confirm. This deletes the saved query for good.

## Chart the results

When the result has a time column and a numeric column, click **Chart** to plot it. Click **Add to dashboard** to put the chart on a [Metrics](/docs/documentation/features/monitoring/metrics) view.

<img src={"/docs/images/sql-editor/sql-editor-chart-light.png"} className="block dark:hidden" alt="SQL results shown as a line chart of daily cost over 14 days, with Add to dashboard, Table, Chart, and Export in the toolbar" />
<img src={"/docs/images/sql-editor/sql-editor-chart-dark.png"} className="hidden dark:block" alt="SQL results shown as a line chart of daily cost over 14 days, with Add to dashboard, Table, Chart, and Export in the toolbar" />

This query produces the chart above:

```sql
SELECT
    toDate(timestamp) AS day,
    sum(cost) AS total_cost
FROM logs
WHERE timestamp >= now() - INTERVAL 14 DAY
GROUP BY day
ORDER BY day
```

## Export results

Click **Export**, or press **E**, and choose **Export as CSV** or **Export as JSONL**. The export reruns your query in the background, so it isn't limited to the rows on screen. When it's done, download it from the dialog or from **Settings** › **Exports**.

**Copy rows as TSV**, in the same menu, copies the rows shown.

## Tables

| Table | One row per | Time column |
| --- | --- | --- |
| `logs` | Span: LLM call, tool call, or workflow step | `timestamp` |
| `traces` | Trace. Group by `trace_unique_id`. | `start_time` |
| `eval_results` | Evaluator score | `created_at` |
| `annotations` | Human feedback on a span | `timestamp` |

The **Rollups** group in the **Tables** panel has pre-aggregated tables for faster charts over long ranges: `log_metrics`, `log_metrics_hourly`, `latency_quantiles_minute`, `latency_quantiles_hourly`, and `metadata_metrics`.

Useful `logs` columns include `model`, `provider_id`, `cost`, `latency`, `prompt_tokens`, `completion_tokens`, `status`, `customer_identifier`, `thread_identifier`, and `trace_unique_id`. Read custom properties with `metadata['key']`.

## More examples

**Error rate by model, last 24 hours:**

```sql
SELECT
    model,
    count(*) AS requests,
    round(countIf(status = 'failed') / count(*) * 100, 2) AS error_rate_pct
FROM logs
WHERE timestamp >= now() - INTERVAL 1 DAY
GROUP BY model
HAVING count(*) > 10
ORDER BY error_rate_pct DESC
```

**Cost by a custom property, such as `feature`:**

```sql
SELECT
    metadata['feature'] AS feature,
    count(*) AS requests,
    round(sum(cost), 2) AS total_cost
FROM logs
WHERE timestamp >= now() - INTERVAL 7 DAY
GROUP BY feature
ORDER BY total_cost DESC
```

## Limits

| Limit | Value |
| --- | --- |
| Statements | `SELECT` only, including `WITH` |
| Data | Your project only. Respan adds the project filter before the query runs. |
| Run time | 30 seconds |
| Runs | 10 per minute |
| Query length | 10,000 characters |
| Export | 1,000,000 rows, 240 seconds, or 1 GB. Your `WHERE` and `LIMIT` still apply. |
