+ It ties measured plan costs to the bottleneck and index fix.
- The sort timestamps could be mistaken for exclusive sort time.
Reads the execution plan to locate where time actually goes, before reaching for an index.
| Category | Development › Data & databases |
|---|---|
| Tags | AnalyzingCodeDeveloper |
Diagnose this slow query. Work from the execution plan, in this order: 1. Find the node where actual time is concentrated. Quote it. *Start from measured cost, not from what looks suspicious in the SQL.* 2. Compare estimated rows to actual rows at each node. A large gap means the planner is working from bad statistics, and no index will fix that. 3. Classify the bottleneck: scan that should be a seek / wrong join order / join method mismatch / sort or hash spilling to disk / row count genuinely large. 4. Say where the fix belongs — **index, query rewrite, schema, or statistics** — and why not the others. 5. Give the change, with what to measure after. Also check: - Functions or casts applied to an indexed column in a predicate, which silently disable the index - Leading-column mismatch against a composite index - `SELECT *` pulling columns that force a lookup instead of an index-only read - `OR` conditions that prevent index use - Correlated subqueries running per row Rules: - *Do not recommend an index before step 4.* Most proposed indexes address a node that was not the bottleneck. - If the plan does not explain the time, say so and name what to capture next. - Note if the query is fast and the problem is that it runs too often — that is a different fix entirely.
The reflex is to add an index, which often is not the problem. This finds the expensive plan node first and decides whether the fix belongs in the index, the query, or the schema.
ChatGPT is the most accurate and measured diagnosis. Gemini is directionally sound but makes unsupported claims, while [C] provides no answer.
+ It ties measured plan costs to the bottleneck and index fix.
- The sort timestamps could be mistaken for exclusive sort time.
+ It covers every requested diagnostic step and extra check.
- It overclaims stats freshness, latency, and buffer reductions.
| Criterion | ChatGPT | Gemini | Leader |
|---|---|---|---|
| Instruction following | 10 | 10 | Tie |
| Accuracy | 9 | 7 | ChatGPT +29% |
| Specificity | 10 | 9 | ChatGPT +11% |
| Structure | 10 | 9 | ChatGPT +11% |
| Right length | 9 | 8 | ChatGPT +13% |
Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-25). This is an AI review, not a measurement.
We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.
Query: SELECT o.order_id, o.created_at, o.status, c.name, c.email
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.status = 'PAID'
AND o.created_at >= '2026-08-01'
AND o.created_at < '2026-09-01'
ORDER BY o.created_at DESC
LIMIT 50;
Execution plan: Limit (cost=15234.12..15234.24 rows=50 width=96) (actual time=842.311..842.355 rows=50 loops=1)
-> Sort (cost=15234.12..15298.45 rows=25732 width=96) (actual time=842.309..842.331 rows=50 loops=1)
Sort Key: o.created_at DESC
Sort Method: top-N heapsort Memory: 32kB
-> Hash Join (cost=1123.00..14532.88 rows=25732 width=96) (actual time=12.442..818.204 rows=26890 loops=1)
Hash Cond: (o.customer_id = c.customer_id)
-> Seq Scan on orders o (cost=0.00..13102.00 rows=25732 width=24) (actual time=0.015..782.601 rows=26890 loops=1)
Filter: ((status = 'PAID'::text) AND (created_at >= '2026-08-01 00:00:00'::timestamp) AND (created_at < '2026-09-01 00:00:00'::timestamp))
Rows Removed by Filter: 812340
-> Hash (cost=850.00..850.00 rows=20000 width=80) (actual time=12.201..12.202 rows=20000 loops=1)
-> Seq Scan on customers c (cost=0.00..850.00 rows=20000 width=80) (actual time=0.005..5.332 rows=20000 loops=1)
Planning Time: 0.512 ms
Execution Time: 842.601 ms
Tables and indexes: orders (약 84만 행, 최근 6개월 데이터)
order_id bigint PK
customer_id bigint -- FK customers.customer_id
status text -- 'PAID','CANCELLED','PENDING','REFUNDED'
created_at timestamp
total_amount numeric
인덱스:
orders_pkey (order_id)
idx_orders_customer_id (customer_id)
customers (약 2만 행)
customer_id bigint PK
name text
email text
인덱스:
customers_pkey (customer_id)가장 오래 걸린 노드는 orders 전체 순차 스캔입니다.
Seq Scan on orders o ... (actual time=0.015..782.601 ms rows=26890)Rows Removed by Filter: 812340
전체 약 84만 행을 읽어 26,890건만 남겼습니다. 이후 Hash Join까지 누적 818ms가 걸렸지만, 실질적인 원인은 이 순차 스캔입니다.
Sort는 병목이 아닙니다.
Sort Method: top-N heapsort Memory: 32kBactual time=842.309..842.331
정렬은 32KB 메모리에서 수행됐고 디스크 spill도 없습니다.
| 노드 | 예상 행 | 실제 행 | 판단 |
|---|---|---|---|
| orders 필터 | 25,732 | 26,890 | 약 4.5% 차이, 통계는 양호 |
| customers 스캔 | 20,000 | 20,000 | 정확 |
| Hash Join | 25,732 | 26,890 | 약 4.5% 차이 |
| Sort 입력 | 25,732 | 26,890 | 약 4.5% 차이 |
| Limit | 50 | 50 | 정확 |
큰 추정 오류가 없습니다. 따라서 이 문제는 잘못된 통계 때문에 생긴 것이 아니며, 통계 갱신만으로 해결되지 않습니다.
orders에 대해 seek할 수 있는데 전체를 scan하고 있는 문제입니다.
orders 84만 행을 순차 읽음OR, 상관 서브쿼리는 없음idx_orders_customer_id(customer_id)는 필터의 선두 조건과 맞지 않아 이 조회에 유용하지 않음SELECT *는 아니며 필요한 컬럼만 선택하고 있습니다. 다만 새 인덱스가 order_id, customer_id까지 포함하면 orders 쪽 추가 테이블 조회를 줄일 수 있습니다. customers의 name, email은 고객 PK로 최대 50건만 lookup하면 됩니다.
수정 위치는 인덱스입니다.
CREATE INDEX idx_orders_status_created_at
ON orders (status, created_at DESC)
INCLUDE (order_id, customer_id);
이 인덱스는 다음을 지원합니다.
status = 'PAID'로 선두 범위 탐색created_at 날짜 범위 조건ORDER BY created_at DESCorder_id, customer_id를 인덱스에서 제공그러면 전체 orders scan 대신 조건에 맞는 최신 주문부터 읽고, LIMIT 50에서 조기 종료할 가능성이 큽니다. 고객 정보는 customers_pkey를 이용해 최대 50건만 조회하면 됩니다.
통계가 주원인이 아닌 이유는 예상 행과 실제 행이 이미 가깝기 때문입니다. 쿼리 rewrite도 필요하지 않고, 스키마 변경도 과합니다. 현재 문제는 데이터가 26,890건이라서가 아니라 84만 건을 먼저 읽는 데 있습니다.
인덱스 생성 후 다음을 비교하십시오.
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...
확인할 항목은 다음입니다.
Seq Scan on orders가 Index Scan 또는 Index Only Scan으로 바뀌었는지Rows Removed by Filter가 크게 줄었는지orders의 shared read 블록 수LIMIT 50 근처에서 읽기를 멈추는지이 계획은 한 번 실행하는 것 자체가 느린 경우를 명확히 설명합니다. 반복 실행 빈도가 문제라면 별도로 호출 빈도, 캐시, 애플리케이션 batching을 조사해야 하지만, 제공된 계획만 보면 우선 원인은 실행당 과도한 순차 스캔입니다.
| Advanced Text Converter for Large Datasets | |
| AI-powered data extraction and organization tool | |
| AI2sql SQL Model — Query Generator | |
| Backend Architect | |
| base-R |