데이터베이스 분석
절차
- 대상과 목적을 구분한다. 셋 중 무엇인가 — 스키마 설계 검토, 느린 쿼리 개선, 마이그레이션 안전성 확인. 목적에 따라 봐야 할 것이 다르다.
- 추측 전에 사실을 모은다. 테이블 행 수, 카디널리티, 실제 실행계획, 실제 파라미터 값. 이것 없이 인덱스를 제안하지 않는다.
- 가장 큰 비용부터 본다. 전체 스캔 → 조인 순서 → 정렬/임시 테이블 → 반환 행 수.
- 하나씩 바꾸고 다시 측정한다. 여러 변경을 동시에 적용하면 무엇이 효과였는지 알 수 없다.
스키마 검토
- 각 테이블의 한 행이 무엇 하나를 뜻하는지 한 문장으로 말할 수 있는가. 못 하면 책임이 섞인 것이다.
- 자연키를 PK로 쓸 때 그 값이 바뀔 수 있는가
- NULL 이 "값 없음"인지 "해당 없음"인지 구분되는가. 의미가 두 개면 컬럼을 나눈다.
- 상태 컬럼이 문자열 자유값인가 (제약 없는 상태값은 반드시 오염된다)
- 금액·수량에 부동소수점을 쓰고 있는가
- 시각 컬럼의 타임존 기준이 명시되어 있는가
- 삭제가 물리 삭제인가 논리 삭제인가, 그리고 조회 경로 전체가 그것을 일관되게 반영하는가
- 정규화를 푸는 결정에는 읽기 패턴 근거가 있어야 한다. "빠를 것 같아서"는 근거가 아니다.
쿼리 / 인덱스
- 실행계획을 실제로 확인한다(
EXPLAIN/EXPLAIN ANALYZE). 예상 비용과 실제 행 수 차이가 크면 통계가 낡았거나 조건 추정이 틀린 것이다. - 인덱스 선정 기준:
- WHERE 등치 조건 컬럼을 앞에, 범위 조건 컬럼을 뒤에 둔다
- ORDER BY 를 인덱스로 흡수할 수 있는지 본다
- 선택도가 낮은 컬럼(값 종류가 적은 컬럼) 단독 인덱스는 대개 무용하다
- 커버링으로 만들면 조회가 인덱스만으로 끝나는지 검토한다
- 인덱스를 추가하면 쓰기 비용이 늘어난다. 읽기 이득과 쓰기 부담을 같이 적는다.
- 인덱스가 안 타는 흔한 이유: 컬럼에 함수/연산 적용, 타입 불일치 암묵 변환, 선행 와일드카드 LIKE, OR 조건 분기
- 반환 행 수를 먼저 줄인다. 페이징 없는 전체 조회는 인덱스로 구제되지 않는다.
- 큰 오프셋 페이징은 커서 기반으로 바꾸는 것을 검토한다.
마이그레이션 안전성
- 잠금 시간을 확인한다. 큰 테이블에 대한 컬럼 추가/타입 변경/인덱스 생성은 서비스 중단을 만들 수 있다.
- 파괴적 변경은 한 번에 하지 않는다. 확장 → 이중 쓰기 → 백필 → 읽기 전환 → 제거 순으로 나눈다.
- NOT NULL 컬럼 추가는 기본값과 백필 계획이 같이 있어야 한다.
- 되돌리는 방법을 먼저 적는다. 되돌릴 수 없는 단계(데이터 삭제)는 별도 배포로 분리한다.
- 배포와 마이그레이션의 순서를 명시한다. 구버전 애플리케이션이 새 스키마에서 동작하는가.
보고 형식
현상: <측정된 사실>
원인: <실행계획/스키마 근거>
제안: <변경 1개> — 기대 효과 / 부작용(쓰기 비용, 잠금 시간)
검증: <다시 측정할 지표>
대상 프로젝트의 실제 스키마·테이블명·쿼리는 그 프로젝트 안에서 확인한다. 여기에 적지 않는다.