Словарь
Словарь в ClickHouse предоставляет представление данных в оперативной памяти в формате key-value из различных внутренних и внешних источников, оптимизированное для запросов с крайне низкой задержкой поиска.
Словари полезны для:
- Повышения производительности запросов, особенно при использовании в операциях
JOIN - Обогащения данных на лету в процессе ингестии, не замедляя её

Ускорение соединений с помощью Dictionary
Dictionary можно использовать для ускорения определённого типа JOIN: LEFT ANY, когда ключ соединения должен совпадать с ключевым атрибутом базового key-value-хранилища.

В таком случае ClickHouse может использовать Dictionary для выполнения Direct Join. Это самый быстрый алгоритм соединения в ClickHouse, и он применим, когда базовый движок таблицы для таблицы правой части поддерживает key-value-запросы с низкой задержкой. В ClickHouse есть три движка таблиц, обеспечивающие это: Join (по сути, предварительно вычисленная хеш-таблица), EmbeddedRocksDB и Dictionary. Мы опишем подход на основе Dictionary, но механика одинакова для всех трёх движков.
Алгоритм Direct Join требует, чтобы правая таблица была реализована на основе Dictionary, так, чтобы данные, которые нужно присоединять из этой таблицы, уже находились в памяти в виде key-value-структуры данных с низкой задержкой.
Пример
Используя набор данных Stack Overflow, ответим на вопрос: Какой пост, касающийся SQL, является самым спорным на Hacker News?
Мы будем считать пост спорным, если у него схожее количество голосов «за» и «против». Мы вычислим эту абсолютную разницу, где значение, ближе к нулю, означает большую спорность. Будем считать, что у поста должно быть как минимум 10 голосов «за» и 10 «против» — посты, за которые почти не голосуют, не слишком спорные.
При нормализованных данных этот запрос в текущем виде требует JOIN с использованием таблиц posts и votes:
Используйте меньшие наборы данных в правой части
JOIN: Этот запрос может показаться избыточно многословным, так как фильтрация поPostIdвыполняется и во внешнем, и во вложенном запросах. Это оптимизация производительности, которая обеспечивает быстрое время отклика запроса. Для оптимальной производительности всегда следите за тем, чтобы правая сторонаJOINбыла меньшим набором и по возможности как можно меньшего размера. Советы по оптимизации производительностиJOINи обзору доступных алгоритмов приведены в этой серии статей в блоге.
Хотя этот запрос работает быстро, он требует от нас аккуратного использования JOIN, чтобы достичь хорошей производительности. В идеале мы бы просто отфильтровали посты по тем, которые содержат «SQL», прежде чем анализировать значения UpVote и DownVote для этого подмножества блогов, чтобы вычислить нашу метрику.
Применение словаря
Чтобы продемонстрировать эти концепции, мы используем словарь для наших данных о голосах. Поскольку словари обычно хранятся в памяти (ssd_cache — исключение), пользователям следует учитывать размер данных. Проверим размер нашей таблицы votes:
Данные будут храниться в нашем словаре без сжатия, поэтому нам требуется как минимум 4 ГБ памяти, если бы мы сохраняли все столбцы (мы этого делать не будем) в словаре. Словарь будет реплицирован по нашему кластеру, поэтому этот объём памяти нужно зарезервировать на каждый узел.
В приведённом ниже примере данные для нашего словаря берутся из таблицы ClickHouse. Хотя это и является наиболее распространённым источником словарей, поддерживается ряд источников, включая файлы, HTTP и базы данных, в том числе Postgres. Как мы покажем, словари могут автоматически обновляться, что является идеальным способом обеспечить доступность небольших наборов данных, подверженных частым изменениям, для прямых JOIN-ов.
Для нашего словаря необходим первичный ключ, по которому будут выполняться поиски. Концептуально он идентичен первичному ключу в транзакционной базе данных и должен быть уникальным. Наш запрос выше требует поиска по ключу соединения — PostId. Словарь, в свою очередь, должен быть заполнен суммарным количеством голосов «за» и «против» для каждого PostId из нашей таблицы votes. Ниже приведён запрос для получения данных для этого словаря:
Чтобы создать наш словарь, потребуется следующий DDL — обратите внимание на использование нашего запроса, приведённого выше:
В самоуправляемой установке OSS приведённую выше команду необходимо выполнить на всех узлах. В ClickHouse Cloud словарь будет автоматически реплицирован на все узлы. Эту операцию выполняли на узле ClickHouse Cloud с 64 ГБ ОЗУ, загрузка заняла 36 с.
Чтобы проверить объём памяти, потребляемой нашим словарём:
Теперь получение голосов «за» и «против» для конкретного PostId сводится к использованию простой функции dictGet. Ниже показано, как получить значения для поста 11227902:
Мало того, что этот запрос значительно проще, он ещё и более чем вдвое быстрее! Его можно дополнительно оптимизировать, загружая в словарь только посты с более чем 10 голосами «за» и «против» и сохраняя лишь заранее вычисленное значение спорности.
Обогащение данных при выполнении запроса
Словари можно использовать для поиска значений в момент выполнения запроса. Эти значения могут возвращаться в результатах запроса или использоваться в агрегациях. Предположим, мы создаём словарь для сопоставления идентификаторов пользователей с их местоположением:
Мы можем использовать этот словарь для обогащения результатов:
Аналогично приведённому выше примеру join, мы можем использовать тот же словарь, чтобы эффективно определить, откуда происходит большинство постов:
Обогащение во время индексации
В приведённом выше примере мы использовали словарь на этапе выполнения запроса, чтобы убрать JOIN. Словари также можно использовать для обогащения строк на этапе вставки. Это обычно уместно, если значение для обогащения не меняется и существует во внешнем источнике, который можно использовать для заполнения словаря. В таком случае обогащение строки на этапе вставки позволяет избежать обращения к словарю во время выполнения запроса.
Предположим, что Location пользователя в Stack Overflow никогда не меняется (в реальности это не так), а именно столбец Location таблицы users. Допустим, мы хотим выполнить аналитический запрос к таблице posts по местоположению. В этой таблице есть столбец UserId.
Словарь предоставляет соответствие между идентификатором пользователя и его местоположением, используя таблицу users:
Мы исключаем пользователей с
Id < 0, что позволяет использовать тип словаряHashed. Пользователи сId < 0— это системные пользователи.
Чтобы задействовать этот словарь на этапе вставки данных в таблицу posts, необходимо изменить схему:
В приведённом выше примере Location объявлен как столбец MATERIALIZED. Это означает, что значение может быть передано в запросе INSERT и всегда будет вычислено.
ClickHouse также поддерживает столбцы с типом
DEFAULT(когда значение может быть явно указано при вставке или вычислено, если не задано).
Чтобы заполнить таблицу, мы можем использовать обычный INSERT INTO SELECT из S3:
Теперь мы можем определить название местоположения, откуда поступает большинство сообщений:
Расширенные темы по словарям
Выбор LAYOUT словаря
Секция LAYOUT управляет внутренней структурой данных словаря. Существует несколько вариантов, которые описаны здесь. Некоторые рекомендации по выбору подходящего варианта структуры можно найти здесь.
Обновление словарей
Мы указали для словаря LIFETIME со значением MIN 600 MAX 900. LIFETIME — это интервал обновления словаря; в данном случае значения приводят к периодической перезагрузке через случайный интервал между 600 и 900 с. Этот случайный интервал необходим для распределения нагрузки на источник словаря при обновлении на большом количестве серверов. Во время обновления старая версия словаря по‑прежнему может запрашиваться; только начальная загрузка блокирует запросы. Обратите внимание, что установка (LIFETIME(0)) предотвращает обновление словарей.
Словари можно принудительно перезагрузить с помощью команды SYSTEM RELOAD DICTIONARY.
Для источников баз данных, таких как ClickHouse и Postgres, можно настроить запрос, который будет обновлять словари только в том случае, если они действительно изменились (это определяется ответом запроса), а не через фиксированный периодический интервал. Дополнительные сведения можно найти здесь.
Другие типы словарей
ClickHouse также поддерживает иерархические словари, полигональные словари и словари на основе регулярных выражений.