-
[ClickHouse] Parts & Partition 알아보기Database/Clickhouse 2024. 2. 29. 07:04728x90반응형
- 목차
들어가며.
이번 글에서는 ClickHouse 의 MergeTree 엔진에서 사용되는 Parts 와 Partition 에 대해서 알아보려고 합니다.
Partition 은 MergeTree Table 에 생성되는 데이터의 물리적인 단위입니다.
Table 은 Partition 을 기준으로 물리적인 저장 위치가 나뉘어집니다.
그래서 시계열 데이터의 경우에, Partition 을 시간 기준으로 나눌 수 있고, Table 의 데이터를 연월일시에 따라 개별적인 파일로써 관리됩니다.
Parts 는 하나의 온전한 Partition 을 만들기 위해서 저장되는 임시 단위입니다.
만약 시간 단위로 Partition 이 나뉘어진다고 가정하겠습니다.
그리고 1분마다 100개의 데이터가 삽입됩니다.
이때 1시간 동안 총 60의 Insert Query 가 발생하게 되는데, 그렇게 되면 60개의 Parts 가 생성되게 됩니다.
그리고 60개의 Parts 는 최종적으로 1개의 Part 로 Merge 되어 하나의 Partition 을 구성합니다.
간략하게 Parts 와 Partition 에 대해서 작성해보았는데요.
이어지는 내용에서 상세하게 알아보도록 하겠습니다.
ClickHouse 세팅하기.
ClickHouse 의 간단한 생성을 위해서 Docker 를 활용합니다.
아래 페이지는 Docker 를 기반으로 ClickHouse 컨테이너를 실행하는 간단한 설명을 포함합니다.
아래 페이지의 가이드에 따라 ClickHouse 컨테이너를 실행하실 수 있습니다.
https://westlife0615.tistory.com/694
MergeTree 테이블 생성.
default 데이터베이스 내부에 test_parts 테이블을 생성합니다.
datetime64 데이터 타입의 칼럼인 `date` 이 Partition 의 기준으로 사용됩니다.
CREATE TABLE default.test_parts ( `id` UInt32, `data` String, `date` DATETIME64 ) ENGINE MergeTree() PARTITION BY toYYYYMM(date) ORDER BY tuple(date) SETTINGS index_granularity = 8192, max_parts_in_total = 60000;
그리고 아래의 INSERT 쿼리문을 실행합니다.
아래의 문장들은 5개의 Rows 를 생성하며, 하나의 문장이 하나의 Row 를 생성합니다.
insert into default.test_parts (id, data, date) values (1, 'test1', '2023-01-01'); insert into default.test_parts (id, data, date) values (2, 'test2', '2023-02-01'); insert into default.test_parts (id, data, date) values (3, 'test4', '2023-03-01'); insert into default.test_parts (id, data, date) values (4, 'test4', '2023-04-01'); insert into default.test_parts (id, data, date) values (5, 'test5', '2023-05-01');
그 결과로써 생성되는 Parts 들은 아래와 같습니다.
총 5개의 Parts 가 생성되구요.
각 Part 의 특징을 알아보겠습니다.
SELECT partition, name, part_type, rows, path FROM system.parts WHERE table = 'test_parts' AND active = 1;
+---------+-------------+---------+----+ |partition|name |part_type|rows| +---------+-------------+---------+----+ |202301 |202301_1_1_0 |Compact |1 | |202302 |202302_2_2_0 |Compact |1 | |202303 |202303_3_3_0 |Compact |1 | |202304 |202304_4_4_0 |Compact |1 | |202305 |202305_5_5_0 |Compact |1 | |202306 |202306_6_8_1 |Compact |6 | |202401 |202401_9_10_1|Compact |2 | +---------+-------------+---------+----+
동일한 Partition 의 데이터 생성하기.
추가적으로 6개의 Rows 를 생성합니다.
새롭게 추가되는 6개의 Rows 는 "202306" 이라는 동일한 Partition Key 를 가집니다.
insert into default.test_parts (id, data, date) values (6, 'test6', '2023-06-01'), (7, 'test7', '2023-06-01'); insert into default.test_parts (id, data, date) values (8, 'test8', '2023-06-02'), (9, 'test9', '2023-06-03'); insert into default.test_parts (id, data, date) values (10, 'test10', '2023-06-02'), (11, 'test11', '2023-06-03');
그리고 system.parts 를 조회하게 되면 아래의 결과를 얻게 됩니다.
"202306" 에 해당하는 3개의 Parts 가 생성됩니다.
저는 2개의 Rows 를 BatchInsert 하는 방식으로 Row 를 생성하였습니다.
그 결과로써 rows 갯수가 2인 Parts 3개가 생성이 되죠.
+---------+------------+---------+----+ |partition|name |part_type|rows| +---------+------------+---------+----+ |202301 |202301_1_1_0|Compact |1 | |202302 |202302_2_2_0|Compact |1 | |202303 |202303_3_3_0|Compact |1 | |202304 |202304_4_4_0|Compact |1 | |202305 |202305_5_5_0|Compact |1 | |202306 |202306_6_6_0|Compact |2 | |202306 |202306_7_7_0|Compact |2 | |202306 |202306_8_8_0|Compact |2 | +---------+------------+---------+----+
하지만 이 3개의 Parts 는 서로 저장된 물리적인 파일 위치가 다릅니다.
각각 서로 다른 위치에 저장됩니다.
이 Parts 는 MergeTree 의 Compaction 에 의해서 하나로 통합됩니다.
이는 LSM Tree 의 Merge 동작과 유사합니다.
/bitnami/clickhouse/data/store/25f/25f18906-cd3e-4c56-a34d-7c719aa8d498/202306_6_6_0/ /bitnami/clickhouse/data/store/25f/25f18906-cd3e-4c56-a34d-7c719aa8d498/202306_7_7_0/ /bitnami/clickhouse/data/store/25f/25f18906-cd3e-4c56-a34d-7c719aa8d498/202306_8_8_0/
Merge Operation .
많은 양의 Insert Query 로 인해서 하나의 Partition 이 여러 Parts 로 분리되어 있을 경우에 Merge Operation 이 동작합니다.
Merge Operation 을 강제로 트리거시키는 OPTIMIZE TABLE 이라는 쿼리문이 존재하는데요.
아래 명령어를 통해서 Merge Operation 을 실행합니다.
OPTIMIZE TABLE default.test_parts;
실행 결과는 아래와 같습니다.
"202306_6_6_0", "202306_7_7_0", "202306_8_8_0" Parts 는 "202306_6_8_1" 로 머지됩니다.
"202306_6_8_1" 는 Merge 되었기 때문에 rows 는 6개를 가지게 되구요.
Part 이름 또한 6_8_1 로 변경됩니다.
"6_8" 은 6 ~ 8 에 해당하는 Parts 가 머지되었음을 뜻하며, "_1" 는 Merge 횟수를 의미합니다.
+---------+------------+---------+----+-------------------------------------------------------------------------------------+ |partition|name |part_type|rows|path | +---------+------------+---------+----+-------------------------------------------------------------------------------------+ |202301 |202301_1_1_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202301_1_1_0/| |202302 |202302_2_2_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202302_2_2_0/| |202303 |202303_3_3_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202303_3_3_0/| |202304 |202304_4_4_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202304_4_4_0/| |202305 |202305_5_5_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202305_5_5_0/| |202306 |202306_6_8_1|Compact |6 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202306_6_8_1/| +---------+------------+---------+----+-------------------------------------------------------------------------------------+
MergeTree Part 에 대해서.
하나의 Part 는 크게 partition, name, part_type, rows, path 라는 정보를 포함합니다.
그 외에서 많은 정보가 존재하지만 의미있는 몇가지 정보들만 알아보려고 합니다.
partition.
MergeTree Table 에서 설정한 Partition Key 가 Partition 으로 사용됩니다.
ClickHouse 의 MergeTree Table 은 Partition Key 를 기준으로 물리적인 파일을 관리합니다.
예를 들어보겠습니다.
아래와 같은 데이터가 존재하고, Partition Key 는 "YYYYMM 에 해당하는 연월" 입니다.
1 ~ 5월은 각 하나의 Row 를 가지구요.
6월은 6개의 Row 들을 가집니다.
+--+------+-----------------------+ |id|data |date | +--+------+-----------------------+ |11|test11|2023-06-03 00:00:00.000| |9 |test9 |2023-06-03 00:00:00.000| |10|test10|2023-06-02 00:00:00.000| |8 |test8 |2023-06-02 00:00:00.000| |7 |test7 |2023-06-01 00:00:00.000| |6 |test6 |2023-06-01 00:00:00.000| |5 |test5 |2023-05-01 00:00:00.000| |4 |test4 |2023-04-01 00:00:00.000| |3 |test4 |2023-03-01 00:00:00.000| |2 |test2 |2023-02-01 00:00:00.000| |1 |test1 |2023-01-01 00:00:00.000| +--+------+-----------------------+
이 Row 들의 Parts 는 아래와 같이 총 6개로 구성됩니다.
"202306" Part 는 6개의 Rows 를 가집니다.
+---------+------------+---------+----+-------------------------------------------------------------------------------------+ |partition|name |part_type|rows|path | +---------+------------+---------+----+-------------------------------------------------------------------------------------+ |202301 |202301_1_1_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202301_1_1_0/| |202302 |202302_2_2_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202302_2_2_0/| |202303 |202303_3_3_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202303_3_3_0/| |202304 |202304_4_4_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202304_4_4_0/| |202305 |202305_5_5_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202305_5_5_0/| |202306 |202306_6_8_1|Compact |6 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202306_6_8_1/| +---------+------------+---------+----+-------------------------------------------------------------------------------------+
그래서 모든 Merge Operation 이 마무리된 Merge Table 은 Partition 의 갯수만큼 물리적인 파일들이 생성됩니다.
name.
name 은 Part 의 이름입니다.
Part 의 이름은 Part 의 특징을 나타내는데요.
"PartitionName - minimum data block - maximum data block - Merge Level" 의 포맷을 취합니다.
포맷의 표현이 어렵기 때문에 몇가지 예시를 작성해보겠습니다.
PartitionName 은 202301 과 같은 Partition 기준값을 뜻합니다.
그리고 data block 은 각 Part 가 구성하는 Block 의 넘버를 뜻하는데요.
Insert Query 로 인해서 하나의 Part 가 생성될 때에 Part 는 자신의 Block Number 를 가집니다.
아래의 2개의 Insert Query 를 실행합니다.
insert into default.test_parts (id, data, date) values (100, 'test100', '2024-01-01'); insert into default.test_parts (id, data, date) values (101, 'test101', '2024-01-01');
그리고 system.parts 를 확인해보면 "202401_9_9_0", "202401_10_10_0" Parts 가 생성됩니다.
이때에 9와 10 은 이 Part 가 가지는 Block 의 Numbering 에 해당합니다.
즉 9번 Block 과 10번 Block 이 생성되었다는 뜻입니다.
+---------+--------------+---------+----+---------------------------------------------------------------------------------------+ |partition|name |part_type|rows|path | +---------+--------------+---------+----+---------------------------------------------------------------------------------------+ |202301 |202301_1_1_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202301_1_1_0/ | |202302 |202302_2_2_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202302_2_2_0/ | |202303 |202303_3_3_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202303_3_3_0/ | |202304 |202304_4_4_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202304_4_4_0/ | |202305 |202305_5_5_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202305_5_5_0/ | |202306 |202306_6_8_1 |Compact |6 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202306_6_8_1/ | |202401 |202401_9_9_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202401_9_9_0/ | |202401 |202401_10_10_0|Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202401_10_10_0/| +---------+--------------+---------+----+---------------------------------------------------------------------------------------+
그리고 이들을 Merge 되면 아래와 같이 202401 Partition 은 2024-9-10-1 과 같은 이름의 Part 가 됩니다.
OPTIMIZE TABLE default.test_parts PARTITION 202401;
+---------+-------------+---------+----+--------------------------------------------------------------------------------------+ |partition|name |part_type|rows|path | +---------+-------------+---------+----+--------------------------------------------------------------------------------------+ |202301 |202301_1_1_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202301_1_1_0/ | |202302 |202302_2_2_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202302_2_2_0/ | |202303 |202303_3_3_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202303_3_3_0/ | |202304 |202304_4_4_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202304_4_4_0/ | |202305 |202305_5_5_0 |Compact |1 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202305_5_5_0/ | |202306 |202306_6_8_1 |Compact |6 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202306_6_8_1/ | |202401 |202401_9_10_1|Compact |2 |/bitnami/clickhouse/data/store/215/215ce9aa-f181-4c1c-8a99-3baf3e5117c2/202401_9_10_1/| +---------+-------------+---------+----+--------------------------------------------------------------------------------------+
index_granularity.
클릭하우스의 MergeTree Table 은 Primary Index 를 가집니다.
클릭하우스의 Primary Index 는 여타 데이터베이스와 달리 개별적인 Row 에 대해서 인덱싱을 수행하지 않습니다.
대신 모든 Row 를 일일이 인덱싱하지 않고 Granule 이라는 단위별로 Index 를 적용하게 되죠.
Granule 은 보통 8192 개의 Row 들을 묶는 단위인데요.
그래서 클릭하우스의 Primary Index 는 8192 개의 Row 로 구성된 Granule 에게 인덱싱을 적용합니다.
이는 Row 들을 듬성듬성하게 인덱싱한다고 하여 Sparse Index 라고도 부릅니다.
index_granularity 는 Granule 이 몇개의 Row 를 하나의 단위로 설정할지에 대한 설정입니다.
일반적으로 index_granularity 는 8192 를 기본적으로 권장합니다.
하지만 이는 변경 가능한 설정이기도 합니다.
MergeTree Table 을 정의할 때에 index_granularity 를 설정할 수 있죠.
예시는 아래와 같습니다.
CREATE TABLE default.test_table ( `id` UInt32, `date` DATETIME ) ENGINE MergeTree() PARTITION BY toYYYYMM(date) ORDER BY tuple(date) SETTINGS index_granularity = 8192
index_granularity_bytes.
index_granularity 설정은 하나의 Granule 에 속할 수 있는 Row 의 갯수 제한입니다.
반면 index_granularity_bytes 는 하나의 Granule 의 bytes 크기를 제한할 수 있는 설정입니다.
만약 index_granularity 로 설정된 8192 보다 적은 갯수의 Row 일지언정 index_granularity_bytes 사이즈를 넘게된다면
추가적인 Row 들이 하나의 Granule 에 포함되는 것이 제한됩니다.
index_granularity_bytes 설정은 아래와 같이 설정될 수 있으며, 0 으로 설정하게 되면 제한을 적용하지 않음을 뜻합니다.
설정하지 않게된다면 기본값은 10Mb 로 적용됩니다.
CREATE TABLE default.test_table ( `id` UInt32, `date` DATETIME ) ENGINE MergeTree() PARTITION BY toYYYYMM(date) ORDER BY tuple(date) SETTINGS index_granularity = 8192, index_granularity_bytes = 0
반응형'Database > Clickhouse' 카테고리의 다른 글
[ClickHouse] Logger 설정하기 (0) 2024.06.02 [ClickHouse] Mutation 알아보기 (0) 2024.04.13 [ClickHouse] primary.idx 파일 알아보기 (0) 2024.02.28 [Clickhouse] ReplicatedMergeTree 알아보기 (0) 2024.02.18 [Clickhouse] Docker 로 Clickhouse 구현하기 (2) 2024.02.17