ClickHouse: строковая оптимизация с LowCardinality

от автора

Привет, Хабр!

В прошлых статьях мы разбирали основной движок ClickHouse — MergeTree, материализованые представления и словари. В этой статье разберем инструмент оптимизации — LowCardinality. Это не просто тип данных, а способ эффективной работы со строками.

1. LowCardinality

Прежде чем мы погрузимся в детали LowCardinality, давайте дадим определение понятию «кардинальность».

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

Теперь поговорим о LowCardinality и о том, как это связано с кардинальностью.

LowCardinality(T) — это специальная «обёртка» над другим типом данных T (как правило, это String или FixedString), которая заставляет ClickHouse использовать словарное кодирование для колонки. Это значит, что ClickHouse создаст словарь уникальных значений и в основной таблице будет хранить лишь компактные числовые ссылки на него. Этот тип данных особенно эффективен для колонок, где количество уникальных значений значительно меньше общего числа строк. Такие колонки называют колонками с низкой кардинальностью.

1.1. Как это работает?

Представим, что у нас есть огромная таблица с миллионами записей о визитах на сайт. В этой таблице есть колонка browser, где хранится название браузера пользователя: «Chrome», «Яндекс.Браузер» и «Safari». Уникальных названий браузеров всего три, но сами строки повторяются миллионы раз.

Для простоты восприятия изобразим это следующим образом:

Постоянное дублирование строк неэффективно как для хранения, так и для скорости выполнения запросов. Гораздо эффективнее было бы присвоить каждому уникальному браузеру короткий числовой код (например, «Яндекс.Браузер» → 1, «Safari» → 2, «Chrome» → 3) и хранить в таблице именно эти числа. Здесь мы и можем использовать оптимизацию с помощью типа данных LowCardinality.

Изменим тип данных в нашей первоначальной колонке со String на LowCardinality(String):

ClickHouse «под капотом» сделал следующее (в упрощённом виде):

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

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

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

SELECT browserFROM tableWHERE browser = 'Chrome'

Схематично выполнение запроса можно представить следующим образом:

  1. ClickHouse видит в запросе значение «Chrome» и один раз смотрит в словарь, чтобы найти его числовой ключ, в данном случае — 3.

  2. Теперь вся основная работа по фильтрации миллионов строк происходит с числами — это на порядки быстрее, чем искать по строкам. 

  3. Когда все строки с ключом 3 найдены, ClickHouse берёт эти ключи и, снова заглянув в словарь, превращает их обратно в строки «Chrome» для финального вывода. Этот шаг применяется лишь к небольшому набору итоговых строк, а не ко всей таблице.

1.2. Преимущества использования

  • Ускорение запросов: Запросы, использующие фильтрацию, группировку и сортировку по колонкам LowCardinality, выполняются значительно быстрее. ClickHouse оперирует с числами, что гораздо эффективнее, чем работа со строками.

  • Экономия места на диске: Хранение целочисленных индексов вместо повторяющихся строк или других значений может существенно сократить объём данных, занимаемый колонкой на диске.

2. Рекомендации по использованию

Главное правило — данных много, а уникальных значений мало.

Для чего подходит:

  • страны, города, регионы;

  • статусы: «new», «in_progress», «done», «error»;

  • типы устройств: «desktop», «mobile», «tablet»;

  • коды валют: «USD», «EUR», «RUB»;

  • названия браузеров, операционных систем;

  • HTTP-методы: «GET», «POST», «PUT»;

  • и т.д.

Тип данных LowCardinality наиболее эффективен для столбцов, содержащих до 10 000 уникальных значений, но может ухудшить производительность, когда их количество превышает 100 000. Стоит избегать использования LowCardinality для колонок с высокой кардинальностью (ID пользователей, ID заказов, полнотекстовые комментарии). В этих случаях размер словаря приблизится к размеру самих данных, а накладные расходы на его ведение сведут на нет всю пользу и даже замедлят работу. Также LowCardinality редко бывает полезен для числовых типов, так как они и так хранятся компактно.

Надеюсь, эта статья помогла вам понять, что такое LowCardinality и как он работает в ClickHouse.

P.S. Если вы хотите систематизировать знания и получить прочную теоретическую базу для дальнейшего освоения ClickHouse на практике, буду рад видеть вас на моем бесплатном курсе ClickHouse с нуля который охватывает все самое необходимое для уверенного старта в работе с технологией. Закрепить пройденную теорию можно на практическом продолжении курса ClickHouse с нуля: практика.

Удачи в изучении!

ссылка на оригинал статьи https://habr.com/ru/articles/1077906/