|
Professor Seleznov
|
-Сегодня поговорим про Iceberg V3 и Apache Doris 4.1. Но не в формате «у нас теперь есть поддержка новой версии формата, хлопаем в ладоши». Гораздо интереснее другой вопрос: что меняется, когда SQL-движок умеет не только читать Iceberg-таблицу, но и делать маленькие исправления, reconciliation, maintenance и диагностику без отдельного Spark-кластера на каждое телодвижение? Спойлер: Spark никто не отменял. Flink тоже. Но есть целый класс ежедневной работы, где переключение движка дороже самой операции. Что вы узнаете из этой статьи
- UPDATE на Iceberg без Spark job. Doris 4.1 делает UPDATE, DELETE, MERGE INTO на Iceberg-таблицах из того же SQL-клиента, где вы уже нашли проблему. Цикл «query → fix → verify» сжимается с 14 часов до минут.
- Deletion Vectors вместо Position Delete files. В Iceberg V3 DML больше не копит отдельные parquet delete files при каждом commit. Один Puffin bitmap вместо 320 файлов. Query latency перестаёт деградировать с ростом delete ratio (бенчмарк: 2–3x ускорение).
- Row Lineage как CDC watermark. _last_updated_sequence_number двигается только при реальном DML, а не при compaction. Downstream больше не переобрабатывает строки после rewrite_data_files. Один integer watermark вместо snapshot diff.
- Doris не заменяет Spark. Heavy ETL, backfills и streaming ingestion остаются за Spark/Flink. Doris забирает adjacent workflow: small DML, incremental reconciliation, maintenance и диагностику.
Хотите сразу попробовать? Переходите в Часть 8: Quick Start там путь от нуля до V3-таблицы за пять минут. - Часть 1: 3 часа ночи, одна строка сломана Представим конкретную ситуацию. Data engineer в e-commerce компании сидит в Doris и разбирает Iceberg-таблицу с заказами. Видит, что вчерашний batch из ERP проставил status = 'cancelled' для 200 заказов, которые на самом деле были оплачены — upstream-система отправила кривой snapshot. Запрос подтверждает: вот они, 200 строк с неверным статусом. Исправление - банальный WHERE order_id IN (...) и SET status = 'paid'. В идеальном мире это выглядит так:
UPDATE orders_iceberg SET status = 'paid' WHERE order_id IN (SELECT order_id FROM bad_batch_ids);
Что происходит дальше в реальном мире — красиво описано в оригинальной статье Mingyu Chen. Инженер закрывает SQL-клиент и начинает другой рабочий процесс:
- Пишет Spark job.
- Подстраивает scheduler.
- Открывает PR.
- Ждёт review.
- Чаще всего — передаёт задачу платформенной команде, потому что у него нет прямого доступа к write-кластеру.
- Утром возвращается в Doris и проверяет, что всё отработало.
Полный цикл — 14 часов. Код по смыслу — один UPDATE. Есть и менее драматичный, но более частый сценарий. CDC-поток пишет в Iceberg, small files и delete files копятся, запросы постепенно деградируют. Все понимают, что нужен rewrite_data_files. В командах с self-service инфраструктурой инженер запустит compaction сам. Но во многих средних и крупных организациях write-доступ к Iceberg-таблицам живёт у выделенной platform team — и тогда задача, которая по сути один SQL-вызов, превращается в ticket, maintenance window и ожидание. Именно этот организационный паттерн описывает автор оригинальной статьи, и он встречается чаще, чем хотелось бы. Iceberg решил огромную часть проблемы: он сделал таблицу открытым transactional-форматом поверх файлов в object storage. Но работа с этой таблицей часто остаётся не такой уж открытой:
- читаем в одном движке;
- пишем в другом;
- compaction и maintenance делаем через третий;
- CDC и streaming ingestion живут отдельно.
Получается два налога на каждое маленькое действие: switch-engine tax и cross-team tax. Apache Doris 4.1 пытается уменьшить оба. - Часть 2: Где Doris находится в Iceberg-экосистеме Важно сразу снять лишнее ожидание: Doris не пытается заменить Spark во всех задачах. Apache Doris — это MPP SQL engine, который начинал как data warehouse, а за последние два мажорных релиза сместил центр тяжести в сторону lakehouse workloads. Spark при этом остаётся нормальным инструментом для cross-source backfills, тяжёлого ETL, больших batch-job’ов и широкой batch/streaming-экосистемы. Flink остаётся естественным выбором для streaming ingestion и continuous CDC write paths. Роль Doris в этом контексте узкая и конкретная: real-time query layer для Iceberg, который постепенно забирает соседний workflow:
- вы уже пришли в SQL-клиент с запросом;
- увидели проблему или расхождение;
- хотите сделать небольшое исправление;
- хотите запустить incremental reconciliation;
- хотите выполнить maintenance или диагностику;
- не хотите ради этого прыгать в другой кластер.
В Doris 4.1 матрица Iceberg-поддержки выглядит довольно широко:
| Зона |
Что поддерживается |
| Read |
V1/V2/V3, time travel, branch/tag, views, system tables, Position/Equality/DV delete |
| Write |
INSERT, OVERWRITE, CTAS, INSERT INTO BRANCH, DELETE, UPDATE, MERGE INTO |
| DDL |
create/drop table, schema change, partition evolution, branch/tag management |
| Maintain |
rewrite_data_files, expire_snapshots, rewrite_manifests, rollback, fast_forward |
| Diagnose |
data file distribution, dangling delete |

