Введение в ClickHouse и OLAP: Быстрый старт

Курс формирует фундаментальное понимание отличий аналитических систем от транзакционных и закладывает базу для работы с колоночными СУБД. Вы пройдете путь от теории хранения данных до запуска первого контейнера и выполнения оптимизированного запроса.

1. Природа аналитических данных: почему классические базы данных не справляются с Big Data

Природа аналитических данных: почему классические базы данных не справляются с Big Data

Представьте глобальный маркетплейс в разгар «Черной пятницы». Каждую секунду пользователи совершают десятки тысяч действий: добавляют товары в корзину, оплачивают заказы, меняют адреса доставки. Система работает безупречно, балансы списываются мгновенно, заказы формируются без задержек. Но стоит директору по маркетингу нажать кнопку «Сформировать отчет по среднему чеку в категории "Электроника" за последние 5 лет по всем регионам» — и база данных «зависает» на несколько часов, а пользователи начинают жаловаться на ошибки при оплате.

Почему система, способная обрабатывать тысячи покупок в секунду, ломается от одного-единственного аналитического вопроса? Ответ кроется в фундаментальном отличии природы транзакционных и аналитических данных.

Идеальный бухгалтер: транзакционные системы (OLTP)

Классические реляционные базы данных (такие как PostgreSQL, MySQL или Oracle) создавались для операционной работы. Их главная задача — быстро и надежно записать, обновить или удалить конкретную строку.

Этот тип нагрузки называется OLTP.

> OLTP (Online Transaction Processing) — класс систем, ориентированных на обработку огромного потока коротких транзакций в реальном времени. Главный приоритет здесь — целостность данных и скорость точечных изменений.

