Перейти к основному содержимому
Перейти к основному содержимому

Обзор

Различия между обновлением данных в ClickHouse и OLTP базах данных

Когда дело доходит до обработки обновлений, ClickHouse и OLTP базы данных значительно различаются из-за их основных философий проектирования и целевых случаев использования. Например, PostgreSQL, ориентированная на строки, совместимая с ACID реляционная база данных, поддерживает надежные и транзакционные операции обновления и удаления, обеспечивая согласованность и целостность данных через такие механизмы, как управление многоверсионной конкурентностью (MVCC). Это позволяет безопасно и надежно вносить изменения даже в условиях высокой конкурентности.

С другой стороны, ClickHouse - это столбцовая база данных, оптимизированная для аналитики с преобладанием чтения и операций добавления с высокой пропускной способностью. Хотя она и поддерживает обновления и удаления на месте, их следует использовать осторожно, чтобы избежать высокой I/O. В качестве альтернативы таблицы могут быть реорганизованы, чтобы преобразовать удаление и обновление в операции добавления, где они обрабатываются асинхронно и/или во время чтения, что отражает акцент на высокой пропускной способности приема данных и эффективной производительности запросов, а не на манипуляциях с данными в реальном времени.

Методы обновления данных в ClickHouse

Существует несколько способов обновления данных в ClickHouse, каждый из которых имеет свои преимущества и характеристики производительности. Вам следует выбрать подходящий метод в зависимости от вашей модели данных и объема данных, которые вы намерены обновить.

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

В resumen, операции обновления следует выполнять осторожно, и очередь мутаций следует тщательно отслеживать с помощью таблицы system.mutations. Не выполняйте обновления слишком часто, как вы бы делали это в OLTP базах данных. Если у вас есть требование к частым обновлениям, смотрите ReplacingMergeTree.

МетодСинтаксисКогда использовать
Обновление мутациейALTER TABLE [table] UPDATEИспользуйте, когда данные должны быть немедленно обновлены на диске (например, для соблюдения норм). Отрицательно влияет на производительность SELECT.
Легковесные обновленияUPDATE [table] SET ... WHEREИспользуйте для обновления небольших объемов данных (до ~10% таблицы). Создает патч-части для немедленной видимости без перезаписи целых колонок. Добавляет дополнительные затраты к запросам SELECT, но имеет предсказуемую задержку. В настоящее время является экспериментальным.
Обновления на летуALTER TABLE [table] UPDATEВключить, используя SET apply_mutations_on_fly = 1;. Используйте при обновлении небольших объемов данных. Строки немедленно возвращаются с обновленными данными во всех последующих запросах SELECT, но изначально только помечаются как обновленные на диске.
ReplacingMergeTreeENGINE = ReplacingMergeTreeИспользуйте, когда обновляете большие объемы данных. Этот движок таблиц оптимизирован для дедупликации данных при слиянии.
CollapsingMergeTreeENGINE = CollapsingMergeTree(Sign)Используйте, когда часто обновляются отдельные строки, или для сценариев, где необходимо поддерживать актуальное состояние объектов, которые со временем меняются. Например, для отслеживания активности пользователей или статистики статей.

Обновление мутациями

Обновления мутациями могут быть выполнены с помощью команды ALTER TABLE ... UPDATE, например,

ALTER TABLE posts_temp
        (UPDATE AnswerCount = AnswerCount + 1 WHERE AnswerCount = 0)

Эти операции являются чрезвычайно I/O-емкими, перезаписывая все части, которые соответствуют выражению WHERE. В этом процессе нет атомарности - части заменяются мутированными частями, как только они готовы, и SELECT запрос, который начинает выполняться во время мутации, увидит данные из частей, которые уже были изменены, вместе с данными из частей, которые еще не были изменены. Пользователи могут отслеживать состояние прогресса через таблицу systems.mutations. Эти операции интенсивны по I/O и должны использоваться экономно, так как они могут повлиять на производительность SELECT запросов к кластеру.

Читать подробнее о обновлениях мутациями.

Легковесные обновления

