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

Обзор обновления данных

В этой статье описаны возможности Apache Doris по обновлению и удалению данных. Она поможет ответить на следующие вопросы:

  • Какую модель таблицы выбрать для вашего сценария?
  • Когда следует использовать обновление при загрузке данных (UPSERT, частичное обновление столбцов), а когда следует обновлять данные с помощью DML (UPDATE, INSERT INTO SELECT)?
  • Как устроена модель Unique Key? (Merge-on-Write, столбец Sequence, метка удаления, частичное обновление столбцов)
  • Как реализуются типичные сценарии, такие как синхронизация CDC и формирование широких таблиц в реальном времени?

Рекомендации по чтению:

1. Выбор способа обновления​

1.1 Сравнение моделей таблиц и возможностей обновления​

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

Модель таблицыОрганизация данныхПоддерживаемые способы обновления и удаленияТипичные сценарии использования
Модель Unique KeyКаждая строка определяется уникальным первичным ключом; дедупликация выполняется при записиUPSERT, частичное обновление столбцов, UPDATE, пометка на удаление, DELETEИзменение статусов заказов, обновление пользовательских тегов, синхронизация CDC
Модель Aggregate KeyЗначения столбцов Value для одинакового Key объединяются функцией агрегации (SUM/MAX/MIN/REPLACE)Обновление через загрузку данных в соответствии с семантикой агрегации; DELETE поддерживает только условия по столбцам KeyОтчёты в реальном времени, подсчёт кликов и другие сценарии агрегации
Модель Duplicate KeyЗапись только с добавлением данных, без дедупликации и агрегацииПоддерживается только DELETEЖурналы, отслеживание поведения и другие сценарии, в которых данные только добавляются

Вывод для выбора модели: если нужны обновления на уровне строк или частичные обновления столбцов, выбирайте модель Unique Key.

1.2 Выбор способа обновления​

Модель Unique Key поддерживает два способа обновления. Выбор зависит от объёма данных и частоты операций:

СпособПодходящие сценарииРекомендуемый метод записи
Обновление при загрузке данных (UPSERT)Частые обновления большими пакетами; синхронизация CDC; формирование широких таблиц из нескольких источниковStream Load, Routine Load, Broker Load, INSERT INTO
Обновление с помощью DML (UPDATE)Нечастые пакетные обновления; обновление данных по условию; обновления с использованием связанных таблицUPDATE, INSERT INTO ... SELECT ...

1.2.1 Обновление при загрузке данных (UPSERT)​

Все методы загрузки (Stream Load, Broker Load, Routine Load, INSERT INTO) по умолчанию обрабатывают данные в модели Unique Key с семантикой UPSERT:

  • Если первичный ключ уже существует, новая строка перезаписывает старую.
  • Если первичный ключ не существует, вставляется новая строка.

Upsert

Поведение обновлений при загрузке данных зависит от модели таблицы. Подробнее см.:

1.2.2 Обновление с помощью оператора UPDATE​

Doris поддерживает стандартный оператор SQL UPDATE, который позволяет обновлять данные в таблицах модели Unique Key по условиям WHERE, а также выполнять обновления с использованием связанных таблиц.

-- Simple update
UPDATE user_profiles SET age = age + 1 WHERE user_id = 1;

-- Cross-table associated update
UPDATE sales_records t1
SET t1.user_name = t2.name
FROM user_profiles t2
WHERE t1.user_id = t2.user_id;

При выполнении UPDATE сначала сканируются данные, соответствующие условиям, а затем обновлённые строки записываются обратно. Этот способ подходит для нечастых пакетных обновлений.

Примечание

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

Синтаксис, типичные примеры использования и ограничения оператора UPDATE описаны в разделе Обновление данных с помощью команды UPDATE.

1.2.3 Обновление с помощью INSERT INTO SELECT​

Поскольку модель Unique Key по умолчанию использует семантику UPSERT, с помощью INSERT INTO ... SELECT ... можно получить тот же эффект, что и при UPDATE. Этот способ подходит для пакетной записи данных из других таблиц.

1.3 Способы удаления данных​

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

Способ удаленияПоддерживаемые модели таблицОписание
Пометка на удаление при загрузке данныхМодель Unique KeyЗаписывается метка __DORIS_DELETE_SIGN__ = 1, а физическую очистку выполняет фоновая Compaction
Удаление с помощью DML (DELETE / TRUNCATE)Все моделиУдаление данных по условию или полная очистка таблицы/раздела

Полную информацию см. в разделе Удаление данных.

2. Механизм реализации модели Unique Key​

2.1 Merge-on-Write и Merge-on-Read​

У модели Unique Key есть две стратегии слияния данных. Начиная с Doris 2.1, по умолчанию используется Merge-on-Write.

