- Позволяет быстро записывать состояния объектов, которые постоянно меняются.
- Удаляет старые состояния объектов в фоновом режиме. Это значительно сокращает объем хранимых данных.
VersionedCollapsingMergeTree служит той же цели, что и CollapsingMergeTree, но использует другой алгоритм схлопывания, который позволяет вставлять данные в любом порядке с использованием нескольких потоков. В частности, столбец Version помогает корректно схлопывать строки, даже если они вставлены в неправильном порядке. В отличие от него, CollapsingMergeTree допускает только строго последовательную вставку.
Создание таблицы
Параметры движка
Секции запроса
VersionedCollapsingMergeTree требуются те же секции, что и при создании таблицы MergeTree.
Схлопывание
Данные
Sign. Если Sign = 1, это означает, что строка представляет состояние объекта (назовём её строкой состояния). Если Sign = -1, это указывает на отмену состояния объекта с теми же атрибутами (назовём её строкой отмены). Также используйте столбец Version, который должен идентифицировать каждое состояние объекта отдельным числом.
Например, мы хотим вычислить, сколько страниц пользователи посетили на некотором сайте и сколько времени они там провели. В некоторый момент времени мы записываем следующую строку, отражающую состояние активности пользователя:
Sign.
Вторая строка содержит текущее состояние.
Поскольку нам нужно только последнее состояние активности пользователя, строки
VersionedCollapsingMergeTree делает это при слиянии частей данных.
Чтобы узнать, почему для каждого изменения нужны две строки, см. Алгоритм.
Примечания по использованию
- Программа, которая записывает данные, должна помнить состояние объекта, чтобы можно было его отменить. Строка “Cancel” должна содержать копии полей первичного ключа, версию строки “state” и противоположный
Sign. Это увеличивает начальный объем хранилища, но позволяет быстро записывать данные. - Длинные растущие массивы в столбцах снижают эффективность движка из-за нагрузки при записи. Чем проще данные, тем выше эффективность.
- Результаты
SELECTсильно зависят от согласованности истории изменений объекта. Будьте внимательны при подготовке данных для вставки. Несогласованные данные могут приводить к непредсказуемым результатам, например к отрицательным значениям для неотрицательных метрик, таких как глубина сеанса.
Алгоритм
Sign. Порядок строк не имеет значения.
При вставке данных ClickHouse упорядочивает строки по первичному ключу. Если столбец Version не входит в первичный ключ, ClickHouse неявно добавляет его в конец первичного ключа и использует для упорядочивания.
Выборка данных
SELECT-запросы в несколько потоков и не может предсказать порядок строк в результате. Это означает, что, если вам нужно получить полностью «схлопнутые» данные из таблицы VersionedCollapsingMergeTree, необходима агрегация.
Чтобы завершить схлопывание, напишите запрос с предложением GROUP BY и агрегатными функциями, учитывающими знак. Например, чтобы вычислить количество, используйте sum(Sign) вместо count(). Чтобы вычислить сумму чего-либо, используйте sum(Sign * x) вместо sum(x) и добавьте HAVING sum(Sign) > 0.
Агрегатные функции count, sum и avg можно вычислить таким способом. Агрегатную функцию uniq можно вычислить, если у объекта есть хотя бы одно несхлопнутое состояние. Агрегатные функции min и max вычислить нельзя, потому что VersionedCollapsingMergeTree не сохраняет историю значений схлопнутых состояний.
Если вам нужно получить данные со «схлопыванием», но без агрегации (например, чтобы проверить, есть ли строки, у которых последние значения соответствуют определённым условиям), можно использовать модификатор FINAL в предложении FROM. Этот подход неэффективен и не должен использоваться с большими таблицами.
Пример использования
INSERT, чтобы создать две разные части данных. Если вставить данные одним запросом, ClickHouse создаст одну часть данных и никогда не выполнит слияние.
Получение данных:
INSERT. Запрос SELECT выполнялся в двух потоках, поэтому в результате строки расположены в случайном порядке.
Схлопывания не произошло, потому что части данных ещё не были слиты. ClickHouse выполняет слияние частей данных в непредсказуемый момент времени, который мы не можем заранее определить.
Вот почему нам нужна агрегация:
FINAL в предложении FROM.