Когда использовать словари вместо JOIN-ов
WHERE. Хотя в последних версиях (24.12+) во многих случаях фильтры применяются до JOIN-ов, это не всегда устраняет накладные расходы. При использовании словаря вы вызываете dictGet прямо в выражении, поэтому поиск выполняется только для строк, которые уже прошли фильтрацию.
Однако dictGet подходит не всегда. Если вам нужно вызывать dictGet для большой доли строк таблицы — например, в условии WHERE, таком как dictGet('dict', 'elevation', id) > 1800 — лучше использовать обычный столбец с нативными индексами. ClickHouse может использовать PREWHERE, чтобы пропускать гранулы для обычного столбца, а dictGet вычисляется построчно и не использует индексы.
Общее практическое правило:
- Используйте словари вместо JOIN-ов с небольшими таблицами измерений, когда ключ для поиска уже доступен.
- Используйте обычные столбцы и индексы, когда нужно фильтровать по найденному значению для большого числа строк.
Выбор структуры
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). Для них характерны те же компромиссы по производительности, что и для вариантов без составного ключа.sparse_hashed— снижает использование памяти по сравнению сhashed, но ценой дополнительной нагрузки на CPU. Редко бывает лучшим выбором — эффективен только при наличии одного атрибута. В большинстве случаев лучше подходитhashed_array.cache/ssd_cache— кэшируют только часто используемые ключи. Полезны, когда весь набор данных не помещается в памяти, но при промахах кэша поиск может обращаться к источнику. Не рекомендуются для рабочих нагрузок, чувствительных к задержкам.direct— выполняет запрос к источнику для каждого поиска без хранения данных в памяти. Используйте, когда данные меняются слишком часто для кэширования или когда словарь слишком велик, чтобы целиком поместиться в памяти.
Мониторинг использования словарей
system.dictionaries:
bytes_allocated— объём памяти, который использует словарь. Словари хранят данные в несжатом виде, поэтому это значение может быть значительно больше сжатого размера таблицы.hit_rateиfound_rate— полезны для оценки эффективности структурыcache.last_exception— проверьте это поле, если словарь не удаётся загрузить или обновить.