АспектMerge-on-Write (MoW)Merge-on-Read (MoR, устаревший вариант)
Поведение при записиДедупликация и слияние выполняются при записи; в хранилище для каждого первичного ключа остаётся только одна, самая новая записьПри записи сохраняются несколько версий
Производительность запросовБлизка к производительности таблицы Duplicate Key без обновленийСлияние выполняется в реальном времени при запросах; время выполнения примерно в 3-10 раз больше, чем при MoW
Производительность записиЕсть накладные расходы на слияние; немного ниже, чем у MoR (примерно на 10-20% для небольших пакетов и на 30-50% для больших)Близка к производительности таблицы Duplicate Key
Потребление ресурсовЗапись и фоновая Compaction потребляют больше ресурсов CPU и памятиЗапросы потребляют больше ресурсов CPU и памяти
Подходящие сценарииПреобладание чтений при редких записях (рекомендуется)Преобладание записей при редких чтениях (больше не рекомендуется)

Новые таблицы по умолчанию используют MoW. Дополнительная настройка не требуется.

2.2 Столбец Sequence и данные, поступающие не по порядку​

В распределённой системе данные могут поступать не по порядку. Например, статус заказа последовательно меняется на «Оплачен» и «Отправлен», но из-за сетевой задержки сообщение «Отправлен» может поступить в Doris раньше сообщения «Оплачен».

Механизм столбца Sequence решает эту проблему: при создании таблицы укажите столбец (обычно с временной меткой или номером версии) в качестве столбца Sequence. При записи данных с одним и тем же первичным ключом Doris всегда сохраняет строку с наибольшим значением Sequence.

CREATE TABLE order_status (
order_id BIGINT,
status_name STRING,
update_time DATETIME
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id)
PROPERTIES (
"function_column.sequence_col" = "update_time" -- Specify update_time as the Sequence column
);

-- 1. Write the "Shipped" record (larger update_time)
-- {"order_id": 1001, "status_name": "Shipped", "update_time": "2023-10-26 12:00:00"}

-- 2. Write the "Paid" record (smaller update_time, arrives later)
-- {"order_id": 1001, "status_name": "Paid", "update_time": "2023-10-26 11:00:00"}

-- Final result: the record with the largest update_time is retained
-- order_id: 1001, status_name: "Shipped", update_time: "2023-10-26 12:00:00"

Дополнительная информация:

2.3 Механизм работы метки удаления​

Для __DORIS_DELETE_SIGN__ используется подход «логическая пометка с фоновой очисткой», который включает три этапа:

  1. Выполнение удаления: при удалении данных через загрузку или оператор DELETE Doris не удаляет данные из физических файлов сразу. Вместо этого записывается новая запись, у которой __DORIS_DELETE_SIGN__ имеет значение 1.
  2. Фильтрация при запросе: при выполнении запросов Doris автоматически добавляет условие фильтрации WHERE __DORIS_DELETE_SIGN__ = 0, чтобы исключить из результатов строки, помеченные на удаление.
  3. Фоновая Compaction: когда процесс Compaction обнаруживает для первичного ключа и обычную запись, и запись с меткой удаления, при слиянии он физически удаляет обе записи, освобождая место в хранилище.

Метка удаления

2.4 Частичное обновление столбцов​

Начиная с версии 2.0, модель Unique Key (MoW) поддерживает частичное обновление столбцов: при загрузке достаточно передать первичный ключ и столбцы, которые нужно обновить. Столбцы, которые не были переданы, сохраняют исходные значения.

Как включить:

Метод загрузкиНастройка для включения
INSERT INTOУстановите переменную сеанса enable_unique_key_partial_update = true
Stream Load и другие методы загрузкиУстановите для параметра partial_columns значение true

При создании таблицы необходимо включить Merge-on-Write:

CREATE TABLE user_profiles (
user_id BIGINT,
name STRING,
age INT,
last_login DATETIME
)
UNIQUE KEY(user_id)
DISTRIBUTED BY HASH(user_id)
PROPERTIES (
"enable_unique_key_merge_on_write" = "true"
);

-- Initial data
-- user_id: 1, name: 'Alice', age: 30, last_login: '2023-10-01 10:00:00'

-- Partial update via Stream Load, writing only age and last_login
-- {"user_id": 1, "age": 31, "last_login": "2023-10-26 18:00:00"}

-- Data after update
-- user_id: 1, name: 'Alice', age: 31, last_login: '2023-10-26 18:00:00'

С точки зрения реализации частичное обновление столбцов в модели Unique Key не выполняется на месте. При загрузке считываются существующие столбцы, заполняются недостающие поля, а затем вся строка перезаписывается. Это приводит к увеличению объёма чтения и записи: например, при обновлении 10 полей широкой таблицы из 100 столбцов с полями примерно одинакового размера обновление с полезным объёмом 1 MB вызывает чтение примерно 9 MB данных и запись 10 MB данных.

Рекомендации по производительности:

