데이터베이스 비용 기반 옵티마이저(CBO)의 실행 계획 붕괴 현상과 히스토그램 통계의 기만성
운영 서버에서 갑자기 특정 시간대만 되면 잘만 타던 인덱스 쿼리가 통째로 풀 테이블 스캔으로 추락하며 DB CPU를 100%로 셧다운 시킨 아찔한 금요일 밤이 있었습니다.
관계형 데이터베이스 내부 파싱 엔진의 두뇌라 할 수 있는 비용 기반 옵티마이저(Cost-Based Optimizer, CBO)는 우리가 입력한 SQL 문을 가장 효율적인 기계적 탐색 경로로 매핑해 주는 AI와 같습니다. CBO는 모든 가능한 접근 경로의 디스크 I/O 횟수와 CPU 소모량을 점수(Cost)로 환산하고 이를 비교하여 최적의 실행 계획(Execution Plan) 스케줄을 도출해 냅니다. 이때 이 절대적인 판별 기준이 되는 것이 바로 테이블과 인덱스 칼럼의 '데이터 분포 통계(Statistics)'와 '히스토그램'입니다.
만약 [상태='취소됨']인 데이터가 전체의 과거 5%에 불과하다면 당연히 보조 인덱스를 타는 파이프라인이 저렴합니다. 하지만 제 경우에는 대량 배치 작업이 수행되며 '취소됨' 상태의 로우가 한순간 전체의 30%를 초과해 버렸습니다. 이 상황에서는 인덱스를 통해 로우를 건건이 랜덤 엑세스(Random Access)로 읽어오는 비용이 역전현상을 일으켜, 차라리 하드디스크 전체를 순차적 무식함으로 다 퍼담아버리는 순차 엑세스(Full Table Scan) 방식이 수학적 연산 비용에서 더 낮게 책정된 것입니다.
즉 CBO는 통계만을 믿고 기계적으로 가장 싼 실행 경로를 꺾어버린 것이고, 불운하게도 통계 데이터 자동 수집 기능이 아직 수행되지 않은 타이밍적 착오가 발생하여 이 사태가 발발했습니다. 이를 해결하기 위해 ANALYZE TABLE 명령어로 통계 객체를 긴급히 최신화하고, 중요한 쿼리에 대해서는 벤더사 종속적인 힌트(Index Hint) 구문을 박아 옵티마이저의 자율 판단을 억압하는 룰-베이스 튜닝 코드를 주입해야만 했습니다. 데이터베이스는 수동적인 저장고가 아니라, 끊임없이 우리를 의심하고 판단하는 살아있는 개체라는 것을 각인하게 된 소중한 트러블슈팅 사례입니다.
Related Posts
JVM JIT 컴파일러의 극단적 런타임 최적화: 탈출 분석(Escape Analysis)과 스칼라 치환의 마법
정적 컴파일 언어를 압도하는 자바 머신의 동적 스크립트 프로파일링 및 객체 힙 버림 최적화 기법.
리눅스 eBPF와 XDP를 활용한 커널 바이패스(Kernel Bypass) 초저지연 패킷 필터링 아키텍처
운영체제 네트워크 스택의 병목을 우회하여 디바이스 드라이버 레벨에서 직접 샌드박스 코드를 주입하는 eBPF의 혁명.
스플릿 브레인(Split-Brain) 붕괴를 막는 분산 락(Distributed Lock) 시스템과 펜싱(Fencing) 토큰의 도입
Zookeeper, Redis Redlock의 시계 위임 맹점을 찌르는 가비지 컬렉션 시간 정지(Stop-the-World) 현상 롤백 설계.