> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# структура словаря cache

> Хранит словарь в кэше фиксированного размера в памяти.

Тип структуры словаря `cached` хранит словарь в кэше с фиксированным количеством ячеек.
Эти ячейки содержат часто используемые элементы.

Ключ словаря имеет тип [UInt64](/ru/reference/data-types/int-uint).

При обращении к словарю сначала выполняется поиск в кэше. Для каждого блока данных все ключи, которые не найдены в кэше или являются устаревшими, запрашиваются из источника с помощью `SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)`. Полученные данные затем записываются в кэш.

Это относится к **поиску** ключа — `dictGet` и другим функциям работы со словарями. Чтение словаря **как таблицы** через `SELECT ... FROM <dictionary>` работает иначе: поскольку кэш не хранит сведений о том, какие ключи существуют, при чтении перечисляются только те ячейки, которые в этот момент находятся в кэше и содержат значение, а условие `WHERE` по ключу — это обычный фильтр по этим ячейкам, а не список ключей для загрузки. Ключ, которого нет в кэше, таким способом обнаружить нельзя, что бы ни было указано в `WHERE`. Ключ, который *был* запрошен, но не найден в источнике, также не виден: кэш запоминает промах как ячейку со значением по умолчанию, а при чтении как таблицы такие ячейки пропускаются. Находящиеся в кэше ячейки тоже не избавлены от обращений к источнику: устаревшая ячейка читается по тому же пути, что и `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 предназначен для использования через функции словаря. Если требуется, чтобы поиск произвольных ключей всегда доходил до источника, используйте `dictGet` со структурой [direct](/ru/reference/statements/create/dictionary/layouts/direct), которая обращается к источнику при каждом поиске и ничего не кэширует. Обратите внимание, что чтение словаря `direct` как таблицы также не является выборкой по ключам: `SELECT ... FROM <dictionary> WHERE key IN (...)` загружает весь источник и фильтрует данные уже после этого, поскольку ClickHouse не проталкивает фильтр по ключу в словарь. Чтобы читать словарь как таблицу, используйте структуру, хранящую его целиком, например [flat](/ru/reference/statements/create/dictionary/layouts/flat) или [hashed](/ru/reference/statements/create/dictionary/layouts/hashed).

Если ключи не найдены в словаре, создается задача обновления кэша и добавляется в очередь обновлений. Параметрами очереди обновлений можно управлять с помощью настроек `max_update_queue_size`, `update_queue_push_timeout_milliseconds`, `query_wait_timeout_milliseconds`, `max_threads_for_updates`.

Для словарей cache можно задать срок действия данных в кэше — [lifetime](/ru/reference/statements/create/dictionary/lifetime). Если с момента загрузки данных в ячейку прошло больше времени, чем `lifetime`, значение ячейки не используется, и ключ считается устаревшим. При следующем обращении этот ключ будет запрошен повторно. Это поведение можно настроить с помощью параметра `allow_read_expired_keys`.

Это наименее эффективный из всех способов хранения словарей. Производительность кэша сильно зависит от правильности настроек и сценария использования. Словарь типа cache показывает хорошую производительность только при достаточно высокой доле попаданий в кэш (рекомендуется 99% и выше). Среднюю долю попаданий можно посмотреть в таблице [system.dictionaries](/ru/reference/system-tables/dictionaries).

Если параметр `allow_read_expired_keys` установлен в 1 (по умолчанию — 0), словарь может поддерживать асинхронные обновления. Если клиент запрашивает ключи и все они есть в кэше, но некоторые из них устарели, словарь вернет клиенту устаревшие ключи и асинхронно запросит их из источника.

Чтобы повысить производительность кэша, используйте подзапрос с `LIMIT` и вызывайте функцию вне словаря.

Поддерживаются все типы источников.

Пример настроек:

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

  <Tab title="Файл конфигурации">
    ```xml theme={null}
    <layout>
        <cache>
            <!-- Размер кэша в количестве ячеек. Округляется вверх до степени двойки. -->
            <size_in_cells>1000000000</size_in_cells>
            <!-- Позволяет читать устаревшие ключи. -->
            <allow_read_expired_keys>0</allow_read_expired_keys>
            <!-- Максимальный размер очереди обновления. -->
            <max_update_queue_size>100000</max_update_queue_size>
            <!-- Максимальный тайм-аут в миллисекундах для помещения задачи обновления в очередь. -->
            <update_queue_push_timeout_milliseconds>10</update_queue_push_timeout_milliseconds>
            <!-- Максимальный тайм-аут ожидания в миллисекундах для завершения задачи обновления. -->
            <query_wait_timeout_milliseconds>60000</query_wait_timeout_milliseconds>
            <!-- Максимальное число потоков для обновления словаря cache. -->
            <max_threads_for_updates>4</max_threads_for_updates>
        </cache>
    </layout>
    ```
  </Tab>
</Tabs>

<br />

Задайте достаточно большой размер кэша. Чтобы подобрать количество ячеек, нужно поэкспериментировать:

1. Задайте некоторое значение.
2. Выполняйте запросы, пока кэш полностью не заполнится.
3. Оцените потребление памяти с помощью таблицы `system.dictionaries`.
4. Увеличивайте или уменьшайте количество ячеек, пока не будет достигнут требуемый уровень потребления памяти.

<Note>
  Не рекомендуется использовать ClickHouse в качестве источника для этой структуры. Поиск по словарю требует случайных точечных чтений, а ClickHouse не оптимизирован под такой шаблон доступа.
</Note>
