query-optimization
Testing & QualityAdvanced query tuning: join algorithms, skip index selection, EXPLAIN interpretation, ProfileEvents profiling, and optimizer settings. Also the autonomous diagnose-loop for open-ended questions like why is my database slow?
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/chmonitor/chmonitor/blob/HEAD/.agents/skills/query-optimization/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/query-optimization, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Query Optimization
Autonomous Diagnose Loop ("why is my database slow?")
Use this loop when the question is open-ended — no specific query was named —
and the agent must find what's slow on its own, not just tune a query the user
already pasted (for that, load query-tuning-advisor instead).
Recommend-only, same as advisor-tools and control-tools: this loop never
executes DDL, never rewrites a query in place, and never runs an optimize/kill
action on its own. Every step below only reads system tables; the final output
is DDL/rewrite text for the user to review and run themselves.
- List slow patterns — call
list_slow_query_patterns(notget_slow_queries, which returns individual runs, not grouped patterns). Defaults to the last 24h, ranked by total duration. Identify the top 1-3 patterns bytotal_duration(overall cost) and separately note any pattern with a highp99_durationrelative top50_duration(tail-latency outlier) or a nonzeroerrorscount. - EXPLAIN the worst pattern — take
normalized_queryfrom step 1 and callexplain_querywithtype: 'indexes'first (are granules being pruned?), thentype: 'plan'if the indexes output doesn't explain the cost (e.g. a large JOIN build side or heavy aggregation step). See "EXPLAIN Analysis" below for what to look for. - Get ranked recommendations — call
get_optimization_recommendationswith the same query (sqlor aqueryIdfromsystem.query_log) to get ranked skip-index / projection / partition-key / PREWHERE suggestions with DDL text, rationale, risk, and effort. - Propose, don't apply — present the top 1-2 recommendations with their
DDL/rewrite text, expected impact, and risk. If a pattern also looks like a
good materialized-view/projection candidate (same GROUP BY shape recurring
often — see
callsin step 1), also callrecommend_materialized_viewand present that as an alternative. Explicitly tell the user these are recommendations to review and run themselves — mirror the control-tools confirmation posture, just for read-only advice instead of a destructive action. - Repeat for the next pattern only if the user wants more than one addressed, or if step 1 flagged both a total-duration offender and a separate tail-latency/error offender.
JOIN Strategies
join_algorithmsetting:hash(default, in-memory),partial_merge(spills to disk for large right table),auto(lets ClickHouse decide)JOIN ... USINGavoids repeated column names vsONfor same-name columns- Filter both sides before joining to reduce intermediate data
GLOBAL JOINbroadcasts the right table to all shards for distributed queries
EXPLAIN Analysis
EXPLAIN PLAN— logical plan, shows projection/pushdown transformationsEXPLAIN PIPELINE— physical execution with parallelism info and port countsEXPLAIN INDEXES— which indexes fire, granules selected vs total- Look for: full table scans, missing index usage, excessive granule reads
Index Usage
- Skip index types with use-cases:
minmax— range queries on numeric/date columnsset(N)— equality on low-cardinality columns, stores N unique values per granulebloom_filter— equality on high-cardinality stringstokenbf_v1— tokenized text search (logs, URLs)
- Check effectiveness via
ProfileEvents['SelectedRows']vs result size
Query Profiling
ProfileEventsmap counters:SelectedRows,MergedRows,FileOpen,SeekCountnormalized_query_hashto group parameterized query variantssystem.query_logcolumns:query_duration_ms,memory_usage,read_bytes
Optimizer Settings
enable_optimizer = 1— activates ClickHouse's new cost-based query optimizer (v22.6+)max_threads— controls query parallelism; higher = faster but more memory; lower for concurrent workloadsprefer_localhost_replica = 1— avoids network round-trip by reading from local replica on distributed queriessystem.query_plan(v23.6+) — persisted query plans for analysis across runs