Apache Doris 4.1 & Iceberg V3 Lakehouse Lifecycle Архитектура: один SQL-движок для Read, Write, DDL, Maintenance и Diagnostics на Iceberg V3 таблицах. Источник: оригинальная статья Mingyu Chen. Но в этой статье нас интересует не вся матрица. Фокус на двух вещах:
- DML completeness: UPDATE, DELETE, MERGE INTO прямо из SQL-клиента.
- Iceberg V3 mechanics: Deletion Vectors и Row Lineage, без которых DML быстро начинает копить технический долг.
- Часть 3: DML возвращается в query layer Начнём с простого. Исправить одну строку:
UPDATE iceberg_tbl SET name = 'Alice-fixed' WHERE id = 1;
Откатить плохой batch:
DELETE FROM iceberg_tbl WHERE dt = '2026-04-01' AND source = 'bad_pipeline';
Сделать upsert по incremental batch:
MERGE INTO iceberg_tbl t USING ( SELECT 1 AS id, 'Alice_new' AS name, 26 AS age, 'U' AS flag UNION ALL SELECT 2, 'Bob', 30, 'D' UNION ALL SELECT 4, 'Dora', 28, 'I' ) s ON t.id = s.id WHEN MATCHED AND s.flag = 'D' THEN DELETE WHEN MATCHED THEN UPDATE SET name = s.name, age = s.age WHEN NOT MATCHED THEN INSERT (id, name, age) VALUES (s.id, s.name, s.age);
MERGE INTO здесь самая важная операция. Именно на ней держатся типичные CDC/upsert-сценарии:
- изменения из PostgreSQL или MySQL прилетают через Flink CDC или похожий инструмент;
- downstream Iceberg-таблица должна принять inserts, updates и deletes вместе;
- incremental materialized views должны обновлять wide tables по change key.
Без MERGE INTO вы либо пересобираете данные целиком, либо уносите логику в Spark/Flink и вручную обслуживаете отдельный pipeline. В Doris 4.1 MERGE INTO поддерживает partitioned targets, subqueries как source и expressions в UPDATE-части, например age = age * 2 + 1. Но caveat сразу: target table должен быть format-version >= 2, а сам MERGE INTO в оригинальной статье помечен как experimental. Это не «сразу катим в прод в пятницу вечером», а «делаем POC на своём workload». - Часть 4: Почему DML без V3 быстро копит долги Может показаться, что раз Doris теперь умеет UPDATE, DELETE, MERGE INTO на Iceberg — задача решена. Не совсем. Наличие DML — это ещё не хороший DML. В Iceberg V2 каждая такая операция создаёт Position Delete file. Это отдельный parquet-файл, в котором записано: «вот эти позиции из data file нужно считать удалёнными». Чтобы вернуть корректный результат, reader вынужден выполнять anti-join: прочитать data files, прочитать все связанные delete files, отфильтровать помеченные строки. Один delete file — ничего страшного. Десять — терпимо. Сотни и тысячи маленьких DML commits в CDC-таблице — уже неприятно. Проблема растёт линейно:
- каждый DML commit добавляет новые delete files;
- каждый последующий query вынужден открывать и объединять все релевантные delete files;
- периодически нужен rewrite_data_files, чтобы вернуть таблицу в нормальное состояние;
- а значит, снова maintenance job, scheduler и платформа — тот самый Jira-ticket из начала статьи.
Это первый долг: performance debt. DML вроде есть, но каждый commit медленно ухудшает чтение. Есть второй долг: observability debt. После того как commit произошёл, downstream-системы больше не знают, когда конкретная строка была последний раз изменена. Они полагаются на snapshot diff. Но compaction и rewrite_data_files тоже создают новые snapshots, хотя данные логически не менялись. В результате downstream pipeline видит физический rewrite и интерпретирует его как новые данные — и начинает переобрабатывать строки, которых никто не трогал. Если коротко:
DML без V3 быстро превращается в два долга: performance debt и observability debt.
Iceberg V3 отвечает на них двумя механизмами:
- Deletion Vectors — чтобы DML не раздувал delete files.
- Row Lineage — чтобы row-level changes были наблюдаемыми.
- Часть 5: Deletion Vectors — меньше delete files, меньше anti-join Deletion Vector — это bitmap, который хранит, какие строки в data file считаются удалёнными. В Iceberg V3 он хранится в Puffin file format. Контраст с V2 такой:
- V2: каждый DML commit создаёт отдельный Position Delete parquet.
- V3: все пометки на удаление для одного data file схлопываются в один Puffin Deletion Vector.
- V2 reader: читает data file, потом anti-join со всеми связанными delete files.
- V3 reader: читает data file + DV и применяет bitmap за один проход. Anti-join исчезает.

