Files
2nd/10_Wiki/Topic_Programming/Coding/DB_Index_Strategy.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.0 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
db-index-strategy DB Index 전략 — 만들 것과 만들지 말 것 Coding draft B conceptual 2026-05-09 2026-05-09
database
index
query-optimization
postgres
vibe-coding
language applicable_to
Postgres / MySQL
Backend
B-tree
composite index
partial index
covering index

DB Index 전략

인덱스는 읽기 빨라지지만 쓰기 느려짐. 무지성으로 만들지 말고 EXPLAIN ANALYZE 보고 결정. composite index 는 컬럼 순서가 핵심. 6개 이상 인덱스 가진 테이블은 검토 대상.

📖 핵심 개념

  • 인덱스는 별도 자료구조 (B-tree). 매 INSERT/UPDATE 마다 갱신.
  • WHERE / JOIN / ORDER BY 의 등호 / 범위 / 정렬 컬럼이 인덱스 후보.
  • composite (a, b) 는 (a) 만 검색해도 사용 가능, (b) 만은 X.

💻 코드 패턴

EXPLAIN ANALYZE 로 결정

EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 10;
-- Seq Scan ← 느림. user_id 인덱스 추가 후 비교.

Composite index — 순서가 중요

-- 자주 함께 검색: (user_id, status, created_at)
CREATE INDEX idx_orders_user_status_created
  ON orders (user_id, status, created_at DESC);

-- 사용 가능:
-- WHERE user_id = ?
-- WHERE user_id = ? AND status = ?
-- WHERE user_id = ? AND status = ? AND created_at > ?
-- WHERE user_id = ? ORDER BY created_at DESC
-- 사용 불가:
-- WHERE status = ?  (앞 컬럼 skip)

규칙: = 컬럼 → IN 컬럼 → 범위 컬럼 → 정렬 컬럼 순서.

Partial index — 작은 도메인만

-- 90%의 행이 status='completed' 인 경우, active 만 인덱스
CREATE INDEX idx_orders_active_user
  ON orders (user_id) WHERE status IN ('pending', 'processing');
-- 인덱스 크기 작음, 갱신 비용 낮음

Covering / INCLUDE

CREATE INDEX idx_users_email_inc ON users(email) INCLUDE (name, avatar_url);
-- WHERE email = ? + SELECT name, avatar_url 만 → 테이블 안 읽고 인덱스로 종료

Functional / Expression

CREATE INDEX idx_users_lower_email ON users (LOWER(email));
-- WHERE LOWER(email) = LOWER(?) 사용

Index 미사용 패턴

-- ❌ 함수 호출 → 인덱스 X
WHERE LOWER(email) = 'foo'         -- 위 functional 인덱스 없으면
WHERE created_at::date = '2025-01-01'  -- → BETWEEN 로

-- ❌ leading wildcard
WHERE email LIKE '%@example.com'   -- B-tree X. trgm/GIN 필요

-- ❌ OR 가 다른 컬럼
WHERE user_id = 1 OR email = 'x'   -- 둘 다 별도 인덱스 + Bitmap OR

🤔 의사결정 기준

컬럼 인덱스?
Primary key 자동
Foreign key — JOIN 빈번
Unique 제약 자동
자주 WHERE
자주 ORDER BY + LIMIT
카디널리티 낮음 (boolean) — 보통 무용. partial 가능
Text 검색 (LIKE %x%) trgm / GIN
JSON 안 검색 GIN on jsonb
시계열 최신만 partial WHERE created_at > now() - interval '30d'

안티패턴

  • 모든 컬럼에 단일 인덱스: write 폭증 + planner 가 못 고름. composite 가 보통 답.
  • composite index 컬럼 순서 무관 가정: (a, b) 와 (b, a) 다름. EXPLAIN 으로.
  • 거대 테이블 동기 CREATE INDEX: write lock 길게. CONCURRENTLY 사용.
  • 사용 안 되는 인덱스 청소 안 함: pg_stat_user_indexes idx_scan = 0 인 거 정기 청소.
  • VACUUM / ANALYZE 안 함: 통계 stale → planner 잘못된 선택.
  • 인덱스 = 만능 가정: 작은 테이블은 Seq Scan 이 더 빠름.
  • timestamp 그대로 인덱스 + 매일 새 값: 인덱스 끝부분만 hot. BRIN 도 검토.

🤖 LLM 활용 힌트

  • 새 쿼리 추가 시: "EXPLAIN ANALYZE 결과 + 인덱스 추천" 함께 요청.
  • composite index 컬럼 순서 = (=) (IN) (range) (order).
  • Postgres 면 partial / INCLUDE / GIN / BRIN 도 후보.

🔗 관련 문서