> ## 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.

# cache Dictionaryレイアウト

> 固定サイズのインメモリ cache にDictionaryを格納します。

`cached` Dictionaryレイアウト型では、固定数の cell を持つ cache にDictionaryを格納します。
これらの cell には、頻繁に使用される要素が格納されます。

Dictionaryキーは [UInt64](/docs/ja/reference/data-types/int-uint) 型です。

Dictionaryを検索するときは、まず cache が検索されます。データの各 block について、cache に存在しないキー、または古くなったキーは、`SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)` を使用してソースへ要求されます。取得したデータはその後 cache に書き込まれます。

cache の内容は各サーバーにローカルに保持され、サーバーが再起動されたり置き換えられたりすると失われます。確実性が求められる挿入時のエンリッチメントには、`cache` や `complex_key_cache` を使用しないでください。cache が空の場合、挿入処理が Dictionary ソースへのルックアップに依存してしまいます。ClickHouse Cloud では、オートスケーリングやマネージドなノード置き換えによって、この状態が発生しやすくなります。代わりに、各サーバーにDictionary全体を読み込むレイアウトを使用してください。詳しくは [Dictionaryのベストプラクティス](/docs/ja/concepts/features/dictionaries/best-practices#cache-dictionaries-in-ingestion-path) を参照してください。

これは、キーの**ルックアップ**、つまり `dictGet` やその他のDictionary関数に適用されます。`SELECT ... FROM <dictionary>` でDictionaryを**table として**読み取る場合は異なります。cache にはどのキーが存在するかの記録がないため、この読み取りでは、その時点で cache に存在し、かつ値を保持している cell のみが列挙され、キーに対する `WHERE` は、取得するキーのリストではなく、それらの cell に対する通常の filter となります。cache に存在しないキーは、`WHERE` に何を記述してもこの方法では発見できません。ルックアップは行われたもののソースで見つからなかったキーも表示されません。cache はそのミスをデフォルト cell として記憶し、table としての読み取りはデフォルト cell をスキップするためです。また、cache に存在する cell もソースと無関係ではありません。期限切れの cell は `dictGet` と同じ経路で読み取られるため、ソースへ再度要求されます。これは同期的に行われ、`allow_read_expired_keys` が有効な場合は非同期に行われます。

```sql theme={null}
CREATE DICTIONARY cache_dict (id UInt64, data String) PRIMARY KEY id
SOURCE(CLICKHOUSE(TABLE 'cache_src')) LIFETIME(MIN 0 MAX 900) LAYOUT(CACHE(SIZE_IN_CELLS 1000));

-- nothing is cached yet, so nothing comes back and the source is not queried
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
0

-- looking the keys up populates the cache
SELECT dictGet('cache_dict', 'data', toUInt64(number + 1)) FROM numbers(3);

-- and now the same read sees them
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
3
```

つまり、cache DictionaryはDictionary関数を通じて使用することを想定しています。任意のキーのルックアップが常にソースへ到達する必要がある場合は、ルックアップごとにソースへクエリを実行し何も cache しない [direct](/docs/ja/reference/statements/create/dictionary/layouts/direct) レイアウトと `dictGet` を使用してください。なお、`direct` Dictionaryを table として読み取る場合も、キー指定による fetch にはなりません。`SELECT ... FROM <dictionary> WHERE key IN (...)` は、ClickHouse がキーの filter をDictionaryにプッシュダウンしないため、ソース全体を読み込んでから filter を適用します。Dictionaryを table として読み取る場合は、[flat](/docs/ja/reference/statements/create/dictionary/layouts/flat) や [hashed](/docs/ja/reference/statements/create/dictionary/layouts/hashed) のようにDictionary全体を保持するレイアウトを使用してください。

Dictionary内にキーが見つからない場合は、cache 更新用の task が作成され、更新 queue に追加されます。更新 queue のプロパティは、`max_update_queue_size`、`update_queue_push_timeout_milliseconds`、`query_wait_timeout_milliseconds`、`max_threads_for_updates` の各設定で制御できます。

cache Dictionaryでは、cache 内のデータの有効期限 [lifetime](/docs/ja/reference/statements/create/dictionary/lifetime) を設定できます。cell にデータを読み込んでから `lifetime` を超える時間が経過すると、その cell の値は使用されず、キーは期限切れになります。そのキーは、次回必要になったときに再度要求されます。この動作は `allow_read_expired_keys` 設定で構成できます。

これは、Dictionaryの格納方法の中で最も効率が低いものです。cache の速度は、適切な設定と使用シナリオに大きく依存します。cache 型Dictionaryが十分に高い性能を発揮するのは、ヒット率が十分高い場合のみです (推奨は 99% 以上) 。平均ヒット率は [system.dictionaries](/docs/ja/reference/system-tables/dictionaries) table で確認できます。

`allow_read_expired_keys` 設定が 1 に設定されている場合 (デフォルトは 0) 、Dictionary は非同期更新をサポートします。クライアントが要求したキーがすべて cache 内に存在し、そのうち一部が期限切れである場合、Dictionary はクライアントに期限切れのキーを返し、それらのキーをソースから非同期に再取得します。

cache のパフォーマンスを向上させるには、`LIMIT` を指定したサブクエリを使用し、Dictionary を使用する関数はその外側で呼び出してください。

すべての種類のソースがサポートされています。

設定例:

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    LAYOUT(CACHE(SIZE_IN_CELLS 1000000000))
    ```
  </Tab>

  <Tab title="構成ファイル">
    ```xml theme={null}
    <layout>
        <cache>
            <!-- cell 数で表した cache のサイズ。2 の累乗に切り上げられます。 -->
            <size_in_cells>1000000000</size_in_cells>
            <!-- 期限切れキーの読み取りを許可します。 -->
            <allow_read_expired_keys>0</allow_read_expired_keys>
            <!-- 更新 queue の最大サイズ。 -->
            <max_update_queue_size>100000</max_update_queue_size>
            <!-- 更新 task を queue に追加する際の最大タイムアウト（ミリ秒）。 -->
            <update_queue_push_timeout_milliseconds>10</update_queue_push_timeout_milliseconds>
            <!-- 更新 task の完了を待機する最大タイムアウト（ミリ秒）。 -->
            <query_wait_timeout_milliseconds>60000</query_wait_timeout_milliseconds>
            <!-- cache Dictionary更新用の最大スレッド数。 -->
            <max_threads_for_updates>4</max_threads_for_updates>
        </cache>
    </layout>
    ```
  </Tab>
</Tabs>

<br />

十分に大きな cache サイズを設定してください。cell 数の選定には試行が必要です:

1. 適当な値を設定します。
2. cache が完全に埋まるまでクエリを実行します。
3. `system.dictionaries` table を使ってメモリ消費量を評価します。
4. 必要なメモリ消費量に達するまで、cell 数を増減します。

<Note>
  このレイアウトのソースとして ClickHouse を使用することは推奨されません。Dictionary のルックアップにはランダムなポイント read が必要ですが、これは ClickHouse が最適化しているアクセスパターンではありません。
</Note>
