DeepSeek总结的MariaDB 的 DuckDB 存储引擎

来源:https://mariadb.org/duckdb-storage-engine-for-mariadb-when-the-sea-lion-learns-to-quack/

MariaDB 的 DuckDB 存储引擎:当海狮学会嘎嘎叫

对 MariaDB 的 DuckDB 存储引擎的早期预览------列式、向量化分析,与您的事务型表紧密相邻。

问题所在

MariaDB 的 InnoDB 在其设计目标上表现出色:事务处理。逐行插入、更新、点查询、强一致性。但是,当您要求它扫描数千万行以进行多路连接和若干聚合操作时,行存储就必须付出巨大的努力。

通常的解决方案是搭建一个独立的分析系统,然后构建 ETL 管道将数据复制进去。这样一来,您需要维护两个系统,并且还要忍受它们之间的延迟。

如果分析引擎就位于同一台服务器内部呢?------ 相同的 SQL,相同的客户端,相同的数据目录?

我们构建了什么

MariaDB 的 DuckDB 存储引擎正是做到了这一点。使用 ENGINE=DuckDB 创建表,其数据以 DuckDB 原生的列式格式存储;针对它的分析查询则通过 DuckDB 的向量化、多核引擎运行------在 MariaDB 服务器内部进行。

无需单独的集群。无需 ETL。无需新的协议。使用熟悉的 mariadb 客户端,一种 SQL 方言,InnoDB 表和 DuckDB 表在同一个数据库中共存。

关于 MariaDB ColumnStore 的说明

MariaDB 已经提供了 ColumnStore,这是一个用于大规模分析的成熟列式引擎------通常部署为横向扩展的多节点数据仓库。DuckDB 引擎则针对不同的应用场景:单节点、进程内、零运维的分析引擎,与您的 InnoDB 表相邻,用于轻量级嵌入式分析和 HTAP。两者是互补而非竞争关系------当您需要分布式数据仓库时使用 ColumnStore,当您希望进行进程内分析且无需额外组件时,则使用 DuckDB 引擎。

30 秒快速体验

像创建任何其他表一样创建 DuckDB 表:

sql 复制代码
CREATE TABLE sales (
  id        BIGINT PRIMARY KEY,
  product   VARCHAR(64),
  amount    DECIMAL(12,2),
  sold_at   TIMESTAMP
) ENGINE=DuckDB;

使用普通 SQL 查询它------整个 SELECT 语句会被下推到 DuckDB:

sql 复制代码
SELECT product, SUM(amount) AS revenue
  FROM sales
 GROUP BY product
 ORDER BY revenue DESC
 LIMIT 10;

而使其真正有用的部分是------跨引擎连接。单个查询可以同时连接 DuckDB 分析表和 InnoDB 操作表。端到端示例如下------两个不同引擎的表,在一个语句中连接:

sql 复制代码
-- 分析数据在 DuckDB 中,操作数据在 InnoDB 中
CREATE TABLE analytics.orders   (id BIGINT PRIMARY KEY, product_id INT, amount DECIMAL(12,2)) ENGINE=DuckDB;
CREATE TABLE inventory.products (id INT PRIMARY KEY, name VARCHAR(64))                          ENGINE=InnoDB;

INSERT INTO inventory.products VALUES (1, 'Wireless Keyboard'), (2, 'Mechanical Switch');
INSERT INTO analytics.orders   VALUES (4217, 1, 1299.00), (4218, 2, 42.00);

-- 一个查询,两种引擎
SELECT d.id, d.amount, i.name
  FROM analytics.orders   d        -- ENGINE=DuckDB
  JOIN inventory.products i        -- ENGINE=InnoDB
    ON d.product_id = i.id
 WHERE d.amount > 1000;

DuckDB 处理连接、聚合和排序;InnoDB 行通过 MariaDB 优化器按需生成。无需复制,无需 ETL。

性能表现

我们在 TPC-H SF10(约 11 GB,8660 万行,lineitem 表 6000 万行)上对该引擎进行了基准测试。分析引擎有两个关键指标:数据加载速度和查询速度。

硬件/环境:Intel Core i7-13700H(14 核 / 20 线程),64 GB RAM,NVMe SSD。MariaDB 11.4.13 内置 DuckDB v1.5.2,duckdb_memory_limit=8 GiBthreads=20。预热运行,稳定在约 ±15% 误差。

查询延迟------全部 22 个 TPC-H 查询

完整套件预热运行约需 4.3 秒

