# SQL Query Optimizer for D1, SQLite and Turso

SQL Query Optimizer for D1, SQLite and Turso is a tested SKILL.md that reviews SQL queries, schemas and migrations for SQLite, Cloudflare D1 and Turso, where the bill and the speed follow the rows a query READS, not the rows it returns; an agent buys it once for $0.01 over x402.

- Page: https://aiskills402.com/skills/sql-query-optimizer
- Category: Code & Engineering (https://aiskills402.com/categories/code)
- Price: $0.01 once, USD-priced, paid in USDC on Base over x402. Price as loaded on this page. The 402 response your agent receives is authoritative.
- Version: 1.0.0
- Card (JSON): https://api.aiskills402.com/v1/skills/sql-query-optimizer

## Use it when

Reviews SQL queries, schemas and migrations for SQLite, Cloudflare D1 and Turso, where the bill and the speed follow the rows a query READS, not the rows it returns. Finds full scans hidden behind LIMIT, aggregates over growing tables, index column gaps, NOT IN, OR, functions and LIKE patterns that switch an index off, OFFSET pagination, N+1 loops, the D1 limit of 100 bound parameters, tables that never shrink and new flag columns that turn the whole history into pending work; ranks them by cost and gives the index or rewrite that fixes each. Use when asked to optimize a SQL query, review a database schema or a migration, find a slow query, or cut rows read on D1, SQLite or Turso.

## Not for

PostgreSQL or MySQL tuning, where the planner and the costs differ, though many patterns carry over; running or timing your queries; choosing a database. It reads the SQL you paste, so anything that depends on data it was not shown, such as real table sizes, is stated as an assumption.

## Tested, honestly

Tested 2026-10-03.

- Strong model (claude-sonnet-5-5 (Claude Code alias "sonnet")): Named the planted problem with the right code in all 11 cases that had one and answered 'No findings.' for the clean schema. Its fixes were working SQL: an index on (scope, created_at) for the gap, a partial index on status = 'pending' for the empty poll, a range on the raw timestamp, keyset pagination, chunks of 50 for D1's 100-parameter limit, a backfill in the same migration, the partial index's WHERE copied into ON CONFLICT. At first 2 of 12 were scored as failures because our pattern accepted only one of the two fixes the skill names; Sonnet chose the other (a latest-prices table kept by the writer; day bounds computed in SQL), both were confirmed with EXPLAIN QUERY PLAN, and the same answers rescored at 12 of 12.
- Weak model (claude-haiku-4-5-20251001 (Claude Code alias "haiku")): Found the planted problem with the right code and a working fix in all 11 cases that had one, including the Bulgarian request. On the clean schema it invented a finding under a code of its own and proposed DELETE ... LIMIT, which standard SQLite rejects as a syntax error. With Haiku, run any suggested statement before relying on it.

Note: Twelve fictional schemas and queries: eleven with one planted problem each (aggregate scan, index gap, NOT IN, OR on a flag, empty queue poll, function on a column, prefix LIKE, OFFSET with COUNT, D1 parameter limit, flag column without backfill, ON CONFLICT against a partial index) and one clean; one request in Bulgarian. Every planted plan and every accepted fix was confirmed with EXPLAIN QUERY PLAN on SQLite 3.53 without ANALYZE. Machine checks look for the finding code and a working fix; one run per model and case. The rescoring of stored answers after two patterns were widened is in results-2026-10-03-recheck.md.

Full summary: https://aiskills402.com/skills/sql-query-optimizer/tests

## Example

### English (claude-sonnet-5-5)

Before:

> Schema: CREATE TABLE events (id INTEGER PRIMARY KEY, scope TEXT NOT NULL, symbol TEXT NOT NULL, created_at INTEGER NOT NULL, payload TEXT); CREATE INDEX idx_events ON events(scope, symbol, created_at); The table has about 2 million rows; 90% of them have scope = 'market'. Old rows are deleted after 30 days. Runs every 30 seconds: SELECT * FROM events WHERE scope = 'market' AND created_at > ?…

After:

> [INDEX-GAP] `SELECT * FROM events WHERE scope = 'market' AND created_at > ? ORDER BY created_at DESC LIMIT 50` Reads: the index `(scope, symbol, created_at)` is searched by `scope` only, because `symbol` has no condition. That means every `market` row still inside the 30-day window is read (about 1.8M at 90% of 2M), then sorted in a temp B-tree before LIMIT 50 applies.…

### Bulgarian (claude-sonnet-5-5)

Before:

> Schema: CREATE TABLE jobs (id INTEGER PRIMARY KEY, status TEXT NOT NULL, run_at INTEGER NOT NULL, payload TEXT); The table keeps every job ever run (about 300,000 rows, 'done' or 'failed'). New jobs arrive a few times a day. A worker polls every minute; most polls find nothing: SELECT * FROM jobs WHERE status = 'pending' AND run_at <= ? ORDER BY run_at LIMIT 90;

After:

> **[EMPTY-PATH]** `SELECT * FROM jobs WHERE status = 'pending' AND run_at <= ? ORDER BY run_at LIMIT 90` Reads: цялата таблица `jobs` (~300 000 реда) при всяко пускане на worker-а. Заявката няма индекс освен първичния ключ. Когато няма чакащи задачи, LIMIT никога не се достига и заявката прочита всички редове.…

## What is in the file

- Hard rules
- Finding codes
- Report format
- Work in this order
- Short example

## Languages

English, Bulgarian

## How to buy

Agent (HTTP):

1. GET https://api.aiskills402.com/v1/skills/sql-query-optimizer/file without a payment header. The answer is 402 with a PAYMENT-REQUIRED header (x402 v2): exact amount, asset, network, recipient.
2. Sign `accepts[0]` with an x402 client (for example @x402/core + @x402/evm).
3. Repeat the GET with the signature in the PAYMENT-SIGNATURE header. The answer is 200 with the file, its sha256 and a re-download token.

Agent (MCP): https://mcp.aiskills402.com/mcp — free tools search_skills, get_skill, redownload_skill. Buying itself is over HTTP.

Full flow: https://aiskills402.com/docs

## The file

- Version: 1.0.0
- Size: 9.8 KB (10077 bytes)
- SHA-256: 09a9cd1326ed96725c5c9da3fe6c5909ff35ccacd113a0a60939bc6b0ba874f5
- Updated: 2026-10-03
- New versions are free through your re-download token.

## Versions

### 1.0.0 (2026-10-03)

First release: reviews SQL, schemas and migrations for SQLite, Cloudflare D1 and Turso by rows read; fifteen finding codes, each with a concrete index or rewrite, ranked by cost, with a way to verify the fix.

## License

Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Terms: https://aiskills402.com/docs#license

## FAQ

### Does it work for PostgreSQL?

It is written for SQLite and the services built on it, Cloudflare D1 and Turso, where the bill follows the rows a query reads. Several patterns, such as an index column gap or a function wrapped around an indexed column, hurt in PostgreSQL too, but its planner differs, so treat the advice there as a lead and check it with EXPLAIN.

### How do I know a suggested fix really helps?

Each report ends with a way to check: run EXPLAIN QUERY PLAN against a local SQLite copy of the schema and look for SEARCH instead of SCAN, and on D1 compare meta.rows_read before and after. We confirmed every planted problem and every accepted fix in our tests the same way.

### Will it invent problems in healthy SQL?

Claude Sonnet answered 'No findings.' for our clean schema. Claude Haiku invented a finding there and suggested a DELETE with LIMIT that standard SQLite rejects, so with Haiku, run each suggested statement before relying on it.

### What is the D1 parameter finding about?

D1 rejects a statement with more than 100 bound parameters. An id list built from your data, or a multi-row insert, uses one parameter per value, so code that worked at launch fails on its own when a reader saves the 101st item. The skill points to such places and suggests chunks of 50.

## Related skills

- [Code Review](https://aiskills402.com/skills/code-review.md): $0.01 once
- [Text to JSON: Extract Data Without Guessing](https://aiskills402.com/skills/text-to-json.md): $0.01 once

## Measurement limits

- Models other than the two named above were not run.
- Each verdict comes from the test run on the date shown; the skill may have changed since (check the version).
- Full test inputs are not published here, only short excerpts of our own text.
- Results on your own texts, languages and domains can differ.

Offer note: Paid in USDC (USD-pegged) over x402 by an AI agent; one-time.
