Рубріки: HighloadТеория

Использование AggregatingMergeTree в Clickhouse

Игорь Грегорченко

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

Пусть мы храним события (например, просмотры страниц) в следующем виде:

**date       | user_id | url | device**
%TODAY% |       1 | /   | Desktop
%TODAY% |       1 | /a  | Desktop
%TODAY% |       2 | /   | Tablet
%TODAY% |       3 | /   | Tablet

## Обычный лог всех просмотров страниц

Представим, что эта таблица огромная. Агрегатные функции на таблицах с 1+ млрд записей часто работают не так быстро:

SELECT count(*)
FROM log_41949_events

┌────count()─┐
│ 1894260239 │
└────────────┘

1 rows in set. ***Elapsed: 8.430 sec.*** Processed 1.89 billion rows, 3.79 GB (224.71 million rows/s., 449.41 MB/s.) 

## Один сервер CH на обычном HDD

Пусть нам необходимо часто делать выборки с фильтром по устройству (device):

SELECT 
    count(*), 
    device
FROM log_41949_events 
GROUP BY device

┌────count()─┬─device───────────┐
│ 1260916969 │ desktop          │
│  454097963 │ smart (Android)  │
│   94101924 │ smart (iOS)      │
│   17922239 │ tablet (iOS)     │
│   67682187 │ tablet (Android) │
│     215990 │ smart (Other)    │
└────────────┴──────────────────┘

6 rows in set. ***Elapsed: 4.022 sec.*** Processed 1.89 billion rows, 1.89 GB (90.82 million rows/s., 90.82 MB/s.)

## Пример запроса с настоящей таблицы на сервере, который собирает около 200 млн событий в сутки

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

AggregatingMergeTree

Этот движок похож на ReplacingMergeTree и CollapsingMergeTree. В нем также определяется ключ по которому выполняется слияние данных. Но кроме этого, движок позволяет использовать агрегатные функции (count, sum, uniq и т.п.). Т.е. вместо хранения всей таблицы, мы могли бы хранить данные в таком виде:

**date       | device  | total**
%TODAY% | Desktop | 2
%TODAY% | Tablet  | 2

## Агрегированная таблица

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

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

  • Все данные складываем в оригинальную таблицу, которая хранит данные в исходном виде.
  • Создает материализованное представление для случая, когда нам необходимо делать агрегационные выборки (в нашем случае – количество событий по устройствам).
  • Используем вторую таблицу для нужных выборок (по устройствам), а все остальные отправляем в исходную таблицу.

Для создания агрегационного представления достаточно объявить специальную таблицу:

CREATE **MATERIALIZED VIEW** log_41949_devices

ENGINE = **AggregatingMergeTree**(date, (date, device), 8192) **POPULATE AS**

SELECT

date,

device,

**countState(*) AS total**

FROM log_41949_events

GROUP BY

date,

device

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

Создаем материализованное представление log_41949_devices. Для него указываем тип движка AggregatingMergeTree. Инструкция POPULATE попросит сервер заполнить новую таблицу всеми данными из исходной таблицы сразу после создания. Кроме этого, созданная таблица будет автоматически заполняться данными, которые будут записываться в оригинальную таблицу.

Для того, чтобы заработали агрегационные функции, вместо них необходимо указывать их состояния: [функция]State() (существуют для всех агрегатных функций: countState, sumState, uniqState, minState, maxState). В нашем случае, мы считаем количество countState(*).

После заполнения таблицы, она станет доступна для выборок. Опять, вместо обычной агрегатной функции необходимо вызывать ее версию для слияния ([функция]Merge()):

SELECT 
    **countMerge(total),**
    device
FROM **log_41949_devices**
GROUP BY device

┌─countMerge(total)─┬─device───────────┐
│        1266626129 │ desktop          │
│         457198984 │ smart (Android)  │
│          94784896 │ smart (iOS)      │
│          18007576 │ tablet (iOS)     │
│          68026713 │ tablet (Android) │
│            217264 │ smart (Other)    │
└───────────────────┴──────────────────┘

6 rows in set. Elapsed: **0.001 sec**. 

## Запрос к агрегационной таблице

Скорость выполнения такого запроса в несколько тысяч раз больше исходного.

В запросе для построения таблицы можно использовать обычный SQL, например фильтрацию:

CREATE MATERIALIZED VIEW log_41949_devices

ENGINE = AggregatingMergeTree(date, (date, device), 8192) POPULATE AS

SELECT

date,

device,

countState(*) AS total

FROM log_41949_events

**WHERE country = ‘Planet Earth’**

GROUP BY

date,

device

Используйте агрегации только в крайних случаях, т.к. они усложняют поддержку приложения.

<h2>TL;DR

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

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023