DBT 高级特性实战


索引

ClickZetta 支持三种索引类型,在 dbt 模型的

config
config
里声明,建表后自动创建:

索引类型适用场景示例查询
bloomfilter
bloomfilter
等值查询(
WHERE col = 'xxx'
WHERE col = 'xxx'
WHERE order_id = 'abc123'
WHERE order_id = 'abc123'
inverted
inverted
全文搜索(
match_all
match_all
match_any
match_any
函数)
WHERE match_all(status, 'completed')
WHERE match_all(status, 'completed')
vector
vector
向量相似度搜索
ORDER BY cosine_distance(embedding, [...])
ORDER BY cosine_distance(embedding, [...])

为什么需要索引?

ClickZetta 的数据以 Parquet 文件存储在对象存储上。没有索引时,

WHERE order_id = 'abc123'
WHERE order_id = 'abc123'
需要扫描所有文件的所有行。Bloomfilter 索引在每个文件上维护一个紧凑的概率数据结构,查询时先检查索引——如果索引说"这个文件里肯定没有这个值",就直接跳过整个文件,大幅减少 I/O。

倒排索引则是为全文搜索场景设计的,它把文本分词后建立词→行的映射,

match_all(col, 'keyword')
match_all(col, 'keyword')
可以直接定位到包含关键词的行,而不需要扫描全表。

向量索引用于 AI 场景,支持对高维向量做近似最近邻搜索(ANN),比暴力计算所有向量的距离快几个数量级。

Bloomfilter + 倒排索引

{{ config( materialized='table', indexes=[ {'type': 'bloomfilter', 'columns': ['order_id']}, {'type': 'bloomfilter', 'columns': ['customer_id']}, {'type': 'inverted', 'columns': ['status']} ] ) }} select order_id, customer_id, amount, status, region, dt from {{ ref('stg_orders') }}

每个索引是一个字典,

type
type
指定类型,
columns
columns
指定列(目前每个索引只支持单列)。dbt 在
CREATE TABLE
CREATE TABLE
完成后自动执行
CREATE INDEX
CREATE INDEX
语句,不需要手动操作。

向量索引

{{ config( materialized='table', indexes=[ { 'type': 'vector', 'columns': ['embedding'], 'distance_function': 'cosine_distance', 'scalar_type': 'f32' } ] ) }} select id, embedding from {{ ref('vector_source') }}

向量索引需要额外指定

distance_function
distance_function
(支持
cosine_distance
cosine_distance
l2_distance
l2_distance
dot_product
dot_product
等)和
scalar_type
scalar_type
f32
f32
f16
f16
b1
b1
)。


Clone(零拷贝克隆)

Clone 是 ClickZetta 的零拷贝克隆能力——克隆一张表不需要复制数据,只复制元数据,创建速度极快,也不占用额外存储。

为什么零拷贝?

ClickZetta 采用存算分离架构,数据以 Parquet 文件存储在对象存储(OSS/S3/COS)上,表的元数据(哪些文件属于这张表)存储在元数据服务里。Clone 操作只是在元数据层面创建一个新的"指针",指向同一批 Parquet 文件,不需要复制任何数据文件。克隆后的表和源表共享底层文件,直到其中一方发生写入操作时才会产生新文件(Copy-on-Write)。

这意味着克隆一张 1TB 的表和克隆一张 1KB 的表耗时相同,都是毫秒级。

基本克隆

{{ config( materialized='clone', source=target.database ~ '.' ~ target.schema ~ '.fct_orders_partitioned' ) }}

source
source
指定被克隆的表,
target.database ~ '.' ~ target.schema
target.database ~ '.' ~ target.schema
是 Jinja 拼接当前连接的 database 和 schema。

典型用途:CI/CD 环境隔离——在测试环境快速克隆生产表,测试完成后删除,不影响生产数据。

Time Travel 克隆

克隆到历史时间点,用于数据误操作恢复或历史版本对比:

{{ config( materialized='clone', source=target.database ~ '.' ~ target.schema ~ '.fct_orders_partitioned', at_timestamp="current_timestamp() - interval 1 hours" ) }}