查询 耗时 (秒) 查询 耗时 (秒) 查询 耗时 (秒)
q01 0.253 q09 0.337 q17 0.116
q02 0.076 q10 0.253 q18 0.318
q03 0.134 q11 0.049 q19 0.207
q04 0.135 q12 0.152 q20 0.166
q05 0.142 q13 0.606 q21 0.486
q06 0.070 q14 0.128 q22 0.113
q07 0.133 q15 0.101 总计 4.30
q08 0.145 q16 0.178

每个查询还需支付少量固定成本(约 40 毫秒),用于客户端连接和下推设置------在最轻量的查询上比较明显,而在重分析查询上可以忽略不计,因为 DuckDB 的向量化执行占据主导。

批量加载

路径 总加载时间
引擎内 COPY (run_in_duckdb,8 GB 内存) 33 秒
LOAD DATA LOCAL INFILE ~400 秒(6.7 分钟)

通过 run_in_duckdb() 函数,在进程内使用 DuckDB 原生的并行读取器加载外部 CSV,可在约 33 秒 内摄取全部 8660 万行数据。标准的 LOAD DATA LOCAL INFILE 路径大约慢 12 倍 ,因为每一行都经过 MariaDB 的 SQL/handler 层路由,串行化了 COPY 并行执行的工作。对于批量加载,建议通过 run_in_duckdb 使用引擎内 COPY,并为大表提高 duckdb_memory_limit

工作原理(简述)

DuckDB 的速度基于三大支柱:列式存储(只读取所需的列)、向量化执行(以缓存友好的批量处理数据)和并行性(利用所有核心)。

在 MariaDB 内部,该引擎接入两个地方:

  • 查询下推 ------整个 SELECT 语句(包括 WHERE、JOIN、GROUP BY、ORDER BY)通过 MariaDB 的 select_handler 接口交给 DuckDB,由 DuckDB 的优化器规划整个查询。
  • 跨引擎扫描------当查询混合了 DuckDB 和非 DuckDB 表时,非 DuckDB 表通过完整的 MariaDB 执行管道按需流入 DuckDB,因此索引访问和谓词评估仍发生在 MariaDB 端。

这是简要版本。更深入的架构文章即将发布。

为什么采用插件形式

DuckDB 引擎以 MariaDB 插件的形式提供------这是一个经过深思熟虑的重要选择。MariaDB 的可插拔架构使得这样的组件可以拥有独立于服务器本身的成熟度。

  • 对服务器稳定性无影响------因为存储引擎插件是按需加载的,并且通过定义良好的接口进行隔离,它可以被添加到一个 GA 版本中,而不会危及核心服务器的稳定性。如果您不加载插件,对您没有任何影响。
  • 按自身节奏成熟------该插件可以按照自己的节奏迭代、稳定并达到生产就绪状态,与服务器的发布周期解耦。早期采用者今天就可以选择加入;其他人则不受影响。
  • 干净的按需启用------当您需要该功能时安装插件,不需要时则不安装。长期以来为 InnoDB、Spider 和 ColumnStore 等引擎提供支持的相同机制,现在也为 DuckDB 提供了支持。

这正是让 MariaDB 能够安全地提供雄心勃勃的新功能的模式:需要时功能强大,不需要时无感隐身。

适用场景

良好适用

  • HTAP ------ InnoDB 用于事务,DuckDB 用于分析,均在同一个数据库中。
  • 即席分析查询 ------ 大数据量的连接、聚合、窗口函数,无需导出数据。
  • 消除 ETL ------ 分析引擎在进程内运行。

当前限制(仍处于早期阶段)

  • DECIMAL 精度上限为 38 位(DuckDB 的限制)。
  • DuckDB 引擎的表需要 PRIMARY KEY,并拒绝非 UTF-8 字符集。
  • 某些 MariaDB 函数尚不支持下推(例如 GROUP_CONCAT()DATE_FORMAT()),将回退到 MariaDB 执行。
  • 比 MariaDB 默认 sql_mode 更严格的 GROUP BY 要求。
  • 不支持 XA 事务;跨引擎外部扫描目前是单线程的。
  • 对于非 UTF-8 字符集,排序规则是近似的。

路线图

这仅仅是开始。我们接下来的方向:

  • 分析型 GIS ------ 开放 DuckDB 的 Spatial 扩展,使地理空间分析能在 MariaDB 内部运行。
  • 仅 InnoDB 数据上的更快 HTAP ------ 通过 DuckDB 的向量化执行对纯 InnoDB 表运行查询,即使不涉及 DuckDB 表也能加速分析。
  • 部分查询下推 ------ 实现一个派生 handler,将复杂查询的部分下推到 DuckDB,使混合工作负载可以卸载其分析子查询。
  • 数据湖访问 ------ 通过 DuckDB 的扩展生态系统访问外部数据湖协议和格式。

