수천만 건 공공데이터 조회 성능을 지키는 MySQL 8.0 파티셔닝과 파티션 프루닝(Partition Pruning) 설계

수천만 건 공공데이터 조회 성능을 지키는 MySQL 8.0 파티셔닝과 파티션 프루닝(Partition Pruning) 설계
수천만 건 공공데이터 조회 성능을 지키는 MySQL 8.0 파티셔닝과 파티션 프루닝(Partition Pruning) 설계

국가 공공데이터 포털(data.go.kr)이나 지자체 OpenAPI로부터 건축물대장, 부동산 실거래가, 기상 관측 이력 등 대용량 시계열·이력 데이터를 주기적으로 수집·적재하다 보면, 단일 테이블의 누적 레코드가 수천만 건에서 수억 건 단위로 급격히 증가하게 됩니다. 단일 테이블 규모가 GB 단위를 넘어 수십 GB에 도달하는 시점부터는 B+Tree 인덱스를 아무리 최적화하더라도 심각한 구조적 문제에 직면하게 됩니다.

대표적으로 인덱스 트리의 깊이(Depth)가 깊어져 단일 탐색 시 거쳐야 하는 I/O 횟수가 증가하고, 버퍼 풀(Buffer Pool)의 크기를 초과하는 방대한 워킹셋(Working Set)으로 인해 캐시 적중률(Hit Ratio)이 급감하며, 오래된 과거 데이터를 삭제(DELETE)할 때 발생하는 InnoDB Undo 로그 부하와 테이블 단편화(Fragmentation)가 백엔드 서버를 마비시킵니다. 본 글에서는 이러한 대규모 공공데이터 백엔드 환경에서 쿼리 처리 성능과 스토리지 관리 효율을 극대화하기 위한 MySQL 8.0 파티셔닝(Table Partitioning) 아키텍처와 파티션 프루닝(Partition Pruning)의 실무 최적화 설계를 심층 분석합니다.

1. 대용량 단일 테이블의 한계와 파티셔닝의 물리적 원리

MySQL 8.0의 InnoDB 엔진에서 파티셔닝은 물리적으로 분리된 여러 개의 .ibd 테이블스페이스 파일을 하나의 논리적 테이블로 묶어 관리하는 기술입니다.

  • 버퍼 풀 워킹셋 국소화(Locality): 파티셔닝을 적용하면 최근 수집된 데이터(예: 최근 3개월 실거래가)의 파티션 페이지만 버퍼 풀에 상주하므로, 전체 수억 건의 인덱스 페이지가 캐시를 오염시키는 현상을 완벽히 방어합니다.
  • I/O 병목 해소와 인덱스 트리 경량화: 수천만 건 규모의 거대한 단일 B+Tree 대신, 파티션별로 독립적인 경량 B+Tree가 생성되므로 인덱스 높이(Height)가 낮아져 탐색 레이턴시가 크게 단축됩니다.
  • 무중단 스토리지 회수 (Fast Drop): 수백만 건의 지난 데이터를 DELETE FROM ...으로 삭제하면 수 시간의 락(Lock) 경합과 디스크 I/O가 발생하지만, 파티션 드롭(ALTER TABLE ... DROP PARTITION)은 물리 파일의 메타데이터만 삭제하므로 수 밀리초(ms) 만에 완료됩니다.

2. MySQL 8.0 RANGE COLUMNS 파티셔닝 DDL 설계

시계열 공공데이터에 가장 적합한 모델은 날짜 컬럼을 기준으로 범위를 분할하는 RANGE COLUMNS 파티셔닝입니다. RANGE와 달리 TO_DAYS() 같은 변환 함수 없이 DATE 또는 DATETIME 타입을 원형 그대로 사용할 수 있어 직관적이고 최적화에 유리합니다.