Iceberg V2 Position Deletes vs V3 Deletion Vector V2 копит Position Delete parquet-файлы при каждом DML commit. V3 схлопывает все пометки в один Puffin Deletion Vector. Источник: оригинальная статья Mingyu Chen. Мини-пример V2:
CREATE TABLE orders_v2 ( id INT, status STRING, amount DECIMAL(10,2) ) PROPERTIES ('format-version' = '2'); INSERT INTO orders_v2 VALUES (1, 'pending', 100), (2, 'pending', 200), (3, 'pending', 300); UPDATE orders_v2 SET status = 'shipped' WHERE id = 1; UPDATE orders_v2 SET status = 'shipped' WHERE id = 2; DELETE FROM orders_v2 WHERE id = 3;
После трёх DML commits в V2 появляются три Position Delete files. Та же логика на V3:
CREATE TABLE orders_v3 ( id INT, status STRING, amount DECIMAL(10,2) ) PROPERTIES ('format-version' = '3'); INSERT INTO orders_v3 VALUES (1, 'pending', 100), (2, 'pending', 200), (3, 'pending', 300); UPDATE orders_v3 SET status = 'shipped' WHERE id = 1; UPDATE orders_v3 SET status = 'shipped' WHERE id = 2; DELETE FROM orders_v3 WHERE id = 3;
Теперь вместо набора parquet delete files рядом с data file лежит Puffin Deletion Vector. SQL на поверхности тот же, физическая механика другая. Проверить это можно через system table:
SELECT content, file_path, record_count FROM orders_v3$files;
В нормальном V3-сценарии вы ожидаете увидеть data file и .puffin DV, а не растущий список ...delete.parquet. Что дают числа В оригинальной статье приведён Doris-side benchmark на нескольких сценариях. Самое важное:
| Сценарий |
Iceberg V2: Position Deletes |
Iceberg V3: Deletion Vector |
| 16 data files, 20% deleted |
336 files to open: 16 data + 320 delete |
17 files: 16 data + 1 Puffin |
| 100M rows, 99% deleted |
98 MiB delete storage |
3.8 MiB DV storage |
| Delete metadata reduction |
— |
~96% |
Latency на 16 data files и 1M rows:
| Delete % |
Doris V2 |
Doris V3 |
Speedup |
| 5% |
0.31s |
0.15s |
2.1x |
| 10% |
0.35s |
0.16s |
2.2x |
| 20% |
0.43s |
0.17s |
2.5x |
| 30% |
0.46s |
0.14s |
3.3x |
| 40% |
0.39s |
0.17s |
2.3x |
Для large file с 99% deleted:
| Table version |
Doris Q1 |
Doris Q2 |
| V2, Position Delete |
3.42s |
3.28s |
| V3, Deletion Vector |
1.03s |
0.86s |
| Speedup |
~3x |
~3x |

