Dbt starrocks models
Skill ivanshamaev/de-agent-skills/group_skills/starrocks_group_skills/dbt_starrocks_models
Профессиональные Data Engineering Agent Skills для разработки AI Agentic Data Platform
npx -y skills add ivanshamaev/de-agent-skills --skill dbt_starrocks_modelsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
dbt + StarRocks models — dbt-starrocks adapter setup (profiles.yml), all materializations (table/view/incremental/ephemeral), incremental strategies (append/insert_overwrite/unique_key merge), StarRocks-specific model config (engine/keys/partition_by/distributed_by/properties), Duplicate/Aggregate/Primary Key table DDL from dbt, partition_by with date_trunc, on_schema_change behavior
SKILL.md
9.6 KB, as published. Nobody here has run it
dbt + StarRocks Models
When to Use
- Building dbt transformation pipelines targeting StarRocks
- Defining StarRocks table DDL (key type, partitioning, distribution) via dbt model config
- Incremental models with StarRocks-native INSERT OVERWRITE or upsert strategies
- Mixing StarRocks internal tables with external Iceberg catalog tables in dbt
Installation and Setup
pip install dbt-starrocks
# dbt-starrocks requires dbt-core >= 1.5.0
profiles.yml
starrocks_project:
target: prod
outputs:
dev:
type: starrocks
host: sr-fe.internal
port: 9030
schema: dbt_dev
username: dbt_user
password: "{{ env_var('STARROCKS_PASSWORD') }}"
database: sales
connect_timeout: 10
prod:
type: starrocks
host: sr-fe-prod.internal
port: 9030
schema: sales
username: dbt_prod
password: "{{ env_var('STARROCKS_PASSWORD_PROD') }}"
database: sales
Table Materialization
dbt-starrocks generates CREATE TABLE ... AS SELECT DDL with StarRocks-specific properties.
Duplicate Key Table
-- models/staging/stg_orders_raw.sql
{{ config(
materialized='table',
engine='OLAP',
keys=['order_id', 'created_at'],
table_type='DUPLICATE',
distributed_by='HASH(order_id)',
buckets=16,
partition_by={
"field": "created_at",
"data_type": "date",
"granularity": "day"
},
properties={
"replication_num": "3",
"storage_medium": "HDD"
}
) }}
SELECT
order_id,
customer_id,
amount,
status,
created_at,
updated_at
FROM {{ source('raw', 'orders_raw') }}
Primary Key Table (Upsert)
-- models/silver/orders.sql
{{ config(
materialized='table',
engine='OLAP',
keys=['order_id'],
table_type='PRIMARY',
distributed_by='HASH(order_id)',
buckets=16,
partition_by={
"field": "created_at",
"data_type": "date",
"granularity": "month"
},
properties={
"enable_persistent_index": "true",
"replication_num": "3"
}
) }}
SELECT
order_id,
customer_id,
amount,
status,
created_at,
updated_at
FROM {{ ref('stg_orders_raw') }}
WHERE amount > 0
AND status IS NOT NULL
Aggregate Key Table
-- models/gold/orders_daily_agg.sql
{{ config(
materialized='table',
engine='OLAP',
keys=['dt', 'customer_id', 'region'],
table_type='AGGREGATE',
distributed_by='HASH(customer_id)',
buckets=8,
partition_by={
"field": "dt",
"data_type": "date",
"granularity": "month"
},
properties={
"replication_num": "3"
}
) }}
SELECT
DATE(created_at) AS dt,
customer_id,
COALESCE(c.region, 'unknown') AS region,
COUNT(*) AS order_count, -- SUM in Aggregate Key
SUM(amount) AS total_revenue,
MAX(updated_at) AS last_updated
FROM {{ ref('orders') }} o
LEFT JOIN {{ ref('dim_customers') }} c USING (customer_id)
GROUP BY DATE(created_at), customer_id, COALESCE(c.region, 'unknown')
Incremental Materialization
append Strategy
-- models/incremental/events_append.sql
{{ config(
materialized='incremental',
incremental_strategy='append',
keys=['event_id'],
table_type='DUPLICATE',
distributed_by='HASH(event_id)',
buckets=32,
partition_by={
"field": "event_ts",
"data_type": "datetime",
"granularity": "day"
}
) }}
SELECT event_id, user_id, event_type, event_ts
FROM {{ source('raw', 'events') }}
{% if is_incremental() %}
WHERE event_ts > (SELECT MAX(event_ts) FROM {{ this }})
{% endif %}
insert_overwrite Strategy (Partition Replace)
-- models/incremental/orders_daily.sql
{{ config(
materialized='incremental',
incremental_strategy='insert_overwrite',
keys=['dt', 'customer_id'],
table_type='DUPLICATE',
distributed_by='HASH(customer_id)',
buckets=8,
partition_by={
"field": "dt",
"data_type": "date",
"granularity": "day"
}
) }}
SELECT
DATE(created_at) AS dt,
customer_id,
SUM(amount) AS revenue,
COUNT(*) AS orders
FROM {{ ref('stg_orders_raw') }}
{% if is_incremental() %}
-- Only recompute partitions newer than 3 days ago (late-arriving data window)
WHERE DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 3 DAY)
{% endif %}
GROUP BY DATE(created_at), customer_id
unique_key Strategy (Upsert via Primary Key)
-- models/incremental/customers.sql
{{ config(
materialized='incremental',
incremental_strategy='unique_key',
unique_key='customer_id',
keys=['customer_id'],
table_type='PRIMARY',
distributed_by='HASH(customer_id)',
buckets=8,
properties={"enable_persistent_index": "true"}
) }}
SELECT
customer_id,
customer_name,
email,
region,
tier,
updated_at
FROM {{ source('raw', 'customers') }}
{% if is_incremental() %}
WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }})
{% endif %}
View Materialization
-- models/marts/vw_revenue_summary.sql
{{ config(materialized='view') }}
SELECT
region,
DATE_TRUNC('month', created_at) AS month,
SUM(amount) AS revenue,
COUNT(*) AS orders
FROM {{ ref('orders') }}
GROUP BY region, DATE_TRUNC('month', created_at)
Ephemeral Models (CTEs)
-- models/intermediate/int_orders_enriched.sql
{{ config(materialized='ephemeral') }}
SELECT
o.*,
c.region,
c.tier AS customer_tier
FROM {{ ref('stg_orders_raw') }} o
LEFT JOIN {{ ref('dim_customers') }} c ON o.customer_id = c.customer_id
Ephemeral models are inlined as CTEs in the parent model — no table is created.
dbt_project.yml StarRocks Config
# dbt_project.yml
name: starrocks_dbt
version: "1.0"
profile: starrocks_project
models:
starrocks_dbt:
staging:
+materialized: table
+table_type: DUPLICATE
+replication_num: "1" # dev: 1 replica
silver:
+materialized: incremental
+incremental_strategy: unique_key
+table_type: PRIMARY
gold:
+materialized: table
+table_type: AGGREGATE
Partition Configuration Options
-- Time-based partition (most common)
partition_by={
"field": "created_at",
"data_type": "date", -- or "datetime"
"granularity": "day" -- "hour", "day", "month", "year"
}
-- For expression-based partition (RANGE with VALUES LESS THAN):
-- Not directly supported in dbt-starrocks config;
-- use pre-hook to create partitions manually or dynamic partition creation:
properties={
"dynamic_partition.enable": "true",
"dynamic_partition.time_unit": "DAY",
"dynamic_partition.start": "-30",
"dynamic_partition.end": "7",
"dynamic_partition.prefix": "p",
"dynamic_partition.buckets": "16"
}
on_schema_change Behavior
{{ config(
materialized='incremental',
on_schema_change='append_new_columns' -- or 'fail', 'ignore', 'sync_all_columns'
) }}
| Value | StarRocks behavior |
|---|---|
fail | Raise error if schema changed |
ignore | Keep running, don't add new columns |
append_new_columns | Add new columns, keep existing data |
sync_all_columns | Full table rebuild (expensive) |
For Primary Key tables: sync_all_columns drops and recreates — use cautiously.
Sources and Refs
# models/sources.yml
sources:
- name: raw
database: raw_layer
schema: ingest
tables:
- name: orders_raw
loaded_at_field: ingested_at
freshness:
warn_after: {count: 2, period: hour}
error_after: {count: 6, period: hour}
- name: customers
-- Reference source
SELECT * FROM {{ source('raw', 'orders_raw') }}
-- Reference model
SELECT * FROM {{ ref('stg_orders_raw') }}
-- Reference model in another project (cross-project)
SELECT * FROM {{ ref('other_project', 'dim_products') }}
Anti-Patterns
- Not specifying
table_type— dbt-starrocks defaults to DUPLICATE; most Silver/Gold tables need PRIMARY or AGGREGATE, which requires explicit config. - Using
unique_keystrategy on Duplicate Key tables — StarRocks can't upsert on Duplicate Key; use PRIMARY KEY table for upsert. incremental_strategy='append'withon_schema_change='ignore'— new source columns silently dropped; setappend_new_columnsfor evolving sources.- No
partition_byon large incremental tables — full table scans on every incremental run; always partition by a date column. bucketstoo low for high-concurrency tables — default 16 buckets may cause hotspots; set to4 * BE countfor fact tables.- Using ephemeral models for heavy transforms — ephemeral inlines SQL as CTEs, which can produce very large query plans; materialize intermediate heavy aggregations.
References
- dbt-starrocks adapter:
github.com/StarRocks/starrocks/tree/main/contrib/dbt-connector - dbt incremental models:
docs.getdbt.com/docs/build/incremental-models - Related skills:
[[dbt-core]],[[starrocks-ddl-table-types]],[[starrocks-partitioning]],[[dbt-starrocks-performance]]