Легковесные обновления - это функция ClickHouse, которая обновляет строки, используя "патч-части" - специальные части данных, содержащие только обновленные колонки и строки, а не переписывая целые колонки, как традиционные мутации. Легковесное ОБНОВЛЕНИЕ Ключевые характеристики:

  • Использует стандартный синтаксис UPDATE и создает патч-части немедленно, не дожидаясь слияний
  • Обновленные значения немедленно видны в запросах SELECT через применение патчей, но физически материализуются только во время последующих слияний
  • Предназначен для небольших обновлений (до ~10% таблицы) с предсказуемой задержкой
  • Добавляет дополнительные затраты к запросам SELECT, которым необходимо применять патчи, но избегает переписывания целых колонок

Для получения дополнительных деталей смотрите "Оператор Легковесное UPDATE".

Обновления на лету

Обновления на лету предоставляют механизм для обновления строк таким образом, что они обновляются немедленно, и последующие запросы SELECT автоматически будут возвращать измененные значения (это влечет за собой дополнительные затраты и замедлит запросы). Это эффективно устраняет ограничение атомарности обычных мутаций. Мы покажем пример ниже:

SET apply_mutations_on_fly = 1;

SELECT ViewCount
FROM posts
WHERE Id = 404346

┌─ViewCount─┐
│   26762   │
└───────────┘

1 row in set. Elapsed: 0.115 sec. Processed 59.55 million rows, 238.25 MB (517.83 million rows/s., 2.07 GB/s.)
Peak memory usage: 113.65 MiB.

-increment count
ALTER TABLE posts
        (UPDATE ViewCount = ViewCount + 1 WHERE Id = 404346)

SELECT ViewCount
FROM posts
WHERE Id = 404346

┌─ViewCount─┐
│       26763   │
└───────────┘

1 row in set. Elapsed: 0.149 sec. Processed 59.55 million rows, 259.91 MB (399.99 million rows/s., 1.75 GB/s.)

Обратите внимание, что для обновлений на лету мутация все еще используется для обновления данных; она просто не материализуется немедленно и применяется во время запросов SELECT. Она будет все равно применяться в фоновом режиме как асинхронный процесс и влечет за собой такие же тяжелые затраты, как и мутация, и, таким образом, является интенсивной по I/O операцией, которую следует использовать экономно. Выражения, которые можно использовать с этой операцией, также ограничены (см. здесь для подробностей).

Читать подробнее о обновлениях на лету.

CollapsingMergeTree

Исходя из идеи, что обновления дорогостоящи, но вставки могут быть использованы для выполнения обновлений, движок таблиц CollapsingMergeTree может использоваться вместе с колонкой sign как способ сообщить ClickHouse обновить конкретную строку, коллапсируя (удаляя) пару строк с sign равным 1 и -1. Если -1 вставлено для колонки sign, вся строка будет удалена. Если 1 вставлено для колонки sign, ClickHouse сохранит строку. Строки для обновления определяются на основе ключа сортировки, используемого в операторе ORDER BY () при создании таблицы.

CREATE TABLE UAct
(
    UserID UInt64,
    PageViews UInt8,
    Duration UInt8,
    Sign Int8 -- A special column used with the CollapsingMergeTree table engine
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID

INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1)
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1) -- sign = -1 signals to update the state of this row
INSERT INTO UAct VALUES (4324182021466249494, 6, 185, 1) -- the row is replaced with the new state

SELECT
    UserID,
    sum(PageViews * Sign) AS PageViews,
    sum(Duration * Sign) AS Duration
FROM UAct
GROUP BY UserID
HAVING sum(Sign) > 0

┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 4324182021466249494 │         6 │      185 │
└─────────────────────┴───────────┴──────────┘
примечание

Указанный выше подход для обновления требует от пользователей поддерживать состояние на стороне клиента. Хотя это наиболее эффективно с точки зрения ClickHouse, работать с ним в масштабах может быть сложно.

Рекомендуем прочитать документацию по CollapsingMergeTree для более полного обзора.

Дополнительные ресурсы