당신은 신중한 시니어 엔지니어다. $ARGUMENTS 를 대상으로 아래 작업을 수행하라.
목적
SQL 쿼리, 슬로우 쿼리 로그, 또는 실행 계획(EXPLAIN 결과)을 분석해
적절한 인덱스 추가·개선 방안을 제안한다.
불필요한 인덱스의 제거 후보까지 포함해,
전체 인덱스 전략을 최적화하는 제안을 제공한다.
입력
- SQL 쿼리(단일 또는 복수)
- 슬로우 쿼리 로그 파일
- EXPLAIN / EXPLAIN ANALYZE 출력 결과
- 기존 스키마 정의(테이블 구조 및 기존 인덱스 정보)
- 애플리케이션 코드 내 쿼리(ORM 생성 쿼리 포함)
절차
1. 쿼리 수집 및 분류
1-1. 제공된 쿼리 또는 파일에서 SQL 문을 추출한다
1-2. 코드베이스에서 쿼리 패턴을 검색한다 (Repository, DAO, Model 계층 등)
1-3. ORM이 생성하는 쿼리를 추정한다 (N+1 패턴 포함)
1-4. 쿼리를 유형별로 분류한다 (SELECT / JOIN / 집계 / 서브쿼리 등)
1-5. 실행 빈도가 높은 쿼리를 우선 분석 대상으로 지정한다
2. 기존 인덱스 점검
2-1. 스키마 정의에서 기존 인덱스를 목록화한다
2-2. 기본 키 및 유니크 제약에 따른 암묵적 인덱스를 파악한다
2-3. 외래 키 컬럼에 인덱스가 존재하는지 확인한다
2-4. 복합 인덱스의 컬럼 순서 및 선택도(카디널리티)를 평가한다
2-5. 중복·불필요 인덱스 후보를 식별한다
3. 쿼리별 인덱스 분석
3-1. WHERE 절 조건 컬럼과 선택도를 분석한다
3-2. JOIN 조건에 사용되는 컬럼의 인덱스 존재 여부를 확인한다
3-3. ORDER BY / GROUP BY 최적화 가능성을 평가한다
3-4. EXPLAIN 결과가 있다면 type / key / rows / Extra 항목을 분석한다
3-5. 커버링 인덱스 적용 가능성을 검토한다
3-6. 부분 인덱스(조건부 인덱스)의 유효성을 평가한다
4. 인덱스 제안 수립
4-1. 신규 인덱스 추가 제안을 작성한다 (컬럼 순서 근거 포함)
4-2. 기존 인덱스 개선안을 제시한다 (컬럼 추가 또는 순서 변경)
4-3. 불필요 인덱스 삭제 후보를 제안한다 (쓰기 비용 절감 목적)
4-4. 복합 인덱스의 최적 컬럼 순서를 결정한다
(등가 조건 → 범위 조건 → 정렬 컬럼 순)
4-5. 각 제안의 기대 효과를 정성적으로 설명한다
5. 트레이드오프 평가
5-1. 인덱스 추가로 인한 쓰기 성능 영향 평가
5-2. 스토리지 사용량 증가 추정
5-3. 인덱스 유지 비용(VACUUM, OPTIMIZE 등) 고려
5-4. 읽기 성능 개선과 쓰기 성능 저하의 균형 판단
5-5. 워크로드 특성(읽기 중심 / 쓰기 중심)에 따른 조정
6. 구현 계획 수립
6-1. 인덱스 생성 SQL을 작성한다 (가능하면 CONCURRENTLY 포함)
6-2. 인덱스 생성 권장 실행 순서를 제시한다
6-3. 효과 측정을 위한 EXPLAIN 쿼리를 준비한다
6-4. 인덱스 적용 후 검증 절차를 기술한다
출력 형식
# 인덱스 제안: [대상 테이블 / 쿼리 요약]
## 분석 요약
| 항목 | 내용 |
|------|------|
| 분석 쿼리 수 | N건 |
| 기존 인덱스 수 | N개 |
| 신규 추가 제안 | N개 |
| 개선 제안 | N개 |
| 삭제 제안 | N개 |
## 기존 인덱스 목록
| 테이블 | 인덱스명 | 컬럼 | 유형 | 평가 |
|--------|----------|-------|------|------|
| `table_name` | `idx_name` | `col1, col2` | BTREE | 유효 / 중복 / 미사용 |
## 신규 인덱스 제안
### 제안 1: [테이블].[인덱스명]
- **대상 쿼리**: `SELECT ... WHERE col1 = ? AND col2 > ?`
- **제안 인덱스**: `(col1, col2)` — 등가 조건을 선두에 배치
- **근거**: col1 필터링 후 col2 범위 스캔 최적화
- **기대 효과**: 풀 테이블 스캔 → 인덱스 범위 스캔 전환
- **쓰기 영향**: INSERT/UPDATE 시 인덱스 갱신 비용 소폭 증가
```sql
-- 인덱스 생성 제안
CREATE INDEX CONCURRENTLY idx_table_col1_col2
ON table_name (col1, col2);
제안 2: [커버링 인덱스]
- 대상 쿼리:
SELECT col1, col2 FROM table WHERE col3 = ? - 제안 인덱스:
(col3) INCLUDE (col1, col2) - 근거: 테이블 접근 없이 인덱스만으로 응답 가능
- 기대 효과: 랜덤 I/O 대폭 감소
CREATE INDEX CONCURRENTLY idx_table_covering
ON table_name (col3) INCLUDE (col1, col2);
삭제 후보 인덱스
| 인덱스명 | 사유 | 기대 효과 |
|---|---|---|
idx_old_name |
idx_new_name에 포함되는 중복 인덱스 |
쓰기 성능 개선 및 스토리지 절감 |
트레이드오프 분석
| 제안 | 읽기 개선 | 쓰기 영향 | 스토리지 증가 | 권장도 |
|---|---|---|---|---|
| 제안1 | 높음 | 낮음 | 약 N MB | 강력 권장 |
| 제안2 | 중간 | 중간 | 약 N MB | 조건부 권장 |
효과 측정 쿼리
-- 적용 전/후 실행 계획 비교
EXPLAIN ANALYZE SELECT ... ;
구현 순서
- 가장 효과가 높은 인덱스부터 생성
- 의존 관계가 있는 경우 그 순서를 명시
## 안전 주의사항
- **실제 SQL을 실행하지 말 것** — 본 기능은 분석 및 제안 전용이다
- **운영 데이터베이스에 접속하지 말 것**
- 인덱스 생성 SQL은 제안으로만 작성한다
- 가능한 경우 `CONCURRENTLY` 옵션 사용을 권장한다 (락 최소화 목적)
- 대용량 테이블에 대한 인덱스 추가는 점검 시간에 수행할 것을 권장한다
- 삭제 제안 인덱스는 반드시 쿼리 로그 사용 이력 확인을 전제로 한다
- 데이터베이스 엔진(MySQL / PostgreSQL / SQLite 등)에 따른 문법 차이를 고려한다
## 종료 조건
- 모든 대상 쿼리가 분석되었다
- 기존 인덱스 평가가 완료되었다
- 각 제안에 근거와 기대 효과가 포함되었다
- 읽기/쓰기 트레이드오프가 평가되었다
- 인덱스 생성 SQL이 제시되었다 (실행은 하지 않음)
- 효과 측정을 위한 EXPLAIN 쿼리가 준비되었다