|
| 1 | +--- |
| 2 | +title: Fuse Engine 的工作原理 |
| 3 | +--- |
| 4 | + |
| 5 | +## Fuse Engine |
| 6 | + |
| 7 | +Fuse Engine 是 Databend 的核心存储引擎,经过优化,可以高效地管理 **PB 级别** 的数据,这些数据存储在 **云对象存储** 上。默认情况下,在 Databend 中创建的表会自动使用此引擎 (`ENGINE=FUSE`)。受到 Git 的启发,其基于快照的设计实现了强大的数据版本控制(如时间回溯),并通过高级的剪枝和索引提供 **高查询性能**。 |
| 8 | + |
| 9 | +本文档解释了它的核心概念以及它的工作原理。 |
| 10 | + |
| 11 | +## 核心概念 |
| 12 | + |
| 13 | +Fuse Engine 使用三个核心结构来组织数据,与 Git 类似: |
| 14 | + |
| 15 | +* **快照(类似于 Git 提交):** 不可变的引用,通过指向特定的 Segment 来定义表在某个时间点的状态。支持时间回溯。 |
| 16 | +* **Segment(类似于 Git 树):** Block 的集合,包含用于快速数据跳过(剪枝)的摘要统计信息。可以在快照之间共享。 |
| 17 | +* **Block(类似于 Git Blob):** 不可变的数据文件(Parquet 格式),包含实际的行和详细的列级统计信息,用于细粒度的剪枝。 |
| 18 | + |
| 19 | +``` |
| 20 | + Table HEAD |
| 21 | + │ |
| 22 | + ▼ |
| 23 | + ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ |
| 24 | + │ SEGMENT A │◄────│ SNAPSHOT 2 │────►│ SEGMENT B │ |
| 25 | + │ │ │ Previous: │ │ │ |
| 26 | + └───────┬───────┘ │ SNAPSHOT 1 │ └───────┬───────┘ |
| 27 | + │ └───────────────┘ │ |
| 28 | + │ │ │ |
| 29 | + │ ▼ │ |
| 30 | + │ ┌───────────────┐ │ |
| 31 | + │ │ SNAPSHOT 1 │ │ |
| 32 | + │ │ │ │ |
| 33 | + │ └───────────────┘ │ |
| 34 | + │ │ |
| 35 | + ▼ ▼ |
| 36 | + ┌───────────────┐ ┌───────────────┐ |
| 37 | + │ BLOCK 1 │ │ BLOCK 2 │ |
| 38 | + │ (cloud.txt) │ │(warehouse.txt)│ |
| 39 | + └───────────────┘ └───────────────┘ |
| 40 | +``` |
| 41 | + |
| 42 | +## 写入工作原理 |
| 43 | + |
| 44 | +当你向表中添加数据时,Fuse Engine 会创建一个对象链。让我们逐步了解这个过程: |
| 45 | + |
| 46 | +### 步骤 1:创建表 |
| 47 | + |
| 48 | +```sql |
| 49 | +CREATE TABLE git(file VARCHAR, content VARCHAR); |
| 50 | +``` |
| 51 | + |
| 52 | +此时,表已存在,但不包含任何数据: |
| 53 | + |
| 54 | +``` |
| 55 | +(Empty table with no data) |
| 56 | +``` |
| 57 | + |
| 58 | +### 步骤 2:插入第一条数据 |
| 59 | + |
| 60 | +```sql |
| 61 | +INSERT INTO git VALUES('cloud.txt', '2022/05/06, Databend, Cloud'); |
| 62 | +``` |
| 63 | + |
| 64 | +在第一次插入后,Fuse Engine 会创建初始快照、segment 和 block: |
| 65 | + |
| 66 | +``` |
| 67 | + Table HEAD |
| 68 | + │ |
| 69 | + ▼ |
| 70 | + ┌───────────────┐ |
| 71 | + │ SNAPSHOT 1 │ |
| 72 | + │ │ |
| 73 | + └───────┬───────┘ |
| 74 | + │ |
| 75 | + ▼ |
| 76 | + ┌───────────────┐ |
| 77 | + │ SEGMENT A │ |
| 78 | + │ │ |
| 79 | + └───────┬───────┘ |
| 80 | + │ |
| 81 | + ▼ |
| 82 | + ┌───────────────┐ |
| 83 | + │ BLOCK 1 │ |
| 84 | + │ (cloud.txt) │ |
| 85 | + └───────────────┘ |
| 86 | +``` |
| 87 | + |
| 88 | +### 步骤 3:插入更多数据 |
| 89 | + |
| 90 | +```sql |
| 91 | +INSERT INTO git VALUES('warehouse.txt', '2022/05/07, Databend, Warehouse'); |
| 92 | +``` |
| 93 | + |
| 94 | +当我们插入更多数据时,Fuse Engine 会创建一个新的快照,该快照同时引用原始 segment 和新的 segment: |
| 95 | + |
| 96 | +``` |
| 97 | + Table HEAD |
| 98 | + │ |
| 99 | + ▼ |
| 100 | + ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ |
| 101 | + │ SEGMENT A │◄────│ SNAPSHOT 2 │────►│ SEGMENT B │ |
| 102 | + │ │ │ Previous: │ │ │ |
| 103 | + └───────┬───────┘ │ SNAPSHOT 1 │ └───────┬───────┘ |
| 104 | + │ └───────────────┘ │ |
| 105 | + │ │ │ |
| 106 | + │ ▼ │ |
| 107 | + │ ┌───────────────┐ │ |
| 108 | + │ │ SNAPSHOT 1 │ │ |
| 109 | + │ │ │ │ |
| 110 | + │ └───────────────┘ │ |
| 111 | + │ │ |
| 112 | + ▼ ▼ |
| 113 | + ┌───────────────┐ ┌───────────────┐ |
| 114 | + │ BLOCK 1 │ │ BLOCK 2 │ |
| 115 | + │ (cloud.txt) │ │(warehouse.txt)│ |
| 116 | + └───────────────┘ └───────────────┘ |
| 117 | +``` |
| 118 | + |
| 119 | +## 读取工作原理 |
| 120 | + |
| 121 | +当你查询数据时,Fuse Engine 使用智能剪枝来高效地查找你的数据: |
| 122 | + |
| 123 | +``` |
| 124 | +Query: SELECT * FROM git WHERE file = 'cloud.txt'; |
| 125 | +
|
| 126 | + Table HEAD |
| 127 | + │ |
| 128 | + ▼ |
| 129 | + ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ |
| 130 | + │ SEGMENT A │◄────│ SNAPSHOT 2 │────►│ SEGMENT B │ |
| 131 | + │ CHECK │ │ │ │ CHECK │ |
| 132 | + └───────┬───────┘ └───────────────┘ └───────┬───────┘ |
| 133 | + │ ✗ |
| 134 | + │ (Skip - doesn't contain |
| 135 | + │ 'cloud.txt') |
| 136 | + ▼ |
| 137 | + ┌───────────────┐ |
| 138 | + │ BLOCK 1 │ |
| 139 | + │ CHECK │ |
| 140 | + └───────┬───────┘ |
| 141 | + │ |
| 142 | + │ ✓ (Contains 'cloud.txt') |
| 143 | + ▼ |
| 144 | + Read this block |
| 145 | +``` |
| 146 | + |
| 147 | +### 智能剪枝过程 |
| 148 | + |
| 149 | +``` |
| 150 | +┌─────────────────────────────────────────┐ |
| 151 | +│ Query: WHERE file = 'cloud.txt' │ |
| 152 | +└─────────────────┬───────────────────────┘ |
| 153 | + │ |
| 154 | + ▼ |
| 155 | +┌─────────────────────────────────────────┐ |
| 156 | +│ Check SEGMENT A │ |
| 157 | +│ Min file value: 'cloud.txt' │ |
| 158 | +│ Max file value: 'cloud.txt' │ |
| 159 | +│ │ |
| 160 | +│ Result: ✓ Might contain 'cloud.txt' │ |
| 161 | +└─────────────────┬───────────────────────┘ |
| 162 | + │ |
| 163 | + ▼ |
| 164 | +┌─────────────────────────────────────────┐ |
| 165 | +│ Check SEGMENT B │ |
| 166 | +│ Min file value: 'warehouse.txt' │ |
| 167 | +│ Max file value: 'warehouse.txt' │ |
| 168 | +│ │ |
| 169 | +│ Result: ✗ Cannot contain 'cloud.txt' │ |
| 170 | +└─────────────────┬───────────────────────┘ |
| 171 | + │ |
| 172 | + ▼ |
| 173 | +┌─────────────────────────────────────────┐ |
| 174 | +│ Check BLOCK 1 in SEGMENT A │ |
| 175 | +│ Min file value: 'cloud.txt' │ |
| 176 | +│ Max file value: 'cloud.txt' │ |
| 177 | +│ │ |
| 178 | +│ Result: ✓ Contains 'cloud.txt' │ |
| 179 | +└─────────────────┬───────────────────────┘ |
| 180 | + │ |
| 181 | + ▼ |
| 182 | +┌─────────────────────────────────────────┐ |
| 183 | +│ Read only BLOCK 1 │ |
| 184 | +└─────────────────────────────────────────┘ |
| 185 | +``` |
| 186 | + |
| 187 | +## 基于快照的功能 |
| 188 | + |
| 189 | +Fuse Engine 的快照架构实现了强大的数据管理功能: |
| 190 | + |
| 191 | +### 时间回溯 |
| 192 | + |
| 193 | + |
| 194 | +查询任何时间点存在的数据。通过完整的审计跟踪和错误恢复,实现数据分支、标记和治理。 |
| 195 | + |
| 196 | +### 零拷贝 Schema 演进 |
| 197 | + |
| 198 | +修改表的结构(添加列、删除列、重命名、更改类型),**无需重写任何底层数据文件**。 |
| 199 | + |
| 200 | +- 更改是仅元数据的操作,记录在新的快照中。 |
| 201 | +- 这是即时的,不需要停机,并避免了昂贵的数据迁移任务。旧数据仍然可以使用其原始 schema 访问。 |
| 202 | + |
| 203 | +## 用于查询加速的高级索引(Fuse Engine) |
| 204 | + |
| 205 | +除了使用统计信息进行基本块/段修剪之外,Fuse Engine 还提供专门的二级索引,以进一步加速特定的查询模式: |
| 206 | + |
| 207 | +| 索引类型 | 简要描述 | 加速的查询类型... | 示例查询片段 | |
| 208 | +| :------------------ | :----------------------------------------------------------- | :-------------------------------------------------- | :-------------------------------------- | |
| 209 | +| **Aggregate Index** | 预先计算指定组的聚合结果 | 更快的 `COUNT`、`SUM`、`AVG`... + `GROUP BY` | `SELECT COUNT(*)... GROUP BY city` | |
| 210 | +| **Full-Text Index** | 用于在文本中快速关键字搜索的倒排索引 | 使用 `MATCH` 的文本搜索(例如,日志) | `WHERE MATCH(log_entry, 'error')` | |
| 211 | +| **JSON Index** | 索引 JSON 文档中的特定路径/键 | 过滤特定 JSON 路径/值 | `WHERE event_data:user.id = 123` | |
| 212 | +| **Bloom Filter Index** | 概率性检查以快速跳过不匹配的块 | 快速点查找 (`=`) 和 `IN` 列表过滤 | `WHERE user_id = 'xyz'` | |
| 213 | + |
| 214 | +## 比较:Databend Fuse Engine vs. Apache Iceberg |
| 215 | + |
| 216 | +_**注意:** 此比较专门关注**表格式功能**。作为 Databend 的原生表格式,Fuse 不断发展,旨在提高**可用性和性能**。显示的功能是当前的;预计会有变化。_ |
| 217 | + |
| 218 | +| 功能 | Apache Iceberg | Databend Fuse Engine | |
| 219 | +| :---------------------- | :--------------------------------- | :----------------------------------- | |
| 220 | +| **Metadata Structure** | Manifest Lists -> Manifest Files -> Data Files | **Snapshot** -> Segments -> Blocks | |
| 221 | +| **Statistics Levels** | 文件级别(+分区) | **多级别**(快照、段、块)→ 更精细的修剪 | |
| 222 | +| **Pruning Power** | 良好(文件/分区统计) | **优秀**(多级别统计 + 二级索引) | |
| 223 | +| **Schema Evolution** | 支持(元数据更改) | **零拷贝**(仅元数据,即时) | |
| 224 | +| **Data Clustering** | 排序(写入时) | **自动**优化(后台) | |
| 225 | +| **Streaming Support** | 基本流式摄取 | **高级增量**(插入/更新跟踪) | |
0 commit comments