DuckDB再次修改游戏规则,DuckLake 支持实时入湖
DuckLake 改变数据入湖游戏规则: 实时入湖
今天看到一篇 DuckDB 的文章, 介绍通过 Data Inlining 的能力实现数据实时入湖.
https://ducklake.select/2026/04/02/data-inlining-in-ducklake/
Data Inlining 本质是:用数据库替代小文件,让 Lakehouse 第一次具备“低延迟写能力”。
玩法:
-- Global: change the default for all tables
SET ducklake_default_data_inlining_row_limit = 50;
-- Per-table: override for a specific table
ALTER TABLE lake.readings SET (data_inlining_row_limit = 100);
-- Disable inlining entirely
SET ducklake_default_data_inlining_row_limit = 0;
ATTACH 'ducklake:sensors.ducklake' AS lake (DATA_PATH 'sensor_data/');
CREATE TABLE lake.readings (
sensor_id INTEGER,
temperature DOUBLE,
ts TIMESTAMP
);
INSERT INTO lake.readings VALUES (1, 21.5, '2025-03-27 10:00:00');
INSERT INTO lake.readings VALUES (2, 22.1, '2025-03-27 10:00:10');
INSERT INTO lake.readings VALUES (1, 21.8, '2025-03-27 10:00:20');
None of these inserts created a Parquet file.
Instead, all three rows live in the catalog database
in an inlined data table named ducklake_inlined_data_table-id_schema-version.
If we peek inside the catalog:
ATTACH 'sensors.ducklake' AS catalog_db;
SELECT * FROM catalog_db.ducklake_inlined_data_1_1;
┌────────┬────────────────┬──────────────┬───────────┬─────────────┬─────────────────────┐
│ row_id │ begin_snapshot │ end_snapshot │ sensor_id │ temperature │ ts │
│ int64 │ int64 │ int64 │ int32 │ double │ timestamp │
├────────┼────────────────┼──────────────┼───────────┼─────────────┼─────────────────────┤
│ 0 │ 2 │ NULL │ 1 │ 21.5 │ 2025-03-27 10:00:00 │
│ 1 │ 3 │ NULL │ 2 │ 22.1 │ 2025-03-27 10:00:10 │
│ 2 │ 4 │ NULL │ 1 │ 21.8 │ 2025-03-27 10:00:20 │
└────────┴────────────────┴──────────────┴───────────┴─────────────┴─────────────────────┘
If a delete targets a row that is still inlined,
DuckLake handles it in place by setting the
end_snapshot column on that row.
No deletion file is created. For example:
DELETE FROM lake.readings WHERE sensor_id = 2;
┌────────┬────────────────┬──────────────┬───────────┬─────────────┬─────────────────────┐
│ row_id │ begin_snapshot │ end_snapshot │ sensor_id │ temperature │ ts │
│ int64 │ int64 │ int64 │ int32 │ double │ timestamp │
├────────┼────────────────┼──────────────┼───────────┼─────────────┼─────────────────────┤
│ 0 │ 2 │ NULL │ 1 │ 21.5 │ 2025-03-27 10:00:00 │
│ 1 │ 3 │ 5 │ 2 │ 22.1 │ 2025-03-27 10:00:10 │
│ 2 │ 4 │ NULL │ 1 │ 21.8 │ 2025-03-27 10:00:20 │
└────────┴────────────────┴──────────────┴───────────┴─────────────┴─────────────────────┘
1. 什么是 Data Inlining
核心思想:
不再为“小数据变更”写 Parquet 文件,而是直接写入元数据数据库。
传统流程是:
写数据 → 生成 Parquet 文件 → 在元数据中登记文件
而 DuckLake 改成:
小数据 → 直接写入 metadata 表(inline)
大数据 → 写 Parquet
👉 本质:把“小数据路径”从“文件系统”改为“数据库”
2. 为什么需要这个机制?
传统 Lakehouse(Iceberg / Delta)的问题:
插入1行数据 → 也要写一个文件
导致:
大量小文件(small file problem) 元数据膨胀 频繁 compaction S3 / OSS round-trip 成本高
👉 结论:
小变更 = 极其低效的 IO 模型
3. DuckLake 的解决方案
✅ 小变更:直接 inline 到 metadata
insert / delete 少量行 → 写 metadata 表 不生成文件
✅ 大批量:正常写 Parquet
达到阈值后再 flush
👉 等价于:
metadata = write buffer(写缓存)
4. 数据是否可查询?
可以,而且是实时可见
inline 数据 + Parquet 数据统一查询 对用户透明
👉 本质:
metadata 表 ≈ 一个“实时增量层”
5. 支持的操作
小规模 INSERT → inline table 小规模 DELETE → inline delete table
6. 触发条件(关键参数)
data_inlining_row_limit = 10(默认)
小于这个行数 → inline 大于 → 写文件
可以:
全局配置 connection 配置 table级配置
7. 后续处理(关键机制)
inline 数据不会一直留在 metadata:
👉 会被:
积累 → 合并 → flush 成 Parquet 文件
设计哲学
1. 本质:把 Lakehouse 的写路径“分层”
传统:
写入 = 文件系统(统一路径)
DuckLake:
写入 = 双路径
小数据 → DB(低延迟)
大数据 → 文件(高吞吐)
👉 这是典型的:
冷热写路径分离(Hot/Cold write path)
2. 本质:把 metadata 升级成“数据层”
传统认知:
metadata = 辅助信息
DuckLake:
metadata = 小数据存储层
👉 这一步非常关键:
数据湖第一次把“数据库”重新拉回核心路径
3. 本质:解决 Lakehouse 三大痛点
痛点1:小文件爆炸
解决:
→ 不写小文件
痛点2:高延迟写入
传统:
写文件 → 更新 metadata → 可见
DuckLake:
写 DB → 立即可见
痛点3:高并发写冲突
传统:
文件级锁 manifest 冲突
DuckLake:
用数据库事务解决
👉 本质:
用 RDBMS 替代 object storage 的并发控制
4. 本质:Lakehouse 向 OLTP 借脑子
这其实是一个很深的趋势:
👉 结论:
DuckLake = Lakehouse + OLTP 思维融合
5. 一个更高级的理解(你应该关心的)
这不是优化,而是范式变化:
旧范式(Iceberg / Delta)
“一切都是文件”
新范式(DuckLake)
“文件 + 数据库协同”
关键判断
1. 这是 Lakehouse 方向上最重要的创新之一
因为它解决的是:
写路径,而不是读路径
而历史上:
Parquet → 优化读 向量化 → 优化读 索引 → 优化读
👉 写路径一直是短板
2. 它的代价也很明确
不是没有 tradeoff:
metadata DB 成为瓶颈 内存 / catalog 膨胀 flush 策略不可控(目前) 生态还不成熟
3. 它真正适合的场景
非常明确:
✅ 高频小写入(stream / CDC)
✅ 实时分析
✅ feature store
✅ AI 数据流水线
不适合:
❌ 纯离线批处理
❌ 超大规模 append-only(直接写 Parquet 更简单)
一句话总结
Data Inlining 本质是:用数据库替代小文件,让 Lakehouse 第一次具备“低延迟写能力”。