Когда вы покупаете книгу на маркетплейсе, база данных выполняет хирургически точную операцию:

  • Находит строку с вашим профилем и проверяет баланс.
  • Находит строку с книгой и уменьшает остаток на складе на 1.
  • Создает новую строку в таблице заказов.
  • Для OLTP-системы данные — это набор независимых карточек (строк), где каждая карточка описывает один объект целиком (пользователя, товар, заказ). База данных оптимизирована так, чтобы мгновенно достать одну карточку по ее идентификатору, изменить в ней пару букв и положить обратно.

    Аналитическая стена: когда строк становится слишком много

    Проблемы начинаются, когда мы перестаем смотреть на одиночные карточки и пытаемся увидеть общую картину.

    Аналитический запрос (например, для построения графика продаж) выглядит в виде SQL-кода примерно так:

    Чтобы выполнить этот запрос, классической базе данных нужно прочитать историю заказов. И здесь проявляется ее архитектурная слабость. Поскольку данные хранятся строками, система не может прочитать только колонки region и price. Ей приходится поднимать с жесткого диска всю строку целиком, включая длинные текстовые описания, адреса доставки, статусы и комментарии курьеров.

    !Симуляция аналитического запроса в классической базе данных

    Если в таблице миллиард записей, база данных вынуждена прочитать терабайты лишней информации только ради того, чтобы сложить два числа. Дисковая подсистема задыхается, оперативная память переполняется «мусорными» данными, а процессор тратит время на распаковку ненужных колонок. Именно поэтому операционная база данных зависает: тяжелый аналитический запрос монополизирует все ресурсы сервера.

    Природа аналитических данных (OLAP)

    Аналитические данные ведут себя совершенно иначе, чем операционные. Если внимательно посмотреть на логику работы с Big Data, можно выделить три ключевые особенности:

  • Данные неизменны (Immutable). Исторические события не меняются. Если пользователь кликнул на баннер вчера в 15:00, этот факт уже никогда не изменится. Нам не нужно обновлять эти строки, мы только дописываем новые (операция Insert).
  • Масштаб чтения огромен. Запросы редко ищут одного конкретного пользователя. Обычно аналитика требует сканирования миллионов или миллиардов записей за один проход.
  • Читается малая часть атрибутов. В таблице событий может быть 100 колонок (IP, устройство, браузер, UTM-метки, координаты), но для конкретного отчета нужны только 2-3 из них.
  • Для работы с такими данными был выделен отдельный класс систем.

    > OLAP (Online Analytical Processing) — класс систем, спроектированных для быстрого выполнения сложных агрегирующих запросов (сумм, средних значений, группировок) над гигантскими массивами исторических данных.

    Разделяй и властвуй

    Осознав, что один инструмент не может быть одновременно идеальным скальпелем (OLTP) и мощным экскаватором (OLAP), инженеры пришли к архитектурному стандарту: разделению баз данных по их назначению.

    !Архитектурное разделение операционных и аналитических баз данных

    В современных IT-проектах операционная база (например, PostgreSQL) продолжает обслуживать текущие действия пользователей. Параллельно с этим, специальный процесс регулярно копирует новые данные и переносит их в специализированное аналитическое хранилище (Data Warehouse).

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

    2. Архитектурная революция: переход от строкового хранения к колоночному формату

    Архитектурная революция: переход от строкового хранения к колоночному формату

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

    В прошлой главе мы выяснили, что главная беда транзакционных систем в аналитике — это чтение колоссальных объемов лишней информации. Теперь пришло время заглянуть «под капот» и понять, как физическая архитектура хранения данных определяет скорость работы всей системы.

    Анатомия дискового ввода-вывода

    Чтобы понять масштаб проблемы, нужно спуститься на уровень физического носителя. Жесткие диски (HDD) и даже современные твердотельные накопители (SSD) не читают данные по одному байту. Они оперируют блоками (или страницами) фиксированного размера — например, по 4 или 8 килобайт.

    Если нужный вам байт находится внутри блока, операционная система прочитает весь блок целиком и поместит его в оперативную память. Это фундаментальное ограничение аппаратного обеспечения: дисковый ввод-вывод (Disk I/O) — самое узкое место любой базы данных. Процессор может складывать числа в тысячи раз быстрее, чем диск успевает поставлять их в память.

    Строковое хранение: идеальное для транзакций, гибельное для аналитики

    В классических реляционных базах данных (PostgreSQL, MySQL) данные на диске хранятся построчно.

    Допустим, у нас есть простая таблица из четырех полей: ID (целое число), Name (текст), Age (целое число) и Salary (целое число). На физическом диске запись одного человека представляет собой непрерывный кусок данных. За ним сразу идет запись второго человека, затем третьего.

    Если строка весит 100 байт, а колонка Salary занимает в ней всего 4 байта, то для вычисления средней зарплаты миллиона пользователей базе данных придется прочитать с диска все строки целиком.

    Рассчитаем объем прочитанных данных:

    При этом полезная нагрузка, которая действительно нужна для вычисления, составляет:

    Эффективность чтения в этом сценарии составляет всего 4%. Остальные 96% пропускной способности диска и оперативной памяти были потрачены впустую на загрузку имен и возрастов, которые тут же будут отброшены процессором.

    Переворот матрицы: Колоночный формат

    Чтобы решить эту проблему, создатели аналитических баз данных, таких как ClickHouse, пошли на радикальный шаг — они «перевернули» логику хранения на 90 градусов.

    В колоночной СУБД (Column-oriented DBMS) значения из разных колонок хранятся на диске раздельно. Все ID лежат в одном файле (или непрерывном блоке на диске), все имена Name — в другом, а все зарплаты Salary — в третьем.

    !Сравнение укладки данных на диск в строковом и колоночном форматах

    При таком подходе запрос на вычисление средней зарплаты обращается только к файлу, содержащему колонку Salary.

    Возвращаясь к нашему примеру: базе данных нужно прочитать ровно полезных данных. Диск читает блоки, заполненные исключительно зарплатами, не захватывая ни единого лишнего байта. Эффективность чтения возрастает до 100%. Мы только что ускорили дисковые операции в 25 раз, просто изменив способ физической укладки данных на носителе.

    !Симуляция чтения одной колонки в разных форматах хранения

    Побочный эффект, ставший суперсилой: Сжатие данных

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

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

    В колоночной базе данных в одном блоке лежат строго однородные данные. Если это колонка Age, то это длинная последовательность двузначных чисел. Если это колонка City, то это список названий городов, которые часто повторяются. Однородные данные сжимаются алгоритмами компрессии феноменально эффективно.

    Один из самых простых и показательных методов — RLE (Run-Length Encoding, кодирование длин серий). Представьте, что вы отсортировали таблицу по колонке City. На диске это будет выглядеть так: [Москва, Москва, Москва, Казань, Казань, Уфа, Уфа, Уфа, Уфа]

    Алгоритм RLE сжимает эту последовательность до компактного вида: [Москва x3, Казань x2, Уфа x4]

    Вместо хранения девяти строк текста, диск хранит три строки и три числа-множителя. В реальных аналитических базах данных коэффициент сжатия часто достигает 10:1. Это означает, что терабайт сырых данных занимает на диске всего 100 гигабайт.

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

    Итог

    Переход от строкового хранения к колоночному — это фундамент любой современной OLAP-системы. Мы устранили главное узкое место (чтение лишних данных с диска) и получили мощное сжатие за счет однородности колонок.

    Данные теперь доставляются в оперативную память с максимальной скоростью. Но возникает новый вызов: как заставить процессор обрабатывать эти потоки однородных данных так же эффективно, не тратя такты на постоянные переключения контекста? Ответ кроется в концепции векторного выполнения запросов, которая лежит в основе философии ClickHouse.