关于 datadiffer
datadiffer 是用于比较两张表的只读工具,面向数据工程与分析流程,也可供编码 Agent 验证数据变更。除新增、删除和修改统计外,它还能指出变化集中在哪些数据分段。
主要功能
- 01比较表格并统计增删改行
- 02显示各列变化率
- 03按类别分段归因变化
- 04支持 Parquet、CSV、DuckDB、Postgres 和 Snowflake
- 05提供只读 MCP 工具
- 06支持结构化差异报告
适用场景
- 01检查开发与生产数据差异
- 02在 Pull Request 中审阅数据变更
- 03验证 Agent 生成的数据管道
- 04定位变更集中于哪些类别
MCP 相关
MCP 服务提供只读连接列表、结构差异、差异摘要和完整表格差异工具。凭据保留在本地配置中,工具使用连接名称而非 DSN。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
datadiffer
对比两张表。查看发生了哪些变化,以及变化集中在哪个数据切片中。
98.6% of modified rows have country = 'DE' (8.87x over-represented)
datadiffer 可对比两张表(开发环境与生产环境、PR 与 main、源表与目标表),并告诉你发生了哪些变化,以及变化集中在哪里:新增/删除/修改的行、各列的变化率,以及分段归因。
它专为 Agent 编写数据管道、需要有人检查其工作成果的时代打造。作为已归档的 data-diff 的后继项目,它持续维护并采用 MIT 许可证。
60 秒快速体验
无需凭据、配置或账号。它会自行生成数据:
uvx datadiffer demo