-- 대용량 부동산 실거래 공공데이터 파티션 테이블 DDL
CREATE TABLE public_real_estate_tx (
    tx_id BIGINT NOT NULL AUTO_INCREMENT,
    deal_date DATE NOT NULL,
    region_code VARCHAR(10) NOT NULL,
    apt_name VARCHAR(100) NOT NULL,
    exclusive_area DECIMAL(8, 2) NOT NULL,
    deal_amount BIGINT NOT NULL,
    floor INT,
    build_year INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    -- 파티션 키(deal_date)는 반드시 Primary Key의 복합 구성 요소여야 함
    PRIMARY KEY (tx_id, deal_date),
    INDEX idx_region_deal (deal_date, region_code, deal_amount)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY RANGE COLUMNS (deal_date) (
    PARTITION p2026_01 VALUES LESS THAN ('2026-02-01'),
    PARTITION p2026_02 VALUES LESS THAN ('2026-03-01'),
    PARTITION p2026_03 VALUES LESS THAN ('2026-04-01'),
    PARTITION p2026_04 VALUES LESS THAN ('2026-05-01'),
    PARTITION p2026_05 VALUES LESS THAN ('2026-06-01'),
    PARTITION p2026_06 VALUES LESS THAN ('2026-07-01'),
    PARTITION p2026_07 VALUES LESS THAN ('2026-08-01'),
    PARTITION p2026_08 VALUES LESS THAN ('2026-09-01'),
    PARTITION p2026_09 VALUES LESS THAN ('2026-10-01'),
    PARTITION p2026_10 VALUES LESS THAN ('2026-11-01'),
    PARTITION p2026_11 VALUES LESS THAN ('2026-12-01'),
    PARTITION p2026_12 VALUES LESS THAN ('2027-01-01'),
    PARTITION p_future VALUES LESS THAN (MAXVALUE)
);

3. 파티션 프루닝(Partition Pruning) 검증과 쿼리 안티패턴

파티셔닝의 성능 이점을 취하기 위한 절대적 전제 조건은 옵티마이저가 쿼리 조건절을 분석하여 대상 파티션만 핀포인트로 읽는 ‘파티션 프루닝’이 반드시 발동되어야 한다는 점입니다.

-- 1. 파티션 프루닝 정상 발동 검증
EXPLAIN
SELECT region_code, COUNT(*), AVG(deal_amount)
FROM public_real_estate_tx
WHERE deal_date BETWEEN '2026-09-01' AND '2026-09-30'
GROUP BY region_code;

-- 실행 계획 분석 결과:
-- partitions 열에 'p2026_09' 파티션 단 하나만 표시되는지 확인 필수
⚠️ 파티션 프루닝을 무력화하는 3대 안티패턴:
1. WHERE 절 좌변 가공: WHERE DATE_FORMAT(deal_date, '%Y-%m') = '2026-09'처럼 함수로 감싸면 옵티마이저가 범위를 특정하지 못해 전체 파티션을 풀스캔(All Partitions Scan)합니다.
2. 타입 불일치(Implicit Casting): 날짜 컬럼에 문자열 형식이나 타임스탬프 포맷을 불일치하게 바인딩하여 내부 암묵적 형변환이 일어나는 경우 프루닝이 실패합니다.
3. Primary Key / Unique Key 제약: MySQL의 제약 조건상 테이블의 모든 Unique Key(PK 포함)는 파티션 표현식에 사용된 모든 컬럼을 포함해야 합니다. 파티션 키가 빠진 인덱스는 생성이 불가능합니다.

4. 무중단 롤링 파티션(Rolling Partition) 자동화 관리

시계열 공공데이터 테이블은 시간이 지남에 따라 미래 파티션을 사전에 생성(REORGANIZE PARTITION)하고, 보존 기한이 만료된 과거 파티션을 드롭하는 주기적인 유지보수 파이프라인이 필수적입니다.

-- 미래 파티션 안전 분할 (p_future MAXVALUE 파티션 재구성)
ALTER TABLE public_real_estate_tx
REORGANIZE PARTITION p_future INTO (
    PARTITION p2027_01 VALUES LESS THAN ('2027-02-01'),
    PARTITION p_future VALUES LESS THAN (MAXVALUE)
);

-- 보존 기한 초과 데이터 무중단 아카이빙 및 즉각 삭제
-- 1단계: 임시 보관 테이블과 데이터 고속 교체 (메타데이터 스왑)
ALTER TABLE public_real_estate_tx
EXCHANGE PARTITION p2026_01 WITH TABLE archive_real_estate_tx;

-- 2단계: 빈 파티션 0.01초 만에 제거
ALTER TABLE public_real_estate_tx
DROP PARTITION p2026_01;

5. 결론 및 실무 권장 가이드라인

수천만 건에 달하는 대용량 공공데이터를 안정적으로 서빙하기 위해서는 단순 하드웨어 스케일업(Scale-up)에 의존하기 전에 데이터의 물리적 저장 구조를 비즈니스 접근 패턴과 일치시켜야 합니다. RANGE COLUMNS 파티셔닝과 엄격한 파티션 프루닝 쿼리 패턴을 결합하면 버퍼 풀의 효율성을 90% 이상 보존하면서 단일 테이블 한계를 넘어서는 견고한 백엔드 시스템을 구축할 수 있습니다.


출처 및 1차 공식 기술 문서

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다