РекомендацияОписание
Используйте SSDЧастичное обновление столбцов создаёт большое количество случайных операций IO. На механических дисках это становится серьёзным узким местом, поэтому рекомендуется использовать SSD (предпочтительно NVMe)
Включите строковое хранение для широких таблицДля очень широких таблиц рекомендуется включить строковое хранение, чтобы за одну операцию IO можно было прочитать всю строку. При столбцовом хранении для каждого недостающего поля требуется отдельная операция IO

Полные инструкции по использованию (Stream Load, INSERT INTO, Flink Connector и т. д.) см. в разделе Обновление столбцов.

3. Типичные бизнес-сценарии​

3.1 Синхронизация CDC в реальном времени​

Такие инструменты, как Flink CDC, отслеживают Binlog исходных баз данных (MySQL, PostgreSQL, Oracle и др.) и записывают его в таблицы Doris с моделью Unique Key.

Flink CDC

Ключевые возможности:

  • Синхронизация всей базы данных: Flink Doris Connector включает Flink CDC, обеспечивая сквозную синхронизацию всей базы данных без ручного создания таблиц или сопоставления полей.
  • Гарантия согласованности: следующие возможности используются совместно, чтобы данные соответствовали состоянию исходной базы данных:
    • UPSERT в модели Unique Key отвечает за обработку INSERT / UPDATE.
    • __DORIS_DELETE_SIGN__ отвечает за обработку DELETE.
    • Столбец Sequence (например, с временной меткой Binlog) позволяет обрабатывать данные, поступающие не по порядку.

3.2 Формирование широких таблиц в реальном времени​

Частичное обновление столбцов позволяет формировать широкие таблицы из нескольких источников непосредственно в Doris, не выполняя соединения в реальном времени во Flink:

  1. Создайте широкую таблицу с моделью Unique Key.
  2. Разные источники данных (основная информация, журналы поведения, данные транзакций и т. д.) записывают в неё данные в реальном времени через Stream Load / Routine Load.
  3. Каждый поток данных записывает только те столбцы, за которые отвечает, например:
    • Поток пользовательского поведения обновляет page_view_count и last_login_time.
    • Поток транзакций обновляет total_orders и total_amount.

Каждый поток записывает только изменённые столбцы, что снижает накладные расходы на IO и позволяет избежать затрат ресурсов на соединения в реальном времени. Об управлении версиями при одновременной работе нескольких потоков см. Многопоточные обновления в модели Unique Key.

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

4.1 Общие рекомендации​

№РекомендацияОписание
1Отдавайте предпочтение обновлениям при загрузке данныхДля частых обновлений большого объёма данных предпочтительнее использовать Stream Load и Routine Load вместо DML-операции UPDATE
2Записывайте данные пакетамиИзбегайте частых операций INSERT, записывающих по одной строке (> 100 TPS), поскольку каждый INSERT создаёт накладные расходы на транзакцию. Можно включить Group Commit для объединения фиксаций небольших пакетов
3Осторожно используйте частые операции DELETE в моделях Duplicate/AggregateНакопление предикатов влияет на производительность последующих запросов
4Используйте TRUNCATE PARTITION для удаления целого разделаПри удалении целого раздела TRUNCATE PARTITION значительно эффективнее, чем DELETE
5Выполняйте UPDATE последовательноИзбегайте параллельного выполнения задач UPDATE, которые могут затрагивать один и тот же первичный ключ

4.2 Модель Unique Key в архитектуре с разделением вычислений и хранения​

В Doris 3.0 появилась архитектура с разделением вычислений и хранения. В этой архитектуре BE не хранит состояние, а Merge-on-Write должен поддерживать глобальное состояние через Meta Service, чтобы разрешать конфликты записи между загрузкой данных, Compaction и Schema Change. MoW модели Unique Key использует распределённую блокировку таблицы на основе Meta Service для обеспечения согласованности записи.

Распределённая блокировка

Частая загрузка данных и Compaction могут приводить к конкуренции за блокировку таблицы. При использовании этой архитектуры рекомендуется:

  1. Контролируйте частоту загрузки в отдельную таблицу: рекомендуется загружать данные в отдельную таблицу Unique Key не чаще 60 раз в секунду. Снизить частоту можно за счёт пакетирования или настройки параллелизма.
  2. Разумно выбирайте разделы и бакеты:
    • Разделы: используйте разбиение по времени (по дням или часам), чтобы при каждой загрузке обновлялось лишь небольшое количество разделов.
    • Бакеты: количество бакетов (количество Tablets) должно соответствовать объёму данных и обычно составлять от 8 до 64. Слишком большое количество Tablets усиливает конкуренцию за блокировки.
  3. Настройте стратегию Compaction: при высокой нагрузке на запись снизьте частоту Compaction, чтобы уменьшить конфликты блокировок с задачами загрузки.
  4. Используйте актуальную версию: в версии 3.1 реализация распределённой блокировки таблицы была значительно оптимизирована. Рекомендуется использовать последнюю стабильную версию.