使用 DuckDB 分析 Parquet 文件
上周朋友发我一个小餐馆的订单文件:restaurant_orders.parquet。
他说是外卖平台导出的,想看看总共多少单、赚了多少钱、哪个菜卖得好、大家怎么付款。
文件几百 MB,不算大,但也不想为了看几个数去折腾数据库。
我直接用了 DuckDB,它有几个好处:
- 不用建表,不用导入,直接
read_parquet() - SQL 支持完整
- 窗口函数也有
- 单机跑,装完就能用
下面按我实际查询的顺序来。
1. 安装 DuckDB,打开文件
安装 DuckDB。
curl https://install.duckdb.org | sh
/home/user/.duckdb/cli/latest/duckdb
进去之后先预览前 5 行:
SELECT * FROM read_parquet('/path/to/restaurant_orders.parquet') LIMIT 5;
这里 DuckDB 的优势已经出来了:我连 CREATE TABLE 都没写,直接查 Parquet。
2. 看数据结构
数据已经呈现在眼前,但先别急着动手。
就像做菜前要先认识食材一样,我们得先搞清楚这份数据的“脾气秉性”。
DESCRIBE SELECT * FROM read_parquet('/path/to/restaurant_orders.parquet') LIMIT 5;
输出会告诉你每列类型。比如:
order_id:订单号order_time:下单时间customer_name:客户名menu_item:菜品quantity:数量price:单价payment_method:支付方式
先看类型,后面算钱才不会出错。
3. 基础分析:回答朋友的问题
好了,现在我们对数据已经了如指掌,是时候来回答朋友最关心的那几个问题了。
3.1 总共多少单
这是最直接的问题,我们先用一个简单的计数来摸清底数。
SELECT COUNT(*) AS total_orders
FROM read_parquet('/path/to/restaurant_orders.parquet');
3.2 总共卖了多少钱
光知道订单数还不够,朋友最关心的还是赚了多少钱。这里有个小细节,收入是单价乘以数量,可别算错了。
SELECT SUM(price * quantity) AS total_revenue
FROM read_parquet('/path/to/restaurant_orders.parquet');
注意是 price * quantity,不是只加 price。
3.3 哪个菜最受欢迎
知道了总收入,朋友又问:“哪个菜卖得最好?我好知道下次备货该重点进什么。”
这个问题,用分组和排序就能轻松搞定。
SELECT menu_item, SUM(quantity) AS total_quantity
FROM read_parquet('/path/to/restaurant_orders.parquet')
GROUP BY menu_item
ORDER BY total_quantity DESC
LIMIT 5;
这里看的是销量。朋友说想知道备货重点,这个结果比销售额更直接。
3.4 大家喜欢怎么付钱
最后一个基础问题,是关于支付方式的。了解顾客的付款习惯,对餐馆的日常运营也很有帮助。
SELECT payment_method, COUNT(*) AS order_count
FROM read_parquet('/path/to/restaurant_orders.parquet')
GROUP BY payment_method
ORDER BY order_count DESC;
微信、支付宝、现金、银行卡,一眼就能看出哪种多。
4. 窗口函数:看趋势和排名
基础问题回答完了,但数据分析的乐趣远不止于此。
DuckDB 对 SQL 标准的支持非常完整,比如强大的窗口函数,能帮我们挖掘出更深层次的信息。
4.1 收入随时间累计
朋友看着总收入,突然好奇:“这一天里,我们的收入是怎么一步步涨上去的?”
这时候,窗口函数就派上用场了,它可以帮我们计算一个“累计和”。
SELECT order_time,
SUM(price * quantity) OVER (ORDER BY order_time) AS running_revenue
FROM read_parquet('/path/to/restaurant_orders.parquet');
不用自连接,也不用写子查询。直接看一天里收入怎么累计。
4.2 最贵的订单排名
最后,朋友八卦心起,想看看谁是今天的“消费冠军”。
我们可以给所有订单按金额排个名。
SELECT order_id,
customer_name,
price * quantity AS order_value,
RANK() OVER (ORDER BY price * quantity DESC) AS rank
FROM read_parquet('/path/to/restaurant_orders.parquet')
LIMIT 5;
朋友可以拿这个看看大单是谁下的。当然,实际用的时候可以去掉 LIMIT 或者加条件。
5. 总结
这整套流程,我没建数据库,没导数据,没起服务。
DuckDB 直接读 Parquet,用 SQL 把问题一个个查出来。
它适合这种场景:
- 手头有 Parquet 文件,想快速看数;
- 不想为了几个查询上 Spark 或建数仓;
- 需要 SQL 聚合、分组、窗口函数;
- 本地跑,快,零运维。
如果你也经常拿到 Parquet 文件不知道怎么看,先装个 DuckDB,然后用read_parquet() 读取它,之后就可以使用 SQL 来分析其中的数据了。
文中用到的 parquet 数据文件:restaurant_orders.parquet: https://url11.ctfile.com/f/45455611-17569897503588-39e921?p=6872 (访问密码: 6872)

浙公网安备 33010602011771号