> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ストレージ効率 - 時系列

> 時系列データのストレージ効率を改善する

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

<div id="time-series-type-optimization">
  ## 型の最適化
</div>

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

```sql theme={null}
SELECT
    uniq(project),
    uniq(subproject)
FROM wikistat;
```

```text theme={null}
┌─uniq(project)─┬─uniq(subproject)─┐
│          1332 │              130 │
└───────────────┴──────────────────┘
```

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

```sql theme={null}
ALTER TABLE wikistat
MODIFY COLUMN `project` LowCardinality(String),
MODIFY COLUMN `subproject` LowCardinality(String)
```

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

```sql theme={null}
SELECT max(hits)
FROM wikistat;
```

```text theme={null}
┌─max(hits)─┐
│    449017 │
└───────────┘
```

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

```sql theme={null}
ALTER TABLE wikistat
MODIFY COLUMN `hits` UInt32;
```

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

<div id="time-series-specialized-codecs">
  ## 特殊なコーデック
</div>

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

```sql theme={null}
ALTER TABLE wikistat
MODIFY COLUMN `time` CODEC(Delta, ZSTD);
```

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

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

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

```sql theme={null}
CREATE TABLE wikistat
(
    `time` DateTime,
    `project` String,
    `subproject` String,
    `path` String,
    `hits` UInt64
)
ENGINE = MergeTree
ORDER BY (time);
```

```sql theme={null}
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);
```

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

```sql theme={null}
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;
```

```text theme={null}
┌─table──────────────┬─uncompressed─┬─compressed─┬─parts─┐
│ wikistat           │ 35.28 GiB    │ 12.03 GiB  │     1 │
│ optimized_wikistat │ 30.31 GiB    │ 2.84 GiB   │     1 │
└────────────────────┴──────────────┴────────────┴───────┘
```

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