datadiffer-demo/orders_prod.parquet vs datadiffer-demo/orders_dev.parquet
key: order_id (inferred from *_id naming)
rows: +800 added -250 removed ~432 modified 49318 unchanged
┏━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃column ┃ changed rows ┃ % of matched┃
┡━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│amount │ 432 │ 0.87%│
└───────┴──────────────┴─────────────┘
-> 98.6% of modified rows have country = 'DE' (8.87x over-represented)
93.2% of added rows have plan = NULL (63.19x over-represented)
sample changes:
[order_id=0] amount: 5.0 -> 7.1
[order_id=1] amount: 6.37 -> 6.38
[order_id=117] amount: 32.4 -> 34.5
[order_id=234] amount: 59.8 -> 61.9
[order_id=351] amount: 87.2 -> 89.3
DIFF FOUND
最后这部分才是重点。diff 会告诉你有 432 行发生变化;datadiffer 则会告诉你这些变化几乎全都来自德国订单。这就是“有些数据变了”和“增值税变更已生效”之间的区别。
安装
pip install datadiffer # local files: Parquet, CSV, DuckDB
pip install 'datadiffer[snowflake]' # + Snowflake
pip install 'datadiffer[postgres]' # + Postgres
pip install 'datadiffer[mcp]' # + MCP server for AI agents
使用方法
# local files
datadiffer diff prod.parquet dev.parquet
# DuckDB
datadiffer diff prod.duckdb:orders dev.duckdb:orders
# Postgres (attached read-only)
datadiffer diff orders orders_v2 --source "postgresql://user@host:5432/db"
# Snowflake, or anything in datadiffer.toml (run `datadiffer init` first)
datadiffer diff wh::analytics.orders wh::analytics_dev.orders
# cross-source: warehouse vs. a local file
datadiffer diff wh::orders orders_snapshot.parquet
# machine-readable, for scripts and CI
datadiffer diff a.parquet b.parquet --format json
退出码遵循 GNU diff 约定:0 表示无差异,1 表示发现差异,2 表示操作错误。
实用标志:--key(省略时会自动推断)、--where、--columns/--exclude-columns、--sample-limit、--no-attribution、-q。
在拉取请求中使用
datadiffer-action 会将报告作为固定 PR 评论发布:
datadiffer:
ANALYTICS.ORDERS与ANALYTICS_PR_482.ORDERS:发现差异 ❌+800 行新增 · −250 行删除 · ~432 行修改 · 49,318 行未变(影响基表行数的 2.96%) 策略:超出 max-changed-rows-pct 限制:2.96% > 0.5%
列 变化行数 匹配行占比 amount432 0.87% 变化集中在: 98.6% 的修改行满足
country = 'DE'(占比是预期的 8.87 倍) 93.2% 的新增行满足plan = NULL(占比是预期的 63.19 倍)
- uses: gauthierpiarrette/datadiffer-action@v1
with:
config: datadiffer.toml # holds the warehouse connection
table-a: wh::ANALYTICS.ORDERS
schema-map: "ANALYTICS=ANALYTICS_PR_${PR_NUMBER}"
max-changed-rows-pct: "0.5"
env:
SNOWFLAKE_PRIVATE_KEY: ${{ secrets.SNOWFLAKE_PRIVATE_KEY }}
使用 dbt?docs/dbt-ci.md 会将 dbt ls --select state:modified 转换为每个已变更模型对应的一个 diff,并为每个模型单独发布评论。
面向 AI Agent(MCP)
让编码 Agent 验证自己的数据变更:
datadiffer init # scaffold datadiffer.toml, then add the server to your client
{ "mcpServers": { "datadiffer": { "command": "datadiffer", "args": ["mcp"] } } }
任何 MCP 客户端都可使用。datadiffer init 会打印服务器配置项供你粘贴,其中也包含适用于不想全局安装的客户端的 uvx 形式。
提供四种只读工具:list_connections、schema_diff、diff_summary(低成本预检)、diff_tables(完整报告)。凭据绝不会经过模型。 工具使用本地 datadiffer.toml 中的连接名称,而非 DSN。超出上限的请求会返回包含解决办法的结构化拒绝信息,让 Agent 能自行修正,而不是直接失败。
有何不同
大多数差异比较工具只回答两张表是否匹配。datadiffer 会告诉你具体改了什么、改在哪里:哪些列发生了变化,以及数据中的哪些部分集中出现了这些变化。
| 工具 | 在以下情况下改用它 |
|---|---|
| Datafold | 你需要在数据库之间核对十亿行数据、协作界面、血缘关系/影响分析,以及支持合同。 |
SQLMesh table_diff | 你已经在运行 SQLMesh,且只需在单个网关内比较差异(跨数据库比较是 Tobiko Cloud 的功能)。 |
| Recce | 你想要原生 dbt 的 PR 审查界面,而且整个工作流都基于 dbt。 |
| Google DVT | 你要在 17 种数据仓库类型之间验证迁移,并希望通过 YAML 配置进行通过/失败验证。 |
| datacompy | 你要在单个进程中比较两个 pandas/Spark/Polars DataFrame。 |
datadiffer 适用于介于这些情况之间的场景:一条命令,无需平台,可在终端、CI 或 Agent 中运行,并且会说明结果。
从 data-diff / reladiff 迁移
用途相同,参数不同:
| data-diff / reladiff | datadiffer |
|---|---|
data-diff DB1 table1 DB2 table2 | datadiffer diff <a> <b>(定位符或 --source/--target) |
-k、--key-columns | --key(可重复指定,也可用逗号分隔) |
-c、--columns | --columns |
-w、--where | --where(会验证:必须是单个布尔表达式,且不含子查询) |
--json | --format json(稳定的 schema v1) |
-l、--limit | --sample-limit |
需要了解的差异:如果省略 --key,系统会根据已声明的约束或 *_id 命名惯例推断键;筛选条件中的未知列名会导致错误,绝不会被静默忽略;退出代码 1 表示“发现差异”(2 保留给操作错误),因此 CI 可以区分两者。
**尚未移植:**用于超大型跨数据库差异比较的校验和二分 hashdiff,这是 reladiff 的主要功能;此外还包括 MySQL、Oracle、ClickHouse、Trino 及其连接器列表中的其余项。如果你现在就需要这些功能,请使用 reladiff;二分移植是我们 v0.2 路线图上的首要事项,并会注明其作者。
完整的命令映射和行为差异: docs/migrating-from-data-diff.md。
范围与限制(v0.1)
- **数据仓库:**Snowflake、Postgres、DuckDB、Parquet、CSV。接下来支持 BigQuery(v0.1.1)。
- **每次差异比较都在本地 DuckDB 中运行。**Postgres 以只读方式挂载,并在原处扫描;Snowflake 则通过 Arrow 一次性拉取所需列。两者每侧都限制为 5,000 万行和 10 GiB,因此请使用
--where缩小比较范围。将比较推送到数据仓库中执行,以及通过校验和二分解除此限制,是接下来要做的两项工作。 - Postgres 读取不会使用快照(报告会在
execution.snapshot中说明);Snowflake 拉取使用单个一致的 SELECT。 - 分段归因仅针对单列、分类数据,且只作描述。它说明的是“占比偏高”,绝不表示因果关系。
项目
MIT,无 CLA,无遥测。报告 schema已冻结为 v1,并通过契约测试,因此解析它的流水线和 Agent 可在不同版本间持续正常工作。依赖刻意保持精简:DuckDB、PyArrow、sqlglot、click、rich。
后续计划
先支持 BigQuery,然后移植校验和二分 hashdiff,让大型跨数据库差异比较不再受行数上限限制(移植时会注明 reladiff),之后再支持更多连接器。 进展记录在问题列表中。请在你需要的事项下留言,它就会优先推进。
贡献
git clone https://github.com/gauthierpiarrette/datadiffer && cd datadiffer
uv sync --group dev
uv run pytest -q # warehouse tests skip unless credentials are set
uv run ruff check .
谨此致谢相关先行工作:data-diff 和 reladiff(Erez Shinan),我们将移植其 v0.2 版校验和二分设计;Adtributor(Microsoft Research)提供归因评分;以及 DuckDB,让这一切快到平淡无奇。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。