在现代 SaaS 系统中,业务数据量增长迅速,尤其是电商、金融等场景,每天产生亿级订单数据。传统 MySQL 虽然适合事务处理(OLTP),但在复杂分析和报表查询(OLAP)方面容易成为瓶颈。DuckDB 是一款嵌入式列式数据库,专为分析型查询设计,具有轻量、高效、易嵌入 Java 应用的特点。本文将介绍如何使用 DuckDB 构建高性能 OLAP 分析平台。
一、DuckDB 简介
-
嵌入式列式数据库,无需安装服务器,直接嵌入应用。
-
列式存储 + 向量化执行,对聚合和扫描型查询性能极佳。
-
支持 Parquet、CSV 等文件,可直接读取列式数据。
-
插件机制,支持连接 MySQL、PostgreSQL 等外部数据库。
-
适合 OLAP 分析,可与现有事务型数据库(MySQL)组合构建数据分析平台。
二、安装与 Java 集成
在 Java 项目中使用 DuckDB,需要引入 JDBC 驱动:
Maven 依赖示例:
<dependency>
<groupId>org.duckdb</groupId>
<artifactId>duckdb_jdbc</artifactId>
<version>1.1.3</version>
</dependency>
Java 连接示例:
Class.forName("org.duckdb.DuckDBDriver");
Connection conn = DriverManager.getConnection("jdbc:duckdb:./data/duckdb.db");
DuckDB 数据库可保存在文件中,也可直接在内存中运行(
jdbc:duckdb:
)。
三、连接 MySQL 并查询数据
DuckDB 通过插件连接 MySQL,实现实时查询或数据抽取。
1. 安装与加载插件
Statement stmt = conn.createStatement();
stmt.execute("INSTALL mysql");
stmt.execute("LOAD mysql");
2. 挂载 MySQL 数据库
stmt.execute("ATTACH 'mysql://root:123@localhost:3306/testdb' AS mydb (TYPE mysql)");
3. 查询 MySQL 数据
ResultSet rs = stmt.executeQuery("SELECT * FROM mydb.orders LIMIT 5");
while (rs.next()) {
System.out.println(rs.getInt("id") + " - " + rs.getString("customer"));
}
注意:这种方式适合小量实时查询,对于海量数据推荐通过增量同步生成 Parquet 文件。
四、生成 Parquet 文件(列式存储)
Parquet 是列式存储格式,非常适合 OLAP 查询。通过 DuckDB 可以将 MySQL 数据导出为 Parquet 文件:
// 创建目录
File dir = new File("data/duckdb/orders/2025-09-30/");
if (!dir.exists()) dir.mkdirs();
String filePath = "data/duckdb/orders/2025-09-30/orders_increment.parquet";
stmt.execute("COPY (SELECT * FROM mydb.orders WHERE updated_at > '2025-09-30 00:00:00') " +
"TO '" + filePath + "' (FORMAT PARQUET)");
优点:
增量导出,避免每次全量导入
列式存储,扫描效率高
支持按日期或店铺分目录管理,便于批量分析
五、在 DuckDB 中分析 Parquet 数据
DuckDB 支持直接读取 Parquet 文件:
SELECT store_id, SUM(amount) as total_sales
FROM read_parquet('data/duckdb/orders/2025-09-30/*.parquet')
GROUP BY store_id;
1. 物化视图优化
对常用聚合预计算,提升查询性能:
CREATE MATERIALIZED VIEW orders_summary AS
SELECT store_id, DATE(updated_at) as day, SUM(amount) as total_amount
FROM read_parquet('data/duckdb/orders/*.parquet')
GROUP BY store_id, day;
2. 分区扫描
如果 Parquet 文件按日期存储,DuckDB 会自动跳过不需要扫描的文件,提高效率。
六、增量同步策略
对于每天亿级订单的场景,推荐:
-
全量初始化:第一次导入 MySQL 历史数据到 DuckDB/Parquet。
-
增量同步 :定时(如每 5 分钟)查询 MySQL
updated_at
> 上次同步时间,生成 Parquet 文件。 -
批量导入:DuckDB 读取 Parquet 文件进行分析或物化视图更新。
-
目录管理:按日期生成文件夹,便于增量同步和清理历史数据。
七、Java/Spring Boot 自动增量同步示例
@Scheduled(fixedDelay = 5 * 60 * 1000) // 每 5 分钟同步一次
public void syncOrders() throws Exception {
// 1. 获取上次同步时间
Timestamp lastSync = duckdbJdbc.queryForObject(
"SELECT MAX(updated_at) FROM orders_duck", Timestamp.class);
// 2. 查询 MySQL 增量数据
List<Map<String, Object>> rows = mysqlJdbc.queryForList(
"SELECT * FROM orders WHERE updated_at > ?", lastSync);
// 3. 导出 Parquet 文件
String dir = "data/duckdb/orders/" + LocalDate.now();
new File(dir).mkdirs();
String filePath = dir + "/orders_increment.parquet";
// 4. 使用 DuckDB COPY 导入 Parquet
// (可用 JDBC 执行 COPY 命令)
}
可以结合物化视图,提升报表查询性能。
八、总结
-
DuckDB 是轻量、列式、嵌入式数据库,适合 OLAP 分析。
-
MySQL + DuckDB 构建混合 OLTP/OLAP 架构:
-
MySQL 保证事务处理
-
DuckDB 提供高性能分析查询
-
-
增量同步 + Parquet + 物化视图 是关键优化策略。
-
目录管理 + 分区存储 便于大数据量管理,每天增量生成的 Parquet 文件可快速供报表和分析查询使用。
通过这种方案,即使每天产生亿级订单,也能保证报表查询在秒级内返回,同时不会影响 MySQL 的事务性能。