Перейти к основному содержимому
Перейти к основному содержимому

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

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

Введение в словари с подробными примерами см. в основном руководстве по словарям.

Когда использовать словари вместо соединения

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

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

Как правило:

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

Выбор структуры

Секция LAYOUT задаёт внутреннюю структуру данных словаря. Все доступные структуры описаны в справочнике по структурам словарей.

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

  • 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). Для них действуют те же компромиссы по производительности, что и для соответствующих структур без complex key.
  • sparse_hashed — снижает потребление памяти по сравнению с hashed ценой дополнительной нагрузки на CPU. Редко бывает лучшим выбором — эффективен только при наличии одного атрибута. В большинстве случаев лучше подходит hashed_array.
  • cache / ssd_cache — кэшируют только часто запрашиваемые ключи. Полезны, когда весь набор данных не помещается в памяти, но при промахах кэша обращения могут идти к источнику. Не рекомендуются для рабочих нагрузок, чувствительных к задержкам.
  • direct — обращается к источнику при каждом поиске без хранения данных в памяти. Используйте, когда данные изменяются слишком часто для кэширования или когда словарь слишком велик, чтобы целиком хранить его в памяти.

Мониторинг использования словарей

Отслеживайте потребление памяти и состояние с помощью таблицы system.dictionaries:

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 — проверьте это поле, если словарь не удается загрузить или обновить.