数据库筑基课 - 列存之 Vortex
这篇是 digoal skill 写的(已开源), 一字未改.
本节: 列存之 Vortex
先说结论
Parquet 统治列存格式多年,但它的"块压缩"致命弱点正在拖累 AI 时代的数据处理效率。Vortex 作为 Linux 基金会旗下的下一代列式存储格式,通过"编码下推 + 延迟物化"的设计,在随机访问场景比 Parquet 快 100-200 倍,全表扫描快 2-10 倍,同时保持相当的压缩率。
如果你的业务场景是:交互式分析、实时查询、ML 训练数据管道、GPU 原位解压,Vortex 值得优先考虑。
1. Parquet 的痛点:块压缩的代价
Parquet 是 Google Dremel 的开源实现,是大数据生态的事实标准。但它有一个与生俱来的局限:块压缩(Block-compressed)。
什么意思?Parquet 把数据切成 Page,每个 Page 内部使用压缩算法(如 Snappy、GZIP)进行压缩。当引擎需要读取数据时:
读取 Parquet 数据流程:
1. 定位到目标 Page (通过 column index / bloom filter)
2. 解压整个 Page
3. 解码数据
4. 执行过滤、聚合
这就好比你想在快递箱里找一把钥匙,必须先把整箱胶带撕开、解压、再翻找。对于随机访问少量数据的场景,这种"先解压再过滤"的模式浪费了大量 CPU 和 IO。
2. Vortex 的核心设计:编码下推 + 延迟物化
Vortex 正是为了解决这个痛点而设计的。它的核心思想是:让过滤和计算尽量在压缩数据上直接执行,而不是先解压再计算。
2.1 三大黑科技
(1) 轻量级编码:不解压直接算
Vortex 内置了多种先进编码,其中最关键的是:
| ALP | ||
| FSST | ||
| FastLanes |
这些编码的共同特点是:可以在压缩数据上直接执行过滤和计算,不需要先解压。
(2) 延迟物化(Late Materialization)
传统列存的数据读取路径:
Page Header → 解压 → 解码 → Filter → Project → CPU
Vortex 的路径:
Compressed Page → Filter (直接在压缩域) → 仅解压需要的行 → CPU
也就是说,数据只有在最后一步进入 CPU/GPU 时才会被解压,最大化利用硬件带宽。
(3) GPU 原位解压
Vortex 的设计支持将压缩数据直接传输到 GPU 显存,然后在 GPU 上就地解压并计算。对于 ML 训练场景,这意味着减少 CPU-GPU 间的数据搬运开销。
2.2 与 Apache Arrow 零拷贝互转
Vortex 定义了与 Arrow 完全兼容的内存布局,可以零拷贝地将磁盘数据映射到 Arrow 数组,反之亦然。避免序列化/反序列化开销。
3. Vortex 文件布局(Layouts)
Vortex 的物理存储采用分块(Chunked)组织,类似于 Parquet 的 RowGroup,但更细粒度:
Vortex File
├── Footer (元数据: schema, layouts, statistics)
├── Chunk 0 (列数据)
├── Chunk 1 (列数据)
├── ...
└── Chunk N (列数据)
每个 Chunk 内部按列存储,同一列的所有 Chunk 组成完整的列数据。Chunk 是压缩、编码的独立单元,支持:
按需读取单个 Chunk:随机访问只需读取目标 Chunk 过滤下推:在 Chunk 级别做统计过滤,直接跳过不相关的 Chunk
Vortex 支持多种 Layout,适配不同的数据特征和查询模式:
| Flat | ||
| Sparse | ||
| Nested |
4. DuckDB + Vortex:秒级上手
DuckDB 自 1.4.2 起正式支持 Vortex(通过 vortex 扩展),使用体验与 Parquet 完全一致:
-- 1. 安装并加载扩展
INSTALL vortex;
LOAD vortex;
-- 2. 写入 Vortex 文件(像写 Parquet 一样)
COPY (SELECT * FROM orders) TO'data.vortex' (FORMAT vortex);
-- 3. 极速读取
SELECT * FROM read_vortex('data.vortex');
-- 4. 带过滤条件的极速随机访问
SELECT * FROM read_vortex('data.vortex')
WHERE order_date = '2026-01-01'AND amount > 1000;
DuckDB 在写入时自动选择最优编码策略,在读取时自动下推过滤条件。
5. 性能对比:DuckDB 实测数据
基于 TPC-H Scale Factor 100(约 20GB 数据量),冷启动环境下多次测试的几何平均结果:
| Vortex | 43.80 s |
关键结论:
Vortex 比 Parquet v2 快 18%,比 Parquet v1 快 35% 存储体积增加约 15%,但换取的是显著的计算加速 稳定性:Vortex 多次运行波动极小,不受缓存机制干扰
数据来源: DuckDB 官方博客
6. 适合场景 vs 不适合场景
适合 Vortex 的场景
不适合 Vortex 的场景
7. Google BigQuery 的 Vortex 存储引擎(顺便科普)
注意:本文讨论的是 Vortex 列式文件格式(DuckDB 集成的)。Google BigQuery 内部也有一个叫 Vortex 的存储引擎(论文原文),两者名字相同但定位不同:
| Vortex 文件格式 | ||
| Vortex 存储引擎 |
BigQuery 的 Vortex 核心思想是"流优先":
WOS (Write Optimized Storage):数据先以行式追加写入,保证高吞吐 ROS (Read Optimized Storage):后台异步将数据转成列式(Capacitor 格式),提升查询效率 查询时自动合并:同时读 WOS 和 ROS,用户无感知
这和 LSM Tree 的思路异曲同工。感兴趣的朋友可以看我的 《AI论文解读 | Vortex: A Stream-oriented Storage Engine For Big Data Analytics》。
8. 前提条件与边界
本文结论成立的前提:
查询特征是分析型(OLAP),而非高频单行点查 存储介质支持随机访问(本地 SSD、对象存储等) 对计算效率的需求 > 对极致压缩的需求
如果以下任一条件满足,请重新评估:
数据写入远多于读取 → 考虑 LSM Tree 系(RockDB、PolarDB XEngine) 需要强一致性事务写入 → 考虑 PostgreSQL/PolarDB 原生表 已有成熟 Parquet 管道 → 迁移收益不明确时不动
9. 快速验证清单
如果你想验证 Vortex 是否适合你的场景:
[ ] 1. 在 DuckDB 中安装 vortex 扩展: INSTALL vortex; LOAD vortex;
[ ] 2. 将你的测试数据同时导出为 Parquet 和 Vortex
[ ] 3. 对比两者在典型查询(尤其是带过滤的随机访问)上的耗时
[ ] 4. 对比存储体积
[ ] 5. 如果随机访问耗时 Vortex < Parquet 的 1/10,考虑迁移
参考
DuckDB Vortex 官方博客 Vortex 文件格式官方文档 Vortex (Linux Foundation 项目) 《数据库筑基课 - 列存之 Parquet》 《AI论文解读 | Vortex: A Stream-oriented Storage Engine For Big Data Analytics》 《DuckDB 悄悄发布1.4.2 LTS版, 支持Vortex存储格式, 随机访问性能飙升》