Могу ли я использовать ClickHouse как key-value хранилище?
Краткий ответ — «нет». Нагрузки типа key-value находятся в числе основных сценариев, когда НЕ СЛЕДУЕТ использовать ClickHouse. В конце концов, это система класса OLAP, тогда как существует множество отличных key-value хранилищ.
Тем не менее, могут быть ситуации, когда всё же имеет смысл использовать ClickHouse для запросов, похожих на key-value. Обычно это малобюджетные продукты, где основная нагрузка носит аналитический характер и хорошо подходит для ClickHouse, но есть и некоторый дополнительный процесс, которому нужна модель key-value без очень высокой пропускной способности запросов и без жёстких требований к задержкам. Если бы у вас был неограниченный бюджет, вы бы развернули отдельную key-value базу данных для этой вторичной нагрузки, но в реальности появляется дополнительная стоимость сопровождения ещё одной системы хранения (мониторинг, резервные копии и т.д.), чего, возможно, хотелось бы избежать.
Если вы решите пойти против рекомендаций и выполнять key-value‑подобные запросы к ClickHouse, вот несколько советов:
- Ключевая причина, по которой точечные запросы дороги в ClickHouse, — это разреженный первичный индекс основного семейства движков таблиц MergeTree. Этот индекс не может указывать на каждую конкретную строку данных, вместо этого он указывает только на каждую N‑ю строку, и системе приходится сканировать от соседней N‑й строки до нужной, по пути читая избыточные данные. В сценарии key-value может быть полезно уменьшить значение N с помощью настройки
index_granularity. - ClickHouse хранит каждый столбец в отдельном наборе файлов, поэтому для сборки одной полной строки ему нужно пройти по каждому из этих файлов. Их количество линейно растёт с числом столбцов, поэтому в сценарии key-value может иметь смысл избегать большого числа столбцов и разместить всю полезную нагрузку в одном столбце типа
String, закодированном в каком-либо формате сериализации, таком как JSON, Protobuf или любом другом подходящем формате. - Существует альтернативный подход, использующий движок таблицы Join вместо обычных таблиц
MergeTreeи функцию joinGet для извлечения данных. Он может обеспечить более высокую производительность запросов, но может сопровождаться некоторыми проблемами с удобством использования и надёжностью. Вот пример использования.