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

# Лучшие практики работы со словарями

> Рекомендации по выбору структуры словаря, по тому, когда словари стоит использовать вместо JOIN, и по мониторингу их использования.

На этой странице собраны практические рекомендации по выбору подходящей структуры словаря, по пониманию того, в каких случаях словари работают быстрее, чем JOIN, а в каких — нет, а также по мониторингу их использования.

Введение в словари с подробными примерами см. в [основном руководстве по словарям](/docs/ru/concepts/features/dictionaries/index).

<div id="when-to-use-dictionaries-vs-joins">
  ## Когда использовать словари вместо JOIN-ов
</div>

Словари лучше всего подходят, когда одна из сторон JOIN — это таблица соответствий, которая помещается в память. При обычном JOIN ClickHouse строит хеш-таблицу на основе правой части, а затем выполняет по ней поиск для левой — даже если позже большинство строк будет отброшено фильтрами `WHERE`. Хотя в последних версиях (24.12+) во многих случаях фильтры применяются до JOIN-ов, это не всегда устраняет накладные расходы. При использовании словаря вы вызываете `dictGet` прямо в выражении, поэтому поиск выполняется только для строк, которые уже прошли фильтрацию.

Однако `dictGet` подходит не всегда. Если вам нужно вызывать `dictGet` для большой доли строк таблицы — например, в условии `WHERE`, таком как `dictGet('dict', 'elevation', id) > 1800` — лучше использовать обычный столбец с нативными индексами. ClickHouse может использовать `PREWHERE`, чтобы пропускать гранулы для обычного столбца, а `dictGet` вычисляется построчно и не использует индексы.

Общее практическое правило:

* Используйте словари вместо JOIN-ов с небольшими таблицами измерений, когда ключ для поиска уже доступен.
* Используйте обычные столбцы и индексы, когда нужно фильтровать по найденному значению для большого числа строк.

<div id="choosing-a-layout">
  ## Выбор структуры
</div>

Конструкция `LAYOUT` задаёт внутреннюю структуру данных словаря. Все доступные структуры описаны в [справочнике по структурам](/docs/ru/reference/statements/create/dictionary/layouts/overview#storing-dictionaries-in-memory).

При выборе структуры используйте следующие рекомендации:

* **`flat`** — самая быстрая структура (простой поиск по смещению в массиве), но ключи должны иметь тип `UInt64` и по умолчанию ограничены 500 000 (`max_array_size`). Лучше всего подходит для монотонно возрастающих целочисленных ключей в таблицах малого и среднего размера. Разреженное распределение ключей (например, значения 1 и 500 000) приводит к неэффективному использованию памяти, поскольку размер массива определяется максимальным ключом. Если вы упираетесь в предел 500k, это сигнал перейти на `hashed_array`.
* **`hashed_array`** — рекомендуемая структура по умолчанию для большинства сценариев. Хранит атрибуты в массивах, а хеш-таблица сопоставляет ключи с индексами массива. Почти так же быстра, как `hashed`, но эффективнее использует память, особенно при большом числе атрибутов.
* **`hashed`** — хранит весь словарь в хеш-таблице. Может быть быстрее, чем `hashed_array`, если атрибутов очень мало, но потребляет больше памяти по мере увеличения их числа.
* **`complex_key_hashed` / `complex_key_hashed_array`** — используйте их, когда ключи нельзя привести к `UInt64` (например, ключи типа `String`). Для них характерны те же компромиссы по производительности, что и для вариантов без составного ключа.
* **`sparse_hashed`** — снижает использование памяти по сравнению с `hashed`, но ценой дополнительной нагрузки на CPU. Редко бывает лучшим выбором — эффективен только при наличии одного атрибута. В большинстве случаев лучше подходит `hashed_array`.
* **`cache` / `ssd_cache`** — кэшируют только часто используемые ключи. Полезны, когда весь набор данных не помещается в памяти, но при промахах кэша поиск может обращаться к источнику. Не рекомендуются для рабочих нагрузок, чувствительных к задержкам.
* **`direct`** — выполняет запрос к источнику для каждого поиска без хранения данных в памяти. Используйте, когда данные меняются слишком часто для кэширования или когда словарь слишком велик, чтобы целиком поместиться в памяти.

<div id="monitoring-dictionary-usage">
  ## Мониторинг использования словарей
</div>

Отслеживайте использование памяти и состояние словарей с помощью таблицы [`system.dictionaries`](/docs/ru/reference/system-tables/dictionaries):

```sql theme={null}
SELECT
    name,
    status,
    element_count,
    formatReadableSize(bytes_allocated) AS size,
    query_count,
    hit_rate,
    found_rate,
    last_exception
FROM system.dictionaries
```

Ключевые столбцы:

* `bytes_allocated` — объём памяти, который использует словарь. Словари хранят данные в несжатом виде, поэтому это значение может быть значительно больше сжатого размера таблицы.
* `hit_rate` и `found_rate` — полезны для оценки эффективности структуры `cache`.
* `last_exception` — проверьте это поле, если словарь не удаётся загрузить или обновить.
