Metabase 查询型 Transforms 完整实战指南:SQL 与查询构建器的定时写回数据管道
【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase
导读
查询型 Transform(Query-based Transforms)是 Metabase 在 Data Studio 中提供的"ETL 之 T"能力:你直接用 SQL 或图形化查询构建器编写一条SELECT查询,Metabase 会按计划让数据库执行这条查询、把结果写入一张新的持久化表,并同步回 Metabase 供问题(Questions)、仪表盘和其他 Transform 复用。读完本文,你将掌握查询型 Transform 的完整生命周期——从创建、测试、保存配置,到利用 SQL 变量与 Snippet 复用查询、配置增量加载与 Merge Key(Upsert),再到将模型批量迁移为 Transform,并理解其底层执行链路。
前置条件:查询型 Transform 的可用性与依赖
在动手之前,需要先确认你的 Metabase 环境满足以下条件:
- Metabase Cloud:运行查询型 Transform 需要购买Basic transforms插件(add-on)。详见 addons.md。
- 自托管 Metabase:Basic transforms(即查询型 Transform)已包含在自托管版本中;Python Transform、Transform Inspector、可写连接(writable connections)等才需要 Pro/Enterprise 的 Advanced transforms 插件。
- 数据库支持:并非所有数据库都支持 Transform。当前支持 BigQuery、ClickHouse(仅 ClickHouse Cloud)、MySQL/MariaDB、PostgreSQL、Redshift、Snowflake、SQL Server。启用了 数据库路由 的数据库以及 Metabase 自带的 Sample Database 不支持 Transform。
- 写权限:Transform 会在你的数据库中创建并替换表,因此连接数据库的用户必须具备 create、drop、write 等相应权限,官方建议为数据库配置 可写连接(Writable connection)。
- 启用功能:需要先在 Data Studio 中启用 Transforms(网格图标 → Data Studio → Transforms,按提示启用)。
从源码看,功能的启用是严格受 Premium 特性开关控制的:
src/metabase/transforms/feature_gating.clj中enabled-source-types仅在premium-features/query-transforms-enabled?为真时把"native"(SQL)与"mbql"(查询构建器)加入可用 source type 集合,否则列表为空。这印证了文档中"查询型 Transform 需要 Basic transforms 插件"的说明。
查询型 Transform 的工作原理
查询型 Transform 的执行链路非常直观,一共五步:
- 在 Metabase 中创建一条
SELECT查询(SQL 或 图形化查询构建器); - Transform 首次运行时,由你的数据库执行该查询;
- 数据库把查询结果写入一张新表;
- 新表被同步(sync)到 Metabase;
- 之后的每次运行,数据库会用最新结果覆盖这张表——除非你配置了增量转换。
这一点与 Python Transform 有本质区别:查询型 Transform 的代码运行在数据库内部,而 Python Transform 运行在独立的执行环境(Python runner)中。
源码视角:一次查询型 Transform 的执行链路
在仓库中,查询型 Transform 的调度执行实现在 query_impl.clj 的run-mbql-transform!,其关键步骤与文档描述一一对应:
- 以归属人身份鉴权执行:手动运行以触发者(requester)身份执行,定时(cron)运行则以 Transform 的 owner(无则 creator)身份执行;执行前通过
check-source-query-permissions!校验源查询权限(手动运行被拒绝会以 403 返回)。 - 防重入:通过
try-start-unless-already-running登记 run,同一 Transform 不会并发运行;已运行时会记录 "Transform is already running" 日志。 - 写连接与执行:
driver.conn/with-write-connection建立写连接,随后调用transforms-base.i/execute-base!真正执行查询,并支持取消(cancelled?轮询)与分阶段计时埋点。 - 后处理:
complete-execution!负责表同步、事件发布等收尾工作。
更底层的查询执行在 query.clj 的run-query-transform!中完成:编译查询(compile)→ 需要时创建 schema → 调用驱动层的driver/run-transform!。它根据目标类型决定执行策略:
:table(普通表):每次运行以overwrite? true重建表;:table-incremental(增量表):无 merge key 时追加新行;设置了 merge key 时(transform-opts返回{:merge {:unique-key ... :columns ...}}),执行前会用validate-merge-unique-key!校验 merge key 必须存在于目标列中。
创建查询型 Transform
完整创建流程如下:
启用 Transforms。
进入Data studio > Transforms。
点击+ New,选择来源:
- Query builder:用图形化查询构建器写查询;
- SQL:写原生 SQL;
- Copy of existing question:复制某个已保存问题的查询——注意 Metabase 只复制查询本身,之后对原问题的修改不会影响该 Transform。
当前不支持在不同 Transform 类型之间互转(例如把查询构建器 Transform 转成 SQL Transform)。若想更换类型,需要以相同的目标表和标签新建 Transform,再删除旧的。
像平时写查询一样编写你的 Transform 查询。查询构建器用法见 Query builder,SQL 编辑器用法见 SQL 编辑器。需注意目标数据库必须支持 Transform。
点击编辑器底部的Run按钮测试查询。
重要:在编辑器中预览查询结果,并不会把结果写回数据库,可以放心反复调试。
点击右上角Save,填写 Transform 信息:
- Name(必填):Transform 名称。
- Schema(必填):目标 Schema。可以不同于源表的 Schema,直接输入新名称即可创建新 Schema。注意:只能在同一个数据库内转换数据,不能跨数据库写入。
- Table name(必填):目标表名。Metabase 会把结果写入这张表并同步。
- Folder(可选):Transform 所在的文件夹,点击可切换或新建。
- Incremental transformation(可选):是否启用增量转换。
可选:给 Transform 打标签(Tags)。标签是 Jobs(任务) 定时调度 Transform 的依据。
从实现角度,Transform 的目标表信息会被持久化到后端模型 transform.clj,执行时由 execute.clj 的execute!将声明式索引(indexes)挂到 target 上,并把full-incremental-run?决策一次性固定下来,保证整个运行期间判断稳定。
SQL Transform 中的变量:与 Snippet 组合复用
SQL Transform 支持变量({{my_variable}}),但变量只有在与 Snippet 组合时才有实际意义——因为 Transform 是定时运行的,无法在运行时弹窗让你输入参数值。典型用法是把一段含变量的完整 SQL 存成 Snippet,然后让多个 Transform 各自引用它。
官方示例:想要按周统计多张表的行数,可创建一个名为rows per week的 Snippet,内容为:
SELECT date_trunc('week', created_at) AS week, count(*) AS row_count FROM {{table}} GROUP BY week ORDER BY week这样每个 Transform 的完整 SQL 只需一行:
{{snippet: rows per week}}然后在每个 Transform 的变量面板中,把table的默认值设为各自的目标表(如orders、returns、subscriptions)。表格类变量(Table Variable)的用法详见 table variables。
这样做的好处是:当你需要调整逻辑(例如把周粒度改成日粒度),只需更新 Snippet 一次,所有引用它的 Transform 都会在下次运行时自动生效。
变量必须可选或带有默认值
Transform 中的参数必须满足以下条件之一:
- 用可选块(
[[ ]])包裹变量; - 或者提供默认值。
原因正如文档所述:Transform 由 Job 按计划调度执行,运行时没有途径向变量传值。这也是 transforms-overview.md 中对 SQL Transform 的硬性要求。
运行查询型 Transform
- 手动运行:进入Data Studio > Transforms,打开 Transform 的Runs页,点击Run。
- 定时运行:先给 Transform 打上标签,再创建定时 Job 按标签批量调度。
Transform 页面会展示每次运行(run)的日志与状态。首次运行会创建并同步目标表,之后就可以编辑该表的元数据和权限;后续运行默认会 drop 并重建表,除非启用增量模式。
运行记录同样有后端支撑:调度执行的统一入口在 execute.clj,它通过
transforms.i/execute!多方法分发(:query类型由 query_impl.clj 实现),并在数据库中登记transform_run记录以跟踪状态、支持取消。依赖排序(DAG)由 dag.clj 与 coordinated_run.clj 负责。
增量查询转换(Incremental Query Transforms)
为什么要增量
默认情况下,除首次运行外,每次运行 Metabase 都会处理输入表的全量数据,然后 drop 旧目标表、用处理结果创建新表。当数据量很大时这很浪费。将 Transform 标记为增量后,Metabase 只处理自上次运行以来新增的数据。
增量转换的前提条件
- 数据中必须有一列可供 Metabase 检查新值,即Checkpoint(检查点)列;
- Checkpoint 列的值必须递增(如自增 ID 或时间戳),Metabase 通过查找"大于已写入 checkpoint 值"的记录来判断哪些是新增数据;
- Schema 必须稳定,即表结构不会随运行而变化。
增量查询转换的工作原理
配置增量时,你需要选择一个"检查点"列。Metabase 会在后台为你的 Transform 查询自动包裹一层过滤:只保留该列值大于上次已写入 checkpoint 值的行。
如果你同时设置了 Merge Key,Metabase 会更新匹配该键的目标行,而不是追加新行——即实现 Upsert 语义。
用表变量实现增量 SQL Transform
图形化查询构建器创建的 Transform 可以直接跳过本节去标记为增量。但如果你写的是原生 SQL,就必须先把含 checkpoint 列的表替换为表变量。
假设原始查询为:
SELECT orders.id, orders.total, products.title FROM orders JOIN products on orders.product_id = products.id想基于orders.id的新值增量加载,你需要:
- 添加表变量,例如
{{orders_var}},替换FROM子句中的orders; - 在表变量设置中把
orders_var连接到orders表; - 将查询中对
orders的其他引用改为:表变量名(如果变量设置中开启了 "Emit table alias"),或你手写的别名。
改造后的查询:
SELECT orders_var.id, orders_var.total, products.title FROM {{orders_var}} JOIN products on orders_var.product_id = products.id这里orders_var在变量设置中连接到orders表,并在变量侧栏中开启了 "Emit table aliases"。查询具备表别名后,就可以在 Transform 设置中用orders.id列将其标记为增量。
源码印证:增量过滤正是注入到表变量上的。
src/metabase/transforms_base/util.clj的incremental-table-tag-name会定位"与 checkpoint 字段所在表关联的表模板标签",把增量范围过滤(inject-filters-into-table-tag)注入该表变量;若增量 SQL Transform 被编辑到丢失表标签,会返回 nil 并被视为损坏状态。checkpoint-source?则判断源是否采用 checkpoint 策略,full-incremental-run?决定何时需要全量重建(首次运行、checkpoint 字段变更、或有待应用的索引变更)。
标记 Transform 为增量
- 进入Data studio > Transforms打开 Transform 页面;
- 切换到Settings选项卡;
- 在Field to check for new values中选择源表中用于判断新记录的字段(仅部分字段符合条件,见增量转换前提);
- (可选)要更新匹配行而不是追加新行,可添加 Merge Key。
Merge Key 的注意事项
- Merge Key 引用的是目标表(Transform 输出)的列,而非源表的列;
- 如果一条记录需要多列组合才能唯一标识(如
id+region),可同时选择多个列作为 Merge Key; - Merge Key 需要一个每次写入行时都会递增的 checkpoint 字段(如
updated_at),否则 Transform 永远感知不到数据变化; - 若目标表已存在,可从其列列表中挑选;若尚未运行过(没有表),则需手动输入数据库中的真实列名(可能与显示名不同),每输入一个按逗号或回车分隔。
全量重处理(Reprocess all data)
增量 Transform 运行后,Settings页会显示Last processed [checkpoint field]及已写入的最高 checkpoint 值——这正是后续运行断点续传的依据。如需清空该值、全量重建目标表,点击Reprocess all data,下次运行(手动或按计划)会从头处理所有行。更换 checkpoint 字段也会重置该值,使 Transform 下次运行时全量重建。
将模型转换为 Transform
如果你有想迁移为 Transform 的模型(Model),Metabase 支持批量转换。转换过程中 Metabase 会:
- 基于模型的查询创建新 Transform;
- 运行 Transform,在数据库中生成输出表;
- 把所有曾使用该模型的问题、仪表盘及其他内容,替换为 Transform 的输出表;
- 将原模型转换为一个普通问题。
前提:必须是管理员,且模型的数据库支持 Transform。
操作步骤:
- 先阅读 Replace data sources(替换数据源) 的概述与限制说明;
- 打开Data Studio,在侧栏选择Transforms;
- 点击Tools > Migrate models;
- 找到要转换的模型并点击打开详情面板,面板会显示模型名称、数据库、所在集合以及依赖它的内容列表;
- 点击Convert to a transform;
- 填写 Transform 设置(同创建查询型 Transform);
- 再次点击Convert to a transform确认。
Metabase 会在后台执行转换,屏幕底部有进度指示。
失败与回滚语义:
- 若 Transform 运行失败,Metabase 会中止并保持模型原样,不替换任何内容;
- 若 Transform 运行成功但随后的源替换失败,Transform 及其输出表会保留,模型保持不变,你可以用 Replace data sources 手动把剩余内容从模型指向 Transform 输出表;
- 转换完成后,所有原本查询模型的内容都会改为查询 Transform 输出表,原模型退化为普通问题。
权限提醒:新建的表会使用默认权限,不会继承模型的权限。更稳妥的做法是:先手动创建并运行 Transform、配置好表权限,再用 Replace data sources 把模型替换为 Transform 输出表。
常见问题与边界
- 无法跨数据库写入:目标 Schema 可以与源不同,但源与目标必须在同一数据库内。
- Transform 类型不可互转:查询构建器 ↔ SQL ↔ Python 之间不能直接转换,需新建并删除旧对象。
- 编辑定义的影响:修改 Transform 查询后,下次运行(手动或定时)即生效;若新查询不再输出某个列,下游依赖该列的问题会报错。
- 更换目标表:在 Settings 的Change target操作中,选择保留或删除旧目标表(删除不可撤销);基于旧目标表构建的问题不会自动迁移到新表。
- 与其他 Transform 的依赖:查询型 Transform 可以引用其他 Transform 的目标表,也可引用 Metabase 问题和模型。Metabase 会追踪依赖(
src/metabase/transforms/dag.clj维护 DAG),按合理顺序执行:若 Transform B 依赖 A 创建的表,Metabase 先跑 A 再跑 B;Job 运行时会自动补跑"尚未更新"的依赖。 - 与模型持久化的区别:Transform 需要分析师具备 Transform 权限、可自定义目标 Schema/表名、支持的数据库更多、且可用 Python 编写;模型持久化未来将被 Transform 取代。
延伸阅读
- Transforms 总览:启用、权限、支持的数据库、版本控制与模型对比
- Jobs 与 Runs:标签、定时调度、依赖跳过与失败通知
- Python Transforms:Python 型 Transform 的写法与执行环境
- Transform Inspector:分析数据流、Join 行为与列分布
- 后端实现参考:query_impl.clj(调度执行)、query.clj(查询执行与合并策略)、util.clj(增量/checkpoint/merge 判定)
【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考