Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

ストレージ効率 - 時系列

Wikipedia の統計データセットに対するクエリ方法を見てきたので、次は ClickHouse でのストレージ効率の最適化に焦点を当てます。 このセクションでは、クエリパフォーマンスを維持しながらストレージ要件を削減するための実践的な手法を紹介します。

型の最適化

ストレージ効率を最適化する一般的な方法は、適切なデータ型を使用することです。 projectsubproject のカラムを見てみましょう。これらのカラムは String 型ですが、一意の値の数は比較的少数です。

SELECT
    uniq(project),
    uniq(subproject)
FROM wikistat;
┌─uniq(project)─┬─uniq(subproject)─┐
│          1332 │              130 │
└───────────────┴──────────────────┘

つまり、辞書ベースのエンコーディングを使用する LowCardinality() データ型を使えるということです。これにより、ClickHouse は元の文字列値ではなく内部の値 ID を保存するため、容量を大幅に節約できます。

ALTER TABLE wikistat
MODIFY COLUMN `project` LowCardinality(String),
MODIFY COLUMN `subproject` LowCardinality(String)

hits カラムには UInt64 型も使用しています。これは 8 バイトを使用しますが、最大値は比較的小さめです。

SELECT max(hits)
FROM wikistat;
┌─max(hits)─┐
│    449017 │
└───────────┘

この値であれば、代わりに UInt32 を使用できます。必要な容量は 4 バイトだけで、最大で約40億まで格納できます。

ALTER TABLE wikistat
MODIFY COLUMN `hits` UInt32;

これにより、メモリ内のこのカラムのサイズを少なくとも半分にできます。なお、圧縮されるため、ディスク上のサイズは変わりません。ただし、データ型は小さすぎるものを選ばないよう注意してください。

特殊なコーデック

時系列データのような連続したデータを扱う場合は、特殊なコーデックを使うことでストレージ効率をさらに高められます。 基本的な考え方は、値そのものではなく値の変化分を保存するというもので、変化が緩やかなデータでは必要な容量を大幅に削減できます。

ALTER TABLE wikistat
MODIFY COLUMN `time` CODEC(Delta, ZSTD);

time カラムには Delta コーデック を使用しています。これは時系列データに適しています。

適切な ordering key を選ぶことでも、ディスク容量を節約できます。 通常は path で絞り込みを行いたいため、sorting key に path を追加します。 そのため、テーブル を再作成する必要があります。

以下に、初期の テーブル と最適化後の テーブル の CREATE コマンドを示します。

CREATE TABLE wikistat
(
    `time` DateTime,
    `project` String,
    `subproject` String,
    `path` String,
    `hits` UInt64
)
ENGINE = MergeTree
ORDER BY (time);
CREATE TABLE optimized_wikistat
(
    `time` DateTime CODEC(Delta(4), ZSTD(1)),
    `project` LowCardinality(String),
    `subproject` LowCardinality(String),
    `path` String,
    `hits` UInt32
)
ENGINE = MergeTree
ORDER BY (path, time);

それでは、各テーブルのデータが占める容量を見てみましょう:

SELECT
    table,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
    formatReadableSize(sum(data_compressed_bytes)) AS compressed,
    count() AS parts
FROM system.parts
WHERE table LIKE '%wikistat%'
GROUP BY ALL;
┌─table──────────────┬─uncompressed─┬─compressed─┬─parts─┐
│ wikistat           │ 35.28 GiB    │ 12.03 GiB  │     1 │
│ optimized_wikistat │ 30.31 GiB    │ 2.84 GiB   │     1 │
└────────────────────┴──────────────┴────────────┴───────┘

最適化されたテーブルは、圧縮形式では占有容量が4分の1弱になります。

Navigation