sql-optimizer

Iteratively optimize ClickHouse SQL queries against a real database, comparing variants on structural metrics (read_rows, read_bytes, peak memory, CPU time, wall time) — not just wall clock. Use this skill whenever the user asks to optimize a query, speed up an analytics endpoint, reduce memory of a database query, profile a slow query, compare query variants, or work with a Rust/Python file or API route that contains a query builder. Triggers on phrases like "optimize this query", "make this endpoint faster", "why is this slow", "compare X vs Y", "tune the FINAL/JOIN/GROUP BY", "reduce memory", or any mention of ClickHouse query performance. The skill reads DB creds from .env, accepts either raw SQL or a path to a file / API route containing a query builder, runs structural benchmarks, proposes optimizations one at a time, verifies result equivalence with a hash, and stops when no candidate improves both correctness and structural cost.

5 stars

Best use case

sql-optimizer is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Iteratively optimize ClickHouse SQL queries against a real database, comparing variants on structural metrics (read_rows, read_bytes, peak memory, CPU time, wall time) — not just wall clock. Use this skill whenever the user asks to optimize a query, speed up an analytics endpoint, reduce memory of a database query, profile a slow query, compare query variants, or work with a Rust/Python file or API route that contains a query builder. Triggers on phrases like "optimize this query", "make this endpoint faster", "why is this slow", "compare X vs Y", "tune the FINAL/JOIN/GROUP BY", "reduce memory", or any mention of ClickHouse query performance. The skill reads DB creds from .env, accepts either raw SQL or a path to a file / API route containing a query builder, runs structural benchmarks, proposes optimizations one at a time, verifies result equivalence with a hash, and stops when no candidate improves both correctness and structural cost.

Teams using sql-optimizer should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/sql-optimizer/SKILL.md --create-dirs "https://raw.githubusercontent.com/deadlock-api/deadlock-api/main/.claude/skills/sql-optimizer/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/sql-optimizer/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How sql-optimizer Compares

Feature / Agentsql-optimizerStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Iteratively optimize ClickHouse SQL queries against a real database, comparing variants on structural metrics (read_rows, read_bytes, peak memory, CPU time, wall time) — not just wall clock. Use this skill whenever the user asks to optimize a query, speed up an analytics endpoint, reduce memory of a database query, profile a slow query, compare query variants, or work with a Rust/Python file or API route that contains a query builder. Triggers on phrases like "optimize this query", "make this endpoint faster", "why is this slow", "compare X vs Y", "tune the FINAL/JOIN/GROUP BY", "reduce memory", or any mention of ClickHouse query performance. The skill reads DB creds from .env, accepts either raw SQL or a path to a file / API route containing a query builder, runs structural benchmarks, proposes optimizations one at a time, verifies result equivalence with a hash, and stops when no candidate improves both correctness and structural cost.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# SQL Optimizer

Iteratively optimize ClickHouse queries with a structural lens — I/O, memory, CPU, then wall time — and verify that each rewrite preserves results.

## Why structural metrics, not just wall time

Wall time alone is misleading: page cache, file cache, and concurrent load skew it heavily. A change that drops wall time 30% but doubles peak memory will OOM in production. To know whether a rewrite actually wins, look at all of:

- **read_rows / read_bytes** — how much data the query touched. Big drops here usually mean partition / MinMax / granule pruning kicked in.
- **memory_usage** (peak) — set by the heaviest operator (sort, GROUP BY, JOIN, FINAL). Drops here mean the algorithm changed, not just the cache.
- **OSCPUVirtualTimeMicroseconds / UserTimeMicroseconds** (from `system.query_log`) — actual CPU spent. Low CPU + high wall time = blocked on I/O, locks, or coordination.
- **wall time** (≥3 runs after warm-up, mean ± stddev) — bottom line, but only meaningful with the others as context.

State the structural numbers before the wall numbers in every report.

## Scope: query rewrites only

This skill optimizes by **rewriting the query**. It does not propose, suggest, or apply any schema-level change. Off-limits:

- `ALTER TABLE … ADD PROJECTION` / `DROP PROJECTION`
- `CREATE MATERIALIZED VIEW` / `CREATE VIEW`
- `CREATE TABLE` / `CREATE DICTIONARY`
- Adding/changing/removing indexes (skip indexes, bloom filters, primary key)
- Changing engine, ORDER BY, PARTITION BY, TTL, codecs
- Inserting rows, populating projections, or running `OPTIMIZE TABLE`