Doris on Iceberg V3 Deletion Vector performance Doris V3 vs V2: latency остаётся плоской при росте delete ratio, в то время как V2 деградирует линейно. Источник: оригинальная статья Mingyu Chen. Смысл не в конкретном множителе «всегда 3x». Паттерн другой: под V2 anti-join cost растёт вместе с числом delete files, и query latency деградирует по мере роста delete ratio. Под V3 bitmap применяется за один проход, и latency остаётся практически плоской независимо от того, сколько строк помечено на удаление. Что именно Doris реализует для Deletion Vectors Важный нюанс из оригинала: чтобы Deletion Vectors приносили пользу, движок должен уметь и читать, и писать DV. Read-only движок может потреблять DV, записанные кем-то другим, но сам их не создаёт. Write-only движок создаёт DV, которые никто не прочитает. Doris 4.1 поддерживает обе стороны:
- Read: Puffin-format Deletion Vectors читаются без дополнительной настройки. V3-таблицы queryable сразу.
- Write: DELETE, UPDATE, MERGE INTO на V3-таблице автоматически создают Puffin DV вместо Position Delete files. Пользователю достаточно указать format-version = 3 при создании таблицы — SQL-синтаксис не меняется.
Caveats по Deletion Vectors Три практических ограничения:
- DELETE, UPDATE, MERGE INTO требуют format-version >= 2.
- Deletion Vectors появляются только при format-version = 3.
- Concurrent writes используют Iceberg optimistic concurrency control, так что конфликты будут всплывать как transaction exceptions. Для high-conflict workloads нужны retry или сериализация.
- Часть 6: Row Lineage — watermark для CDC без snapshot diff Deletion Vectors отвечают на performance debt. Теперь про observability debt. В Iceberg V1/V2 change tracking в основном живёт на уровне snapshot. Это нормальная модель для многих задач, но у неё есть неприятный эффект: физический rewrite может выглядеть как логическое изменение. Например:
- downstream-система подписана на изменения Iceberg-таблицы;
- она сравнивает snapshots;
- между checkpoint’ами прошёл rewrite_data_files;
- физические файлы новые, snapshot новый;
- downstream не знает, изменились строки логически или просто переехали между файлами.
И начинает переобрабатывать лишнее. Iceberg V3 добавляет Row Lineage: две скрытые системные колонки для каждой строки.

