概要
この記事はここ引用し、知識を整理するために、記載しました。
なぜMergeTreeはいる?
データをClickHouseに書き込む時、ClickHouseはデータを複数のブロックを分けて、保存しているそうです。ClickHouseは、ブロックのデータを確保し、そのブロックのデータを変更したりはしない。(新しいデータをインサートする時は、ブロックに上書きしたりしないと自分の認識です。)ブロックは多くなると、データは下記のように、不連続となると思います。
不連続のデータは検索する時、効率は下がるため、ClickHoseは裏側で、定期的に同じパーティションと設定されているデータをマージするようです。
MergeTreeはどうやってマージするのか
ClickHouseではテーブルを作成する時、よく使っているテーブルエンジンMergeTreeですが、MergeTreeを設定する時、ClickHouseはどうやって、パーティションをマージしているんでしょうか?例えば、下記のSQLを使って、テーブルを作成してみました。
CREATE TABLE test
(
user_id String,
date Date,
group_id String
) ENGINE = MergeTree()
ORDER BY (user_id, date,group_id)
PRIMARY KEY (user_id, date)
PARTITION BY toYYYYMM(date)
SETTINGS index_granularity= 8192 ;
上記のSQLを実行し終わると、下記のところにファイルは作成された。
#path database/metadata/test.sql
ATTACH DATABASE _ UUID '0eb2002c-834c-4eb7-ac2f-35160d976765'
ENGINE = Atomic
上記のUUID
を使って、検索してみたら、このUUIDを使って、命名しているディレクトリーはあった。
# database/store/0eb/0eb2002c-834c-4eb7-ac2f-35160d976765
上記のディレクトリーの配下にはtest.sql
というファイルがあり、それはさっき実行したSQL文でした。
-- database/store/0eb/0eb2002c-834c-4eb7-ac2f-35160d976765/test.sql--
ATTACH TABLE _ UUID '48794f04-7524-46f7-a489-66cabed437c1'
(
`user_id` String,
`date` Date,
`group_id` String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(date)
PRIMARY KEY (user_id, date)
ORDER BY (user_id, date, group_id)
SETTINGS index_granularity = 8192
ちょっと、データをインサートしてみます。
INSERT INTO test (`user_id`, `date`, `group_id`) values ('1', toDate(now()), '1');
上記のtest.sql
にもテーブルのUUID
は記載していますので、もう一回このUUID
を使って、検索してみたら、デーブルのパーティションを管理するディレクトリにたどり着けます。
# database/store/487/48794f04-7524-46f7-a489-66cabed437c1/
ちょっとこのディレクトの配下みてみると、下記の感じです。
└── 48794f04-7524-46f7-a489-66cabed437c1 (テーブルのUUID)
├── 202103_1_1_0 (parition名)
│ ├── checksums.txt
│ ├── columns.txt (カラム定義に関するファイル)
│ ├── count.txt
│ ├── data.bin
│ ├── data.mrk3
│ ├── default_compression_codec.txt
│ ├── minmax_date.idx (paritionキーを設定すると、作成されるファイル)
│ ├── partition.dat (paritionキーを設定すると、作成されるファイル)
│ └── primary.idx (primaryキー情報)
├── detached
└── format_version.txt
上記のファイルによって、ClickHouseはテーブルのインデックスなど管理しているようですね。この時、あること気付きました。パーティション名はテーブルを作成した時、設定されているPARTITION BY toYYYYMM(date)
によって、命名したように見えますね。パーティション名の構成は下記の感じです。
paritionID_minBlockNum_maxBlockNum_level
paritionID
の作成は2パターンがあるようですが、PARTITION BY
を設定する場合は、設定されるキーによって作成し、PARTITION BY
を設定していない場合はall
という名前を使います。minBlockNum
、maxBlockNum
、maxBlockNum
、level
について、自分の理解は曖昧ですので、ここでは割愛です。
次はマージの過程をみてみると、下記のイメージです。
minBlockNum
、maxBlockNum
、level
は上記のイメージで計算しているようです。
まとめ
一部のことはまだ理解していないんですが、パーティションのマージについて、一応イメージを掴みました。