If the query is fundamentally limited by the schema (e.g. missing the right sort key for the access pattern), say so in the verdict — "no further query-level wins; consider a schema change such as X" — and stop. Don't write the schema change yourself; that's the user's call and a separate workflow.

The bench / equiv scripts only ever issue `SELECT` (and `EXPLAIN` / `SYSTEM FLUSH LOGS`). Anything that mutates state is out.

## Inputs

The skill accepts any of:

1. **A raw SQL string.** Run it directly.
2. **A file path** (e.g. `api/src/routes/v1/analytics/hero_stats.rs`). Read the file, find the query builder (typically a `build_query` fn or a big `format!("…")` block), and reconstruct a representative SQL string by feeding it default/typical parameters. Show the rendered SQL to the user before benchmarking.
3. **An API route** (e.g. `/v1/analytics/hero-stats`). Grep the codebase for the route handler, then proceed as in (2).

For (2)/(3), realistic parameters matter — pick recent timestamps (e.g. last 30 days), `Normal` game mode if the schema has one, and any required filters. Don't run with parameters that return zero rows; the planner behaves differently.

## Workflow

1. **Locate creds.** Read `CLICKHOUSE_HOST`, `CLICKHOUSE_HTTP_PORT`, `CLICKHOUSE_USERNAME`, `CLICKHOUSE_PASSWORD`, `CLICKHOUSE_DBNAME` from `.env` (commonly `<repo>/api/.env` in this codebase). Prefer the read-only user if both `CLICKHOUSE_USERNAME` and `CLICKHOUSE_RESTRICTED_USERNAME` exist. Never echo the password back to the user.

2. **Render and inspect.** Show the rendered SQL. Run `EXPLAIN ESTIMATE` and `EXPLAIN PIPELINE` first — they're free and reveal partition counts, granule counts, and the operator pipeline. Often this alone tells you where the win is.

3. **Baseline.** Use `scripts/bench.sh` to run the query 5 times after a warm-up, capturing `X-ClickHouse-Summary` per run and pulling matching rows from `system.query_log` for CPU/I/O counters. Save baseline metrics.

4. **Propose 2–4 candidates.** Read the query carefully and pick transformations from `references/clickhouse_optimizations.md`. Prefer changes that target a specific structural metric you've identified as the bottleneck — don't fire a shotgun.

5. **Verify equivalence per candidate.** Use `scripts/equiv.sh`, which runs `cityHash64(groupArray(tuple of columns))` over both results and compares. If a transformation uses approximate functions (`uniq`, `quantile*`, `topK`), allow ≤1% delta but call it out explicitly. Never benchmark a candidate before checking equivalence — a faster wrong query is not faster.

6. **Bench each candidate.** Same `bench.sh` invocation as baseline. Build a comparison table.

7. **Iterate.** Pick the best candidate (best structural delta, no regression on memory, equivalent result), make it the new baseline, propose more changes that compose with it, rerun. Stop when no candidate improves the chosen metrics by ≥5%, or the user is satisfied.

## Reporting format

Present every result as a single table, structural metrics first:

| variant | read_rows | read_bytes | peak_mem | cpu_us | wall_ms (n=5) | equivalent |
|---------|-----------|-----------|----------|--------|---------------|------------|
| baseline | … | … | … | … | … ± … | — |
| candidate_A | … (Δ%) | … (Δ%) | … (Δ%) | … (Δ%) | … ± … (Δ%) | yes |

End with a 1–2 sentence verdict and a clear recommendation:
- "Ship variant X — N% less memory, equivalent results."
- "No improvement worth the complexity; keep baseline."

Show absolute numbers and percentage deltas. Don't hide regressions — if memory grew while wall time dropped, say so and let the user decide.

## Equivalence check

Two queries are equivalent if `cityHash64(groupArray(tuple_of_all_output_columns))` matches when both are wrapped in `SELECT … FROM (… ORDER BY <stable key>)`. The `equiv.sh` script handles this. For approximate aggregates, hash a rounded form, e.g. `cityHash64(groupArray((col1, round(approx_col, 3))))`, or compare totals separately and tolerate ≤1% drift.

If equivalence fails, **stop**. Do not proceed to benchmarking. Either the rewrite is wrong, or the original behavior depended on something subtle (NULL ordering, dedup, FINAL semantics) that the user should know about.

## Anti-patterns to avoid