Iceberg V3 Row Lineage hidden columns Row Lineage:_row_idдаёт стабильную идентичность строки,_last_updated_sequence_number— watermark для CDC. Источник: оригинальная статья Mingyu Chen.
| Колонка |
Что означает |
| _row_id |
стабильный numeric identifier строки |
| _last_updated_sequence_number |
sequence number последнего логического изменения строки |
Обе колонки поддерживаются системой. Пользователь не записывает их руками. Самая важная часть: _last_updated_sequence_number меняется при настоящем UPDATE или MERGE INTO, но не меняется при compaction и physical rewrite. Значит, его можно использовать как CDC watermark. Пример:
CREATE TABLE users_v3 ( id INT, name STRING, email STRING ) PROPERTIES ('format-version' = '3'); SET show_hidden_columns = true; INSERT INTO users_v3 VALUES (1, 'Alice', 'alice@x.com'), (2, 'Bob', 'bob@x.com'), (3, 'Carol', 'carol@x.com'); SELECT id, name, email, _row_id, _last_updated_sequence_number FROM users_v3;
После первого insert все три строки получают стабильные _row_id, а _last_updated_sequence_number равен 1. Дальше меняем Bob:
UPDATE users_v3 SET email = 'bob@newmail.com' WHERE id = 2;
У Bob _row_id остаётся тем же, но _last_updated_sequence_number становится 2. Alice и Carol остаются с SN = 1. Добавляем Dora:
INSERT INTO users_v3 VALUES (4, 'Dora', 'dora@x.com');
Dora получает новый _row_id и SN = 3. Теперь downstream, который синхронизирован по watermark 1, может запросить только реальные изменения:
SELECT id, name, email, _last_updated_sequence_number FROM users_v3 WHERE _last_updated_sequence_number > 1;
Вернутся Bob и Dora. Alice и Carol не попадут в pipeline. Если между checkpoint’ами случится compaction, они всё равно не попадут, потому что physical rewrite не двигает _last_updated_sequence_number. Это и есть главный выигрыш: downstream хранит один integer watermark, а не пытается угадывать смысл snapshot diff. Как меняется CDC-pipeline Контраст в архитектуре: V2 (snapshot diff): Upstream (PostgreSQL и т.д.) → Flink CDC → Iceberg V2 Sink → Downstream делает snapshot diff, но не может отличить реальное изменение от compaction/rewrite → false positives → переобработка. V3 (Row Lineage): Upstream → Flink CDC → Iceberg V3 Sink → Downstream делает WHERE _last_updated_sequence_number > :watermark → только реальные изменения → без false positives. Разница не только в точности, но и в простоте: вместо инфраструктуры для snapshot diffing — один SQL-запрос с одним integer watermark. Что Doris реализует для Row Lineage В Doris скрытые колонки можно читать явно или включить их отображение:
SET show_hidden_columns = true;
UPDATE и MERGE INTO на V3-таблицах автоматически обновляют _last_updated_sequence_number. Пользователь не добавляет отдельный audit trigger, не пишет отдельную таблицу lineage, не синхронизирует внешний log. Но caveat снова важный: Row Lineage в оригинале помечен как experimental. Проверять на своём workload обязательно. - Часть 7: Audit trail через _row_id Ещё один полезный сценарий — аудит. Финансовый аудитор спрашивает: «Order 102 менялся три раза. Какие суммы были на каждом шаге?» В V2 обычно приходится идти во внешнюю audit log, потом пытаться совместить её с текущим состоянием таблицы, потом учитывать compaction, file rewrite и прочие радости жизни. Это возможно, но хрупко: audit system и table state живут в разных местах. В V3 появляется более удобная опора: _row_id остаётся lifetime identity строки. Условно:
| Snapshot SN |
Amount |
Event |
| SN=1 |
80.00 |
Order created |
| SN=2 |
90.00 |
Customer complaint, partial refund |
| SN=3 |
100.00 |
Final settlement |
Сама Row Lineage не заменяет time travel и не хранит полную историю «магически». Важная деталь именно в связке:
- _row_id даёт стабильный ключ строки;
- snapshots/time travel дают возможность смотреть прошлые состояния;
- _last_updated_sequence_number показывает логическую хронологию изменений;
- compaction не ломает эту идентичность.
Примерный запрос для восстановления состояния:
SELECT order_id, amount FROM orders_v3 FOR VERSION AS OF WHERE _row_id = 1;
Да, вам всё ещё нужны snapshots. Но _row_id и _last_updated_sequence_number — это логические свойства строки, а не физические. Если между шагами прошёл ALTER TABLE orders_v3 EXECUTE rewrite_data_files(), физические файлы будут новые, а _row_id останется прежним и SN не изменится. Под V2 тот же compaction создал бы новый snapshot, и без внешней audit log вы бы не знали, менялись строки логически или нет. - Часть 8: Quick Start Если хочется быстро потрогать механику руками, минимальный путь такой. Prerequisites Нужны:
- Apache Doris 4.1.0 или новее (скачать или docker pull apache/doris:4.1.0).
- Iceberg catalog с поддержкой V3.
- Object store, доступный Doris BE: S3, MinIO, OSS или HDFS.
По catalog’ам в оригинале рекомендация такая:
- REST Catalog — наиболее надёжный путь для V3. Например, Apache Polaris, Lakekeeper или Tabular open-source REST catalog image.
- Hive Metastore-backed catalogs подходят для V1/V2 reads, но отстают по V3.
- AWS Glue и Aliyun DLF на момент оригинальной статьи указаны как read-only.
1. Подключить catalog
CREATE CATALOG iceberg_v3 PROPERTIES ( 'type' = 'iceberg', 'iceberg.catalog.type' = 'rest', 'uri' = 'http://your-rest-catalog:8181', 'warehouse' = 's3://your-bucket/warehouse', 's3.endpoint' = 'https://s3.us-west-2.amazonaws.com', 's3.access_key' = '', 's3.secret_key' = '', 's3.region' = 'us-west-2' ); SWITCH iceberg_v3; CREATE DATABASE IF NOT EXISTS demo; USE demo;
2. Создать V3-таблицу и сделать DML
CREATE TABLE orders ( id INT, status STRING, amount DECIMAL(10,2) ) PROPERTIES ('format-version' = '3'); INSERT INTO orders VALUES (1, 'pending', 100), (2, 'pending', 200), (3, 'pending', 300); UPDATE orders SET status = 'shipped' WHERE id = 1; DELETE FROM orders WHERE id = 3;
3. Проверить V3-поведение Проверка Deletion Vector:
SELECT content, file_path, record_count FROM orders$files;
Ожидаем .puffin DV рядом с data file, а не россыпь parquet delete files. Проверка Row Lineage (скрытые колонки по умолчанию не видны):
SET show_hidden_columns = true; SELECT id, status, _row_id, _last_updated_sequence_number FROM orders;
4. Попробовать MERGE INTO
MERGE INTO orders t USING (SELECT 1 AS id, 'delivered' AS status, 110 AS amount) s ON t.id = s.id WHEN MATCHED THEN UPDATE SET status = s.status, amount = s.amount WHEN NOT MATCHED THEN INSERT (id, status, amount) VALUES (s.id, s.status, s.amount);
Напоминание: MERGE INTO experimental. Это хороший кандидат для POC, но не для blind rollout в production. Если orders$files показывает один Puffin file рядом с data file, а выжившие строки несут корректные значения _row_id / _last_updated_sequence_number — ваш стек V3-ready end to end. Полный справочник по конфигурации: Doris Iceberg catalog docs. - Часть 9: Common gotchas Короткий список того, обо что легко удариться:
- format-version = 3 нужно задать при создании таблицы или мигрировать существующую V2-таблицу через ALTER TABLE ... SET PROPERTIES ('format-version' = '3').
- Hidden columns (_row_id, _last_updated_sequence_number) работают только на V3. На V1/V2 таблицах запрос к ним даст ошибку.
- Если MERGE INTO не парсится, проверьте Doris 4.1.0+ и target table V2/V3.
- DML требует format-version >= 2; Deletion Vectors появляются только на V3.
- Concurrent writers могут ловить optimistic concurrency conflicts. Для high-conflict workloads нужны retry, backoff или сериализация.
- REST Catalog behavior зависит от конкретной реализации. Для production лучше свериться с support matrix в Doris docs.
- AWS Glue и Aliyun DLF в оригинале указаны как read-only на момент статьи.
- Часть 10: Где граница Doris, Spark и Flink Самая опасная версия этой статьи звучала бы так: «Теперь Doris заменяет Spark для Iceberg». Это плохая версия. Не надо так. Более честная матрица:
| Инструмент |
Где уместен |
| Doris |
real-time queries, small DML, incremental reconciliation, row-level provenance, day-to-day maintenance, диагностика Iceberg tables из SQL |
| Spark |
heavy backfills, cross-source ETL, long-running batch jobs |
| Flink |
streaming ingestion, continuous CDC write paths |
Doris 4.1 не заменяет Spark. Он сокращает число случаев, когда Spark приходится запускать ради мелкой операции вокруг проблемы, которую вы уже нашли. Если запрос уже привёл вас в SQL-клиент — маленькое исправление не должно превращаться в distributed-computing ритуал с отдельным кластером. - Итог Одна фраза хорошо описывает направление Doris на Iceberg:
Если запрос уже привёл вас в SQL-клиент, маленькое исправление, incremental reconciliation или day-to-day maintenance не должны заставлять уходить в другой движок.
Что меняется в Apache Doris 4.1:
- UPDATE, DELETE, MERGE INTO закрывают loop «query → fix → verify» внутри одного SQL-клиента.
- Deletion Vectors в Iceberg V3 не дают DML накапливать performance debt через растущий набор Position Delete files.
- Row Lineage даёт _row_id и _last_updated_sequence_number, чтобы CDC и audit не ломались от compaction и physical rewrite.
- Maintenance и диагностика становятся ближе к человеку, который уже смотрит на данные.
Что не меняется:
- Spark остаётся для тяжёлых batch/backfill/ETL задач.
- Flink остаётся для streaming ingestion.
- MERGE INTO и Row Lineage в оригинале помечены как experimental.
- Production adoption требует POC на своём catalog, storage, concurrency pattern и workload.
Если коротко: Iceberg V3 делает DML архитектурно более здоровым, а Doris 4.1 пытается сделать этот DML доступным из того же SQL-движка, где вы уже нашли проблему. Для data engineer’а это не звучит как революция. Это звучит как минус один ticket, минус один job, минус один context switch. А иногда именно это и есть настоящая продуктивность. - Ссылки
-Оригинал по лицензии CC BY 4.0 © 2026 Mingyu Chen (Rayner).-Источник
|