课程首页· 术语表· 速查表

Reference · 速查

Parquet 速查表

写代码时放在旁边的一页纸。命令可直接抄,参数带默认值与建议值。打印友好。

① 30 秒体检一个文件

-- 一眼看清:每列多大、什么编码、几个 row group、统计信息在不在
SELECT path_in_schema AS col,
       round(sum(total_compressed_size)/1024.0/1024, 2) AS mb,
       any_value(encodings) AS enc,
       any_value(compression) AS codec
FROM parquet_metadata('f.parquet') GROUP BY 1 ORDER BY mb DESC;

SELECT * FROM parquet_file_metadata('f.parquet');   -- 行数/rg 数/footer 大小
SELECT * FROM parquet_schema('f.parquet');          -- 物理类型 + 逻辑类型

或直接用课程脚本:python inspect_parquet.py f.parquet

② 写入参数:默认值 vs 建议值

pyarrow 参数默认建议为什么
compression"snappy""zstd"小 34%,写入只慢 12%
compression_level库默认别动调到 15 只省 10%,写入慢 6.5 倍
row_group_size1,048,576 行100k–1M 行太大跳不掉、并行差;太小元数据占比高
use_dictionaryTrue(全列)列名列表不收窄的话字典会抢跑,其他编码失效
column_encoding无时间/自增列给 DELTA_BINARY_PACKED实测该列 7.85 → 0.03 MB
write_page_indexFalseTrue代价极小的页级跳过
write_statisticsTrue保持关掉等于放弃 row group 跳过
sorting_columns无与实际排序一致把排序事实记进 footer
bloom_filter_options无按需仅高基数 + 等值点查 + 非排序键
data_page_size1 MB保持另有 max_rows_per_page=20000 同时生效

③ 标准写法(抄这个)

import pyarrow.parquet as pq

LOW_CARD = ["tenant_id", "building_code", "device_id", "metric"]
t = table.sort_by([("device_id", "ascending"), ("ts", "ascending")])

pq.write_table(
    t, "out.parquet",
    compression="zstd",
    row_group_size=200_000,
    use_dictionary=LOW_CARD,                                # 收窄,防抢跑
    column_encoding={"ts": "DELTA_BINARY_PACKED"},          # 时序列
    write_page_index=True,
    sorting_columns=pq.SortingColumn.from_ordering(
        t.schema, [("device_id", "ascending"), ("ts", "ascending")]),
)
COPY (SELECT * FROM src ORDER BY device_id, ts)
  TO 'warehouse/iot'
  (FORMAT parquet, PARTITION_BY (day), COMPRESSION zstd, ROW_GROUP_SIZE 200000);

④ 读取速查

要做的事DuckDBpyarrow
读单文件SELECT * FROM 'f.parquet'pq.read_table("f.parquet")
读一批read_parquet('dir/**/*.parquet')ds.dataset("dir", format="parquet")
Hive 分区当列用read_parquet(…, hive_partitioning=true)ds.dataset(…, partitioning="hive")
列不一致时合并read_parquet(…, union_by_name=true)ds.dataset(…) 自动按名
知道行来自哪个文件read_parquet(…, filename=true)加 ds.field("__filename")
只读几列SELECT a, b FROM …columns=["a","b"]
谓词下推写 WHERE 即可filters=[("day","==","2026-01-08")]
只要行数SELECT count(*) FROM …(0.2 ms)pq.ParquetFile(f).metadata.num_rows

⑤ 编码选择决策树

这一列是什么?
├─ 重复值多(租户/楼栋/设备/枚举/状态)
│    → RLE_DICTIONARY(默认就是,别关)
├─ 递增整数(时间戳/自增 ID/序号)
│    → DELTA_BINARY_PACKED  ← 收益最大,务必显式指定
│      ⚠ 同时用 use_dictionary=[低基数列…] 收窄,否则不生效
├─ 有序且共同前缀的字符串(路径/URL/层级编码)
│    → DELTA_BYTE_ARRAY
├─ 浮点物理量(温度/压力/功率)
│    → 先试 BYTE_STREAM_SPLIT,实测对比后再决定 ← 可能是负收益
└─ 其他(高基数随机字符串、UUID)
     → PLAIN + zstd,并考虑给它加 Bloom filter

⑥ Sizing 决策表

决定规则
单文件大小128 MB – 1 GB
row group100k – 1M 行(约 64–256 MB)
分区粒度让每个分区落在 100 MB – 1 GB。日增 < 100 MB 就按月分,别按天
第二个分区键几乎总是错的。用排序键解决第二维度
排序键选最常出现在 WHERE 里、且分区没覆盖的那个维度
官方 512 MB–1 GB row group 建议那是 HDFS block 时代的取值,对象存储 + 单机引擎场景不适用

⑦ 常见坑

症状原因解法
指定了编码但文件大小没变字典抢跑同时收窄 use_dictionary,写完查 encodings 栏验证
查询扫了全部 row group排序键不匹配查询,或 row group 太大换排序键;row_group_size 调到 100k–200k
统计信息看起来是空的读了已废弃的 stats_min/stats_max改用 stats_min_value/stats_max_value
归档目录体积不降反增分区切太细,小文件元数据开销合并分区层级 + 定期 compaction
分区数比天数多一个分区键用了本地时区strftime(ts AT TIME ZONE 'UTC', …)
混读新旧文件报错/错位schema 不一致按位置对齐union_by_name=true
compaction 后查出重复数据裸目录非原子临时路径 + 整体提交;反复出问题就该上表格式
换个库写出来大小差很多写入器编码策略不同正常现象。换写入器后重新体检,别搬结论

⑧ 本课程实测数字(4,320,000 行楼宇时序样本)

pyarrow 25.0.0 / DuckDB 1.5.5 / macOS ARM / 2026-08。用作量级参考,不是通用基准。
项目数字
JSONL / CSV / Parquet(zstd+排序)624.76 MB / 307.52 MB / 21.79 MB
关掉全部编码压缩的 Parquet266.49 MB(≈ CSV,说明布局本身不省空间)
排序对 device_id 列的影响4.14 MB → 0.02 MB
ts 列换 DELTA 编码7.85 MB → 0.03 MB(整文件 21.79 → 13.54 MB)
zstd vs snappy(同编码)13.54 MB vs 20.45 MB,写入 0.55 s vs 0.49 s
zstd 默认 vs 15 级13.54 MB / 0.55 s vs 12.23 MB / 3.60 s
列裁剪(1 列 vs 7 列 vs count(*))12.2 ms / 42.1 ms / 0.2 ms
排序键选对 vs 选错(时间窗查询)读 1/44 个 rg · 2.8 ms vs 读 44/44 · 14.2 ms
分区过细(day vs day+device)16 文件 14.16 MB 2.5 ms vs 3218 文件 31.42 MB 131.2 ms
PG → Parquet 归档51 MB(432k 行)→ 3.16 MB,校验和一致

⑨ 环境

$ pip install pyarrow duckdb          # 全课程只需这两个
$ brew install duckdb                  # 可选:命令行版
$ python gen_sample.py              # 生成样本数据(约 1 分钟)
$ python inspect_parquet.py f.parquet   # 体检任意文件
参数语义以官方文档为准 pyarrow write_table · DuckDB Parquet · Parquet File Format