尝试一下

获取预构建包

最快路径:MariaDB 的社区 CI 在 ci.mariadb.org/68929/ 发布预构建包。选择与您的平台和架构匹配的目录------每个操作系统/架构组合都有一个,因此您需要选择正确的路径。对于 Ubuntu 24.04 (amd64),路径是:

https://ci.mariadb.org/68929/amd64-ubuntu-2404-deb-autobake/

将该目录用作软件包仓库(或直接从其中下载 .deb 文件)即可安装,无需编译。对于其他目标,请替换为对应的文件夹------例如 amd64-rhel-9-rpm-autobake/、aarch64-ubuntu-2404-deb-autobake/ 等。请注意,这些包未签名,仅适用于测试目的。

从源码构建

另外,该引擎在 storage/duckdb/ 目录下随树提供。克隆与您的目标 MariaDB 版本匹配的分支并进行构建:

bash 复制代码
git clone --recurse-submodules -b 11.4 https://github.com/MariaDB/server.git mariadb-server
cd mariadb-server

./storage/duckdb/build.sh -D   # 安装构建依赖 (需要 root)
./storage/duckdb/build.sh      # 构建 + 安装

自行构建软件包

更愿意自己制作可分发的软件包?在安装构建依赖(build.sh -D)之后,build.sh -p 会为您的平台生成 RPM 或 DEB。详情请参见引擎 README 中的"构建软件包"部分:

bash 复制代码
./storage/duckdb/build.sh -p   # 构建 RPM (Rocky/Fedora/Amazon Linux) 或 DEB (Debian/Ubuntu)

启用引擎

DuckDB 引擎必须在服务器启动时加载------此步骤是必须的。将 duckdb.cnf 文件放入您服务器的 config-include 目录:

  • Debian / Ubuntu: /etc/mysql/mariadb.conf.d/duckdb.cnf

  • RHEL / Fedora / openSUSE: /etc/my.cnf.d/duckdb.cnf

    [mysqld]
    plugin-maturity=alpha
    plugin-load-add=ha_duckdb.so
    duckdb-memory-limit=8G # 默认只有 1G ------ 在测试前值得调高

plugin-load-add 加载引擎,而 plugin-maturity=alpha 是必需的,因为该插件目前处于 alpha 成熟度级别。注意默认的 duckdb-memory-limit 只有 1 GB ------ 对于任何认真测试,都值得先将其调高,因为它是大负载和查询的主要瓶颈。重启服务器后,您就可以创建 ENGINE=DuckDB 表了。

这是一个预览版------我们欢迎测试者、错误报告和反馈。

许可证

该引擎基于 GPL v2 许可(与 MariaDB 服务器相同),而 DuckDB 本身基于宽松的 MIT 许可证分发。

致谢

这项工作借鉴了 DuckDB 项目------其简洁、可嵌入、MIT 许可的引擎使这样的集成成为可能------也借鉴了阿里巴巴的 AliSQL,其 2025 年 12 月将 DuckDB 集成到 MySQL 兼容服务器中的版本是一个有价值的参考和验证点。

后续还有更多内容------包括更深入的架构探讨和更全面的基准研究。

相关推荐
tiancaijiben2 小时前
阿里云VMware服务完全对接指南:从环境准备到混合云生产级应用
数据库
Curvatureflight2 小时前
MySQL 深分页越来越慢?从 LIMIT OFFSET 改成游标分页
数据库·oracle
tiancaijiben2 小时前
阿里云函数计算FC如何实现网站的定时任务与自动化
数据库·oracle·dba
xfhuangfu2 小时前
Oracle 19c 多租户体系架构介绍
数据库·oracle·架构
java1234_小锋2 小时前
请描述 Spring Boot 的启动流程,包括 SpringApplication 的初始化和 run 方法的核心步骤。
java·数据库·spring boot
qq_谁赞成_谁反对3 小时前
甲方IT的成长之路--nginx实战--2604
服务器·数据库·nginx
云水一下3 小时前
从零开始学 PHP 系列(六):MySQL 数据库与 PHP 交互——让数据真正“住”进服务器
数据库·mysql·php
fofantasy3 小时前
NSK LH25FL 升级至 NH25EM 技术规格指南
服务器·网络·数据库·经验分享·规格说明书