- **Optimizing on a single run.** Variance is high; warm-up and average ≥5 runs.
- **Ignoring memory.** A query that's 30% faster but uses 3× memory is a regression under load.
- **Removing FINAL blindly.** ClickHouse's `FINAL` on a `ReplacingMergeTree` *whose sort key matches the dedup key* is heavily optimized — it streams the merge during read. Hand-rolled `LIMIT 1 BY (sort_key)` or `GROUP BY (sort_key) … any(col)` workarounds typically run 5–10× slower and use more memory because they force a full sort or hash aggregation. Always benchmark before recommending FINAL removal. See `references/clickhouse_optimizations.md` for the FINAL decision tree.
- **Changing semantics silently.** If a transformation changes dedup behavior, NULL handling, JOIN strictness, or aggregate exactness, surface it in the verdict.
- **Trusting the cache.** Two warm-cache runs of the same query can differ 10×. Always run baseline and candidate back-to-back, never separated by minutes of other work.
- **Optimizing the wrong query.** When extracting from a file, confirm the rendered SQL matches what the route actually issues. A `tracing::debug!(?query_str)` in the handler can confirm.
- **Sneaking in a schema change.** Projections, materialized views, new indexes, and engine/ORDER BY changes are explicitly out of scope (see "Scope" above). If a transformation needs one to work, surface the recommendation as text and stop — do not draft DDL or run it.

## Scripts

- `scripts/bench.sh <env_path> <sql_file> <label> [runs=5]` — warm-up + N runs, captures summary headers per run, pulls `system.query_log`, prints per-run JSON and aggregate mean/stddev.
- `scripts/equiv.sh <env_path> <sql_a> <sql_b>` — wraps each in a hash query and compares.
- `scripts/run_query.sh <env_path> <sql_file> [format=Null]` — single-shot for ad-hoc inspection.

All scripts read creds from the `.env` path you pass them; they do not hard-code anything. They print to stderr what they're doing without leaking the password.

## Reference

- `references/clickhouse_optimizations.md` — catalog of transformations with when-to-use, when-not-to, and links to the relevant ClickHouse docs.

Related Skills

humanizer

5
from deadlock-api/deadlock-api

Remove signs of AI-generated writing from text. Use when editing or reviewing text to make it sound more natural and human-written. Based on Wikipedia's comprehensive "Signs of AI writing" guide. Detects and fixes patterns including: inflated symbolism, promotional language, superficial -ing analyses, vague attributions, em dash overuse, rule of three, AI vocabulary words, negative parallelisms, and excessive conjunctive phrases.

blog-post

5
from deadlock-api/deadlock-api

Write high-quality blog posts for the Deadlock API website. Takes a rough topic and content ideas, researches data via the APIs and GitHub repos, optionally generates plots/charts, writes the post in a natural human voice, and runs the humanizer skill over the final output.

shadcn

5
from deadlock-api/deadlock-api

Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".

agent-browser

5
from deadlock-api/deadlock-api

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction.

prompt-optimizer

8
from drvoss/everything-copilot-cli

Use when a rough prompt, vague idea, or task description needs to become a finished copy-pasteable prompt for a chat-based LLM - rewrite it into one ready-to-send prompt with no blanks, no placeholders, and a clear output shape.

token-cost-optimizer

8
from drvoss/everything-copilot-cli

Use before a large Copilot task when model choice, context size, or parallelism could drive up billed usage — estimate cost pressure early and apply Copilot-specific reduction tactics before you run

SQL Query Optimizer

8
from Notysoty/openagentskills

Reviews SQL queries for performance issues and rewrites them with optimized execution plans.

SEO Content Optimizer

8
from Notysoty/openagentskills

Analyzes and rewrites content to maximize search engine visibility without sounding robotic.

LLM Cost Optimizer

8
from Notysoty/openagentskills

Audits an AI application for unnecessary token spend and recommends prompt caching, model routing, and token reduction techniques to cut costs.

Form UX Optimizer

8
from Notysoty/openagentskills

Reviews web forms for usability issues — field ordering, validation messages, error states, and accessibility.

OpenClaw Optimizer Skill

7
from Demerzels-lab/elsamultiskillagent

## Overview

prompt-optimizer

7
from Demerzels-lab/elsamultiskillagent

Evaluate, optimize, and enhance prompts using 58 proven prompting techniques. Use when user asks to improve, optimize, or analyze a prompt; when a prompt needs better clarity, specificity, or structure; or when generating prompt variations for different use cases. Covers quality assessment, targeted improvements, and automatic optimization across techniques like CoT, few-shot learning, role-play, and 50+ more.