4가지 기본 파티션 기법을 제공하고 있으며, 해시와 키 파티션에대해서는 리니어 파티션과 같은 추가적인 기법도 제공한다.
- 레인지 파티션
- 리스트 파티션
- 해시 파티션
- 키 파티션
레인지 파티션
파티션 키의 연속된 범위로 파티션을 정의하는 방법으로, 가장 일반적으로 사용되는 파티션 방법 중 하나다.
MAXVALUE
키워드를 이용해 명시되지 않은 범위의 키 값이 담긴 레코드를 저장하는 파티션을 정의할 수 있다.
레인지 파티션의 용도
다음과 같은 성격을 지는 테이블에서는 레인지 파티션을 사용하는 것이 좋다.
- 날짜를 기반으로 데이터가 누적되고 연도나 월, 또는 일 단위로 분석하고 삭제해야 할 때
- 범위 기반으로 데이터를 여러 파티션에 균등하게 나눌 수 있을 때
- 파티션 키 위주로 검색이 자주 실행될 때
데이터베이스에서 파티션의 장점은 다음 2가지로 구분할 수 있다.
- 큰 테이블을 작은 크기의 파티션으로 분리
- 필요한 파티션만 접근(쓰기, 읽기)
위 2가지 장점 중 두 번째 장점의 효과가 매우 큰 편이다.
파티션을 적용하면서 두 번째 장점은 취하지 못하고 첫 번째 장점에만 집중하다보니, 결과적으로 파티션 때문에 오히려 서버의 성능을 더 떨어뜨리게 된다.
실제 데이터베이스 서버의 파티션에서 두가지 장점을 모두 취하기는 매우 어렵지만, 이력을 저장하는 테이블에서 레인지 파티션은 두 가지 장점을 모두 어렵지 않게 취할 수 있다.
레인지 파티션 테이블 생성
|
|
PARTITION BY RANGE
키워드로 레인지 파티션을 정의한다.PARTITION BY RANGE
뒤에 컬럼 또는 내장 함수를 이용해 파티션 키를 명시한다.VALUES LESS THAN
으로 명시된 값보다 작은 값만 해당 파티션에 저장하게 설정한다.LESS THAN
절에 명시된 값은 그 파티션에 포함되지 않는다.
VALUE LESS THAN MAXVALUE
로 명시되지 않은 레코드를 저장할 파티션을 지정한다.- 선택 사항이므로 지정하지 않아도 괜찮다.
VALUE LESS THAN MAXVALUE
가 정의되지 않으면hired
컬럼의 값이 ‘2011-02-30’인 레코드가INSERT
될 때 에러가 발생한다.Table has no partition for value 2011
메시지 표시
- 테이블과 각 파티션은 같은 스토리지 엔진으로 정의할 수 있다.
- 하지만 MySQL 8.0 에서는 InnoDB 스토리지 엔진이 기본 스토리지 엔진이므로 별도로 명시하지 않아도 InnoDB 테이블로 생성된다.
레인지 파티션의 분리와 병합
단순 파티션의 추가
|
|
현재 employees
테이블에는 LESS THAN MAXVALUE
파티션을 가지고 있으므로 새로운 파티션을 추가하려고 하면 에러가 발생한다.
이미 MAXVALUE
파티션이 2001년 이후의 모든 레코드를 가지고 있는 상태에서 2011년 파티션이 추가되면 2011년 레코드는 2개의 파티션에 나뉘어 저장되는 결과를 만들어낸다.
이는 하나의 레코드는 반드시 하나의 파티션에만 저장돼야 한다는 기본 조건을 벗어나는 것이므로 이러한 경우 ALTER TABLE ... REORGANIZE PARTITION
명령을 사용해야 한다.
|
|
해당 명령은 파티션의 레코드를 모두 새로운 두 개의 파티션으로 복사하는 작업을 필요로 한다. p3 파티션의 레코드가 매우 많다면 매우 오랜 시간이 걸리게 된다.
레인지 파티션에서는 일반적으로 LESS THAN MAXVALUE
절을 사용하는 파티션을 추가하지 않고, 미래에 사용될 파티션을 미리 2~3개 정도 더 만들어 두는 형태로 테이블을 생성하기도 한다. 그리고 배치 스크립트를 이용해 주기적으로 파티션 테이블의 여유 기간을 판단해서 파티션을 자동으로 추가하는 방법을 사용한다.
하지만 필요한 파티션을 배치 스크립트에 의존하는 경우 배치 스크립트의 오류로 파티션이 자동으로 추가되지 못할 수도 있다.
LESS THAN MAXVALUE
파티션이 존재한다고 하더라도 이 파티션이 데이터를 가지고 있지 않다면 파티션을 수정하는 명령은 매우 빨리 완료될 것이므로 성능 관련해서 걱정은 하지 않아도 된다.
파티션 삭제
레인지 파티션을 삭제하려면 다음과 같이 DROP PARTITION
키워드에 삭제하려는 파티션의 이름을 지정하면 된다.
레인지, 리스트 파티션을 삭제하는 작업은 아주 빠르게 처리되므로 날짜 단위로 파티션된 테이블에서 오래된 데이터를 삭제하는 용도로 자주 사용된다.
|
|
레인지 파티션을 사용하는 테이블에서 파티션을 삭제할 때 항상 가장 오래된 파티션 순서로만 삭제할 수 있다.
기존 파티션의 분리
하나의 파티션을 두 개 이상의 파티션으로 분리하고자 할 때는 REORGANIZE PARTITION
명령을 사용하면 된다. 다음 예제는 MAXVALUE
파티션인 p3을 두개로 나누는 명령이다.
|
|
MAXVALUE
파티션뿐만 아니라 다른 파티션들도 명령을 이용해 분리할 수 있다.- 기존 파티션의 레코드를 새로운 파티션으로 복사하기 때문에 기존 파티션의 레코드 건수에 따라 오랜 시간이 걸릴 수 있다.
- 기존 파티션의 레코드가 많다면 온라인 DDL로 실행될 수 있도록
ALGORITHM
,LOCK
절을 사용하면 좋다. - 파티션 재구성 명령은
INPLACE
알고리즘을 사용할 수 있지만 최소한 읽기 잠금으로 인해 테이블 쓰기가 불가능하므로 재구성 작업은 쿼리 처리가 많지 않은 시간대에 진행하는 것이 좋다.
기존 파티션 병합
REORGANIZE PARTITION
명령으로 처리할 수 있다.
|
|
파티션을 병합하는 경우도 파티션 재구성이 필요하여, 테이블에 대해 읽기 잠금을 한다.
리스트 파티션
리스트 파티션은 레인지 파티션과 흡사하게 동작한다.
- 둘의 가장 큰 차이는 레인지 파티션은 파티션 키 값의 범위로 파티션을 구성할 수 있지만, 리스트 파티션은 파티션 키 값 하나하나를 리스트로 나열해야 한다는 점이다.
- 따라서 레인지 파티션과 같이
MAXVALUE
파티션을 정의할 수 없다.
리스트 파티션의 용도
테이블이 다음과 같은 특성을 지닐 때는 리스트 파티션을 사용하는 것이 좋다.
- 파티션 키 값이 코드값이나 카테고리와 같이 고정적일 때
- 키 값이 연속되지 않고 정렬 순서와 관계없이 파티션을 해야 할 때
- 파티션 키 값을 기준으로 레코드의 건수가 균일하고 검색 조건에 파티션 키가 자주 사용될 때
리스트 파티션 테이블 생성
|
|
INT
타입의category_id
컬럼 값을 그대로 파티션 키로 사용한다.VALUES IN (...)
을 통해 파티션별로 저장할 파티션 키 값의 목록을 나열한다.- 키 값중에 NULL을 명시할 수도 있다.
MAXVALUE
파티션은 정의할 수 없다.
|
|
리스트 파티션의 분리와 병합
파티션을 정의하는 부분에서 VALUE LESS THAN
이 아닌 VALUES IN
을 사용한다는 것 외에는 레인지 파티션의 추가, 삭제, 병합 작업이 모두 같다.
리스트 파티션 주의사항
- 명시되지 않은 나머지 값을 저장하는
MAXVALUE
파티션을 정의할 수 없다. - 레인지 파티션과는 달리 NULL을 저장하는 파티션을 별도로 생성할 수 있다.
해시 파티션
해시 파티션은 MySQL 에서 정의한 해시 함수에 의해 레코드가 저장될 파티션을 결정하는 방법이다.
- MySQL에서 정의한 해시 함수는 복잡한 알고리즘이 아니라 파티션의 표현식의 결괏값을 파티션의 개수로 나눈 나머지로 저장될 파티션을 결정하는 방식이다.
- 해시 파티션의 파티션 키는 항상 정수 타입의 컬럼이거나 정수를 반환하는 표현식만 사용할 수 있다.
- 해시 파티션에서 파티션의 개수는 레코드를 각 파티션에 할당하는 알고리즘과 연관되기 때문에 파티션을 추가하거나 삭제하는 작업에는 테이블 전체적으로 레코드를 재분배하는 작업이 따른다.
해시 파티션의 용도
해시 파티션은 다음과 같은 특성을 지닌 테이블에 적합하다.
- 레인지 파티션이나 리스트 파티션으로 데이터를 균등하게 나누는 것이 어려울 때
- 테이블의 모든 레코드가 비슷한 사용 빈도를 보이지만 테이블이 너무 커서 파티션을 적용해야 할 때
테이블의 데이터가 특정 값에 영향을 받지 않고 전체적으로 비슷한 사용 빈도를 보일 때 적합하다.
- 해시 파티션, 키 파티션의 대표적인 용도로는 회원 테이블을 들 수 있다. 회원 정보는 가입 일자가 오래돼서 사용되지 않거나 최신이어서 더 빈번하게 사용하지 않고, 지역이나 취미 같은 정보 또한 사용 빈도에 미치는 영향이 거의 없다.
해시 파티션 테이블 생성
|
|
- 해시 파티션의 파티션 키 또는 파티션 표현식은 반드시 정수 타입의 값을 반환해야한다.
- 해시나 키 파티션에서는 특정 파티션을 삭제하거나 병합하는 작업이 거의 불필요하므로 파티션의 이름을 부여하는 것이 크게 의미는 없다.
- 파티션의 개수만 지정하면 각 파티션의 이름은 기본적으로 “p0, p1, …“과 같은 규칙으로 생성된다.
해시 파티션의 분리와 병합
파티션의 분리나 병합으로 인해 파티션의 개수가 변경된다는 것은 해시 함수의 알고리즘을 변경하는 것 이므로, 해시 파티션의 분리와 병합은 모든 파티션에 저장된 레코드를 재분배 하는 작업이 필요하다.
해시 파티션 추가
해시 파티션 키 값을 테이블의 파티션 개수로 MOD 연산한 결괏값에 의해 각 레코드가 저장될 파티션을 결정한다.
따라서 새로운 파티션이 추가된다면 기존의 각 파티션에 저장된 모든 레코드가 재배치돼야 한다.
|
|
위의 예제같이 해시 파티션에서 파티션을 추가하는 작업은 INPLACE
알고리즘으로 실행된다고 하더라도 레코드 리빌드 작업이 필요하며 테이블에 대한 읽기 잠금이 필요하다. 따라서 해시 파티션에서 파티션을 추가하거나 생성하는 작업은 많은 부하를 발생시키며, 다른 트랜잭션에서 동일 테이블에 데이터를 변경하는 작업은 허용되지 않는다.
해시 파티션 삭제
해시나 키 파티션은 파티션 단위로 레코드를 삭제하는 방법이 없다.
|
|
MySQL 서버가 지정한 파티션 키 값을 가공하여 데이터를 각 파티션으로 분산한 것이므로 각 파티션에 저장된 레코드가 어떤 부류의 데이터인지 사용자가 예측할 수 없다.
해시 파티션이나 키 파티션을 사용한 테이블에서 파티션 단위로 데이터를 삭제하는 작업은 의미도 없으며 해서도 안될 작업이다.
해시 파티션 분할
해시 파티션이나 키 파티션에서 특정 파티션을 두 개 이상의 파티션으로 분할하는 기능은 없으며, 테이블 전체적으로 파티션의 개수를 늘리는 작업만 가능하다.
해시 파티션 병합
2개 이상의 파티션을 하나의 파티션으로 통합하는 기능을 제공하지 않고, 파티션의 개수를 줄이는 것만 가능하다.
|
|
COALESCE PARTITION
뒤에 명시한 숫자 값은 줄이고자 하는 파티션 개수를 의미한다.
마찬가지로 테이블의 모든 레코드가 재배치되는 작업이 수행돼야한다.
해시 파티션 주의사항
- 특정 파티션만 삭제 하는 것은 불가능하다.
- 새로운 파티션을 추가하는 작업은 단순히 파티션만 추가하는 것이 아니라 기존 모든 데이터의 재배치 작업이 필요하다.
- 해시 파티션은 레인지 파티션이나 리스트 파티션과는 다른 방식으로 괸리하기 때문에 용도에 적합한 해결책인지 확인이 필요하다.
- 일반적으로 익숙한 파티션 조작이나 특성은 대부분 리스트 파티션이나 레인지 파티션에만 해당하는 것들이 많다.
- 해시, 키 파티션을 사용하거나 조작할 때는 주의가 필요하다.
키 파티션
키 파티션은 해시 파티션과 사용법과 특성이 거의 같다.
- 키 파티션에서는 정수 타입이나 정수값을 반환하는 표현식 뿐만아니라 대부분의 데이터 타입에 대해 파티션을 적용할 수 있다.
- 선정된 파티션 키의 값을
MD5()
함수를 이용해 해시 값을 계산하고, 그 값을 MOD 연산하여 데이터를 각 파티션에 분배한다.
키 파티션 생성
|
|
키 파티션의 주의하항 및 특이사항
- 키 파티션은 MySQL 서버가 내부적으로
MD5()
함수를 이용해 파티션하기 때문에 파티션 키가 반드시 정수 타입이 아니어도 된다. - 프라이머리 키나 유니크 키를 구성하는 컬럼 중 일부만으로도 파티션 할 수 있다.
- 유니크 키를 파티션 키로 사용할 때 해당 유니크 키는 반드시
NOT NULL
이어야 한다. - 해시 파티션에 비해 파티션 간의 레코드를 더 균등하게 분할할 수 있기 때문에 키 파티션이 더 효율적이다.
리니어 해시 파티션/리니어 키 파티션
해시, 키 파티션은 새로운 파티션을 추가하거나 파티션을 통합해서 개수를 줄일 때 대상 파티션만이 아니라 테이블의 전체 파이션에 저장된 레코드의 재분배 작업이 발생하는데, 이러한 단점을 최소화 하기 위해 리니어 해시 파티션/리니어 키 파티션 알고리즘이 고안되었다.
각 레코드 분배를 위해 “Power-of-two(2의 승수)” 알고리즘을 이용하며, 파티션의 추가나 통합 시 다른 파티션에 미치는 영향을 최소화한다.
Power-of-two 알고리즘
해시 테이블의 크기가 2의 거듭제곱 수로 정의되는 경우 사용되는 해시 충돌 해결 방법 중 하나로, 해시 테이블의 크기가 2^n
이라면 적절하게 동작할 수 있다.
- 해시 테이블의 크기를
2^n
으로 설정한다. - 키를 해시 함수에 넣어 해시 값을 계산한다.
- 계산된 해시 값을
2^n
으로 나눈 나머지를 버킷 인덱스로 사용한다.
해시 충돌이 발생할 경우, 다음 빈 버킷으로 이동하여 저장하는 방식으로 충돌을 해결한다.
만약 충돌이 발생한 위치가 이미 사용중인 경우, 다음 버킷을 검사하고 비어있는 버킷을 찾을 때까지 반복하며, 이러한 과정을 선형 탐사라고 한다.
리니어 해시 파티션/리니어 키 파티션의 추가 및 통합
리니어 파티션의 경우 단순히 나머지 연산으로 레코드가 저장될 파티션을 결정하는 것이 아닌, “Power-of-two” 분배 방식을 사용하기 때문에 파티션의 추가나 통합 시 특정 파티션의 데이터에대해서만 이동 작업을 하면 된다.
파티션을 추가하거나 통합하는 작업에서 나머지 파티션의 데이터는 재분배 대상이 되지 않는다.
리니어 해시 파티션/리니어 키 파티션의 추가
리니어 파티션에 새로운 파티션을 추가하는 명령은 일반 해시 파티션이나 키 파티션과 동일하며 키 분배 알고리즘에만 차이가 있다.
리니어 파티션은 “Power-of-two” 알고리즘으로 레코드가 분배돼 있기 때문에 새로운 파티션을 추가할 때도 특정 파티션의 레코드만 재분배 하면 된다.
다른 파티션 데이터는 레코드 재분배 작업과 관련이 없기 때문에 일반 해시 파티션이나 키 파티션의 파티션 추가보다 매우 빠르게 처리할 수 있다.
리니어 해시 파티션/리니어 키 파티션 통합
새로운 파티션을 추가할 때와 같이 일부 파티션에 대해서만 레코드 통합 작업이 필요하다. 통합되는 파티션만 레코드 이동이 필요하며, 나머지 파티션의 레코드는 레코드 재분배 작업에서 제외된다.
리니어 해시 파티션/리니어 키 파티션과 관련된 주의사항
파티션을 추가하거나 통합할 때 작업의 범위를 최소화하는 대신 각 파티션이 가지는 레코드의 건수는 일반 해시 파티션이나 키 파티션보다는 덜 균등해질 수 있다.
해시 파티션이나 키 파티션을 사용하는 테이블에 대해 새로운 파티션을 추가하거나 삭제해야 할 요건이 많다면 리니어 해시 파티션 또는 리니어 키 파티션을 적용하는 것의 좋으나, 파티션을 조정할 필요가 거의 없다면 일반 해시 파티션이나 키 파티션을 사용하는 것이 좋다.
파티션 테이블의 쿼리 성능
파티션 테이블에 쿼리가 실행될 때 테이블의 모든 파티션을 읽을지 아니면 일부 파티션만 읽을지는 성능에 아주 큰영향을 미친다.
쿼리의 성능은 테이블에서 얼마나 많은 파티션을 프루닝할 수 있는지가 관건이며, 옵티마이저가 수립하는 실행 계획에서 어떤 파티션에 제외되고 선택되는지 확인할 수 있다.
- 일반적으로 레인지 파티션이나 리스트 파티션을 사용하는 테이블에서 개별 파티션을 명시해야하므로, 레인지 파티션이나 리스트 파티션이 사용되는 테이블의 개수는 파티션 개수는 적은편이다.
- 해시나 키 파티션의 경우 파티션의 개수만 지정하면 되므로 많은 파티션을 가진 테이블도 쉽게 생성할 수 있어 주의가 필요하다.
- 인덱스가 있다고 하더라도 파티션 테이블 조회가 필요하므로 파티션 조건에 따라 파티션 테이블을 모두 확인해야 할 수 있다.
- 일부 파티션만 집중적으로 사용한다면 문제 없겠지만, 균등하게 파티션 되었다면 오버헤드가 커질 수 있다.
- MySQL 서버의 파티션은 샤딩이 아니므로 파티션을 사용할 때는 반드시 파티션 프루닝이 얼마나 도움이 될지 예측해보고 적용해야한다.