파티션은 논리적으로 하나의 테이블이지만 물리적으로는 여러 개의 테이블로 분리하고 관리하는 기능이다.
주로 대용량 테이블에 사용할 법하지만, 파티션을 쓴다고 무조건 성능이 좋아지는 것은 아니다.
파티션을 사용해야 하는 상황은 다음과 같다.
인덱스는 SELECT 쿼리에서 쓰일 뿐 아니라 UPDATE와 DELETE 쿼리에서도 필요하다.
인덱스가 커질 수록 SELECT 쿼리 뿐 아니라 INSERT, UPDATE, DELETE 작업도 느려진다.
한 테이블의 인덱스의 크기가 MySQL이 사용할 수 있는 메모리 크기보다 크다면, 성능은 더욱 나빠진다.
대용량 테이블을 하나로 사용하면, 인덱스의 워킹 셋 하나만 있게 된다.
파티션을 하여 데이터와 인덱스를 분할하면, 파티션된 인덱스의 워킹 셋이 메모리에 올라갈 수 있게 된다.
※ 워킹 셋이란 전체 데이터에서 실질적으로 사용되는 일부 데이터를 말한다.
Partition을 생성하는 쿼리는 다음과 같다.
CREATE TABLE tb_article (
article_id INT NOT NULL,
reg_date DATETIME NOT NULL,
PRIMARY KEY(article_id, reg_date)
) PARTITION BY RANGE ( YEAR(reg_date) ) (
PARTITION p2019 VALUES LESS THAN (2020),
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p9999 VALUES LESS THAN MAXVALUE
);
여기서 reg_date 컬럼을 Partition의 기준을 설정했다.
Partition의 기준이 되는 컬럼을 Partition Key라고 한다.
위와 같이
INSERT 쿼리가 실행되면, MySQL 서버는 INSERT되는 컬럼의 값 중에서 Partition Kye를 이용해 파티션 표현식을 평가하고,
그 결과를 이용해 레코드가 저장될 적절한 파티션을 결정한다.
레코드가 INSERT될 파티션이 결정되면, 일반적인 INSERT 과정과 동일하게 처리된다.
UPDATE 쿼리를 실행하려면, 변경할 레코드가 어느 파티션이 있는지 알아야 한다.
UPDATE 쿼리의 WHERE 조건에 Partition Key가 있다면, 그 값을 이용해 파티션에 해당 레코드를 빠르게 찾을 수 있다.
하지만 WHERE 조건에 Partition Key가 없다면, MySQL 서버는 변경할 레코드를 찾기 위해 모든 파티션을 검색해야 한다.
그리고 UPDATE 쿼리가 어떤 컬럼의 값을 변경하느냐에 따라 큰 차이가 생긴다.
파티션 테이블을 검색할 때 성능에 크게 영향을 미치는 조건은 다음과 같다.
두번째 항목은 파티션 테이블 뿐 아니라 일반 테이블의 검색 성능에도 똑같이 영향을 미친다.
하지만 파티션 테이블에서는 첫번째 항목의 결과에 따라 두번째 항목의 작업 내용이 달라질 수 있다.
파티션 선택 가능 + 효율적 인덱스 사용 가능 : 두 항목이 모두 사용 가능할 때, 쿼리가 가장 효율적으로 처리된다.
파티션 선택 불가 + 효율적 인덱스 사용 가능 : WHERE 조건에 일치하는 레코드가 저장된 파티션을 찾을 수 없으므로,
테이블의 모든 파티션을 검색해야 한다. 하지만 각 파티션에 대해 Index Range Scan을 사용할 수 있으므로, 테이블의 모든 파티션의 개수만큼 Index Range Scan을 수행하여 검색하게 된다.
파티션 선택 가능 + 효율적 인덱스 사용 불가 : 검색하려는 레코드가 저장된 파티션을 선별할 수 있으므로, 검색에 필요한 파티션만 읽으면 된다. 하지만 인덱스는 이용할 수 없으므로, 대상 파티션에 대해 Full Table Scan을 하게 된다. 각 파티션의 레코드 건수가 많다면, 매우 느리게 처리될 것이다.
파티션 선택 불가 + 효율적 인덱스 사용 불가 : WHERE 조건에 일치하는 레코드가 저장된 파티션을 찾을 수 없으므로, 테이블의 모든 파티션을 검색해야 한다. 인덱스 또한 사용할 수 없으므로 각 파티션에 대해 Full Table Scan을 하게 된다.