先来三个灵魂拷问
你上一次把 ADS 表导出 Excel 做探查,是不是卡到风扇起飞?
你上一次 vlookup 三张百万行 CSV,是不是蓝屏死机?
你上一次把 Excel 粘给老板,是不是被问“能不能换个格式,我要透视”?
如果你都点头,那恭喜你——你已经在做“二次分析”了
而二次分析,正是DuckDB在今天依旧值得被数据人放进工具箱的最大理由。
一、闲谈
1.1 什么是二次分析
| 维度 | 一次加工 | 二次分析 |
|---|---|---|
| 位置 | 数仓/Hadoop/Spark | 本地电脑 |
| 产出 | dwd/dws/ads 表 | 业务问题的答案 |
| 工具 | hive/spark/flink等 | excel/Python/r |
| 量级 | TB级 | GB及以下 |
| 目标 | 口径对齐与沉淀 | 灵活探查与试错 |
一句话总结:数仓把数据做对,DuckDB把数据做活
1.2 为什么能赢 Excel
| 维度 | Excel 2021 | DuckDB 1.3 |
|---|---|---|
| 单文件上限 | 1,048,576 行 | 无硬性限制(受内存) |
| CSV 读取 | 慢、类型推断错 | GB/s+、自动推断 |
| SQL 支持 | PowerQuery 半吊子 | 完整 sql:2016 |
| 多表关联 | vlookup | 标准 JOIN |
| 窗口函数 | 不支持 | 全支持 |
| 可脚本化 | VBA | Python/R/CLI等 |
| 结果导出 | xlsx/csv/txt | parquet/json/xlsx等 |
ps: 表格数据来自 AI 总结
另外在文件读取上,DuckDB 支持 parquet/avro/xlsx/csv 等文件自动推断,包括文件类型和 schema 推断
二、上手
2.1 安装
通用脚本安装
curl https://install.duckdb.org | sh |
点击查看更多安装方式: https://duckdb.org/docs/installation/?version=stable&environment=cli&platform=macos&download_method=direct
不会装?那直接使用 wasm 版本吧!!!点击前往:https://shell.duckdb.org/(注意数据安全问题哦)
2.2 数据
使用 COVID-19 流行病学公开数据中的
各国/地区每日疫情核心指标,包含:地区、确诊人数、死亡人数等点击下载:https://storage.googleapis.com/covid19-open-data/v3/epidemiology.csv
各国/地区人口、面积等静态数据,点击下载: https://storage.googleapis.com/covid19-open-data/v3/demographics.csv
schema等相关信息访问github仓库: https://github.com/GoogleCloudPlatform/covid-19-open-data
2.3 分析
虚拟一个分析场景:
找出过去 30 天内,每百万人口新增确诊最多的前 10 个国家,并给出它们的死亡率(新增死亡 ÷ 新增确诊)与 确诊率(新增确诊 ÷ 人口 × 1,000,000)
如果使用 Excel,嗯…我不会…AI说可以。
个人认为做数据分析最好的形态就是 notebook,一次尝试一个cell清晰简洁。使用duckdb -ui开启它会自动跳转到浏览器,默认地址http://localhost:4213/

新建 notebook -> add cell -> 写sql
- 假设 epidemiology.csv 和 demographics.csv 已下载到同目录
-- epidemiology.csv 字段: date, country_code, new_confirmed, new_deceased
-- demographics.csv 字段: country_code, population
WITH last30 AS (
-- 读取原始指标数据,duckdb会自动识别首行和 schema
SELECT location_key, new_confirmed, new_deceased
FROM './epidemiology.csv'
WHERE date between STRPTIME('2021-05-01', '%Y-%m-%d') - INTERVAL 30 DAY and STRPTIME('2021-05-01', '%Y-%m-%d')
),
agg30 AS (
-- 统计每个城市的确诊、死亡人数
SELECT
location_key,
SUM(new_confirmed) AS new_confirmed_30d,
SUM(new_deceased) AS new_deceased_30d
FROM last30
GROUP BY location_key
),
pop AS (
-- 读取原始维度数据,duckdb会自动识别首行和 schema
SELECT location_key, population
FROM './demographics.csv'
)
SELECT
p.location_key,
-- 每百万人口新增确诊
ROUND(new_confirmed_30d / population * 1000000, 2) AS confirmed_per_million,
-- 死亡率
ROUND(CAST(new_deceased_30d AS DOUBLE) / NULLIF(new_confirmed_30d, 0), 4) AS fatality_rate,
-- 原始 30 天新增确诊
new_confirmed_30d
FROM agg30 a
JOIN pop p on a.location_key = p.location_key
WHERE population > 0
ORDER BY confirmed_per_million DESC
LIMIT 10;
仅500毫秒即可返回结果,同时右侧窗口展示指标的数据分布。
如果先将 csv 写入 duckdb 内部表速度将更快,因为它是列存
三、小结
DuckDB 的能力远不止如此,如果你有一些“奇怪”的权限甚至可以直接读 hive 的分区
例如:orders 是一张二级分区的表
orders ├── year=2021 │ ├── month=1 │ │ ├── file1.parquet │ │ └── file2.parquet │ └── month=2 │ └── file3.parquet └── year=2022 ├── month=11 │ ├── file4.parquet │ └── file5.parquet └── month=12 └── file6.parquet |
可以使用下面的sql读取且支持分区裁剪
SELECT *
FROM read_parquet('orders/*/*/*.parquet', hive_partitioning = true)
WHERE year = 2021 and month = 1; |
同时 DuckDB 的 Extension 机制,让 DuckDB 支持读取 Iceberg、RDBMS、S3 甚至可以做 FTS(full-text search)和 Embedding Stores
总之:别再让 Excel 毁了你下班前的灵感,在二次分析这条赛道,DuckDB 不是“单机玩具”,而是“本地 OLAP 火箭”