几点注意事项(来自 dbt-clickzetta examples 的注释):

  • 时间点必须在
    data_retention_days
    data_retention_days
    保留周期内(最长 90 天)
  • 源表在该时间点必须已存在
  • 时间戳使用服务器时区(通常为 UTC+8)

常用时间表达式:

current_timestamp() - interval 1 hours -- 1 小时前 current_timestamp() - interval 1 days -- 1 天前 '2024-01-05 15:00:00' -- 固定时间点 date_sub(current_date(), 1) -- 昨天


物化视图

物化视图预计算并物理存储查询结果,适合高频固定聚合查询加速。与 Dynamic Table 的区别:物化视图需要手动刷新,Dynamic Table 自动按周期刷新。

{{ config(materialized='materialized_view') }} select region, dt, count(order_id) as order_count, sum(amount) as revenue from {{ ref('stg_orders') }} where status = 'completed' group by region, dt

选型建议

  • 需要自动持续刷新 → 用 Dynamic Table
  • 查询模式固定、可以接受手动刷新 → 用物化视图
  • 不需要物理存储、只需逻辑封装 → 用普通视图

VCluster per-model

ClickZetta 支持为单个模型指定计算集群,实现不同类型模型的资源隔离:

{{ config( materialized='dynamic_table', refresh_interval='1 HOUR', refresh_vc='default_ap' -- dynamic_table 专用:指定刷新任务使用的集群 ) }} select ... from {{ ref('stg_orders') }}

也可以在

dbt_project.yml
dbt_project.yml
里按目录批量配置(
vcluster
vcluster
是通用的执行集群,
refresh_vc
refresh_vc
是 dynamic_table 专用的刷新集群):

models: my_project: marts: +vcluster: default_ap # 聚合查询模型用分析型集群 staging: +vcluster: default # ETL 写入模型用通用型集群

集群类型选型

场景推荐集群类型原因
incremental 写入、seed通用型(
DEFAULT
DEFAULT
支持自动小文件合并,适合频繁写入
大规模聚合查询、Dynamic Table 刷新分析型(
DEFAULT_AP
DEFAULT_AP
针对大规模扫描和聚合优化
数据同步、CDC同步型(
PORTAL_SYNC_VC
PORTAL_SYNC_VC
专为数据集成场景设计

Grants

dbt 支持在模型运行后自动授权,让指定角色可以查询该表:

{{ config( materialized='table', grants={ 'select': [var('grant_role', 'workspace_analyst')] } ) }} select region, count(order_id) as order_count, sum(amount) as revenue from {{ ref('stg_orders') }} where status = 'completed' group by region

var('grant_role', 'workspace_analyst')
var('grant_role', 'workspace_analyst')
使用 dbt 变量,默认授权给
workspace_analyst
workspace_analyst
角色,也可以在运行时覆盖:

dbt run --vars '{"grant_role": "my_role"}' --select regional_revenue_with_grants


组合使用示例

以下是一个综合使用多个高级特性的模型:

{{ config( materialized='incremental', incremental_strategy='delete+insert', unique_key='order_id', vcluster='default', -- ETL 写入用通用型集群 indexes=[ {'type': 'bloomfilter', 'columns': ['order_id']}, {'type': 'bloomfilter', 'columns': ['customer_id']}, {'type': 'inverted', 'columns': ['status']} ], grants={ 'select': ['workspace_analyst'] } ) }} select order_id, customer_id, amount, status, region, dt, updated_at from {{ ref('stg_orders') }} {% if is_incremental() %} where updated_at > (select max(updated_at) from {{ this }}) {% endif %}

这个模型:

  • delete+insert
    delete+insert
    策略增量更新,在通用型集群(
    default
    default
    )上运行
  • 建表后自动创建 bloomfilter 和倒排索引
  • 运行后自动授权给
    workspace_analyst
    workspace_analyst
    角色

相关文档

联系我们
预约咨询
微信咨询
电话咨询