
Data Warehouse Engineer
- 29 installs
- 7 repo stars
- Updated May 20, 2026
- daemon-blockint-tech/agentic-enteprises-skill
Designs data warehouses: star/snowflake schemas, dimensional modeling, SQL optimization, ETL/ELT patterns, and partitioning strategies.
About
An agent skill for designing and implementing data warehouses, covering star/snowflake schemas, dimensional modeling, SQL optimization, ETL/ELT patterns, and warehouse-specific features for Snowflake, BigQuery, and Redshift. A developer uses it when designing schemas, optimizing queries, or building ETL pipelines.
- Dimensional modeling and partitioning strategies
- Warehouse-specific features for Snowflake, BigQuery, and Redshift
Data Warehouse Engineer by the numbers
- 29 all-time installs (skills.sh)
- Ranked #513 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/daemon-blockint-tech/agentic-enteprises-skill --skill data-warehouse-engineerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 29 |
|---|---|
| repo stars | ★ 7 |
| Last updated | May 20, 2026 |
| Repository | daemon-blockint-tech/agentic-enteprises-skill ↗ |
What it does
Designs data warehouses: star/snowflake schemas, dimensional modeling, SQL optimization, ETL/ELT patterns, and partitioning strategies.
Files
Data Warehouse Engineer
Overview
Design and implement data warehouses. This skill covers star/snowflake schemas, dimensional modeling, SQL optimization, ETL/ELT patterns, partitioning strategies, and warehouse-specific features (Snowflake, BigQuery, Redshift).
Features
- Dimensional modeling: star schema, snowflake schema, fact/dimension table design
- SQL optimization: query tuning, indexing, materialized views, partition pruning
- ETL/ELT patterns: incremental loads, CDC, data quality checks, error handling
- Partitioning strategies: range, list, hash, and composite partitioning
- Warehouse-specific features: Snowflake clustering, BigQuery partitioning, Redshift sort keys
Usage
1. Identify the user's warehouse need (schema design, SQL optimization, ETL, or partitioning) 2. Follow the corresponding workflow below 3. Produce structured outputs: ER diagrams, optimized SQL queries, ETL pipeline designs, or partitioning plans
Examples
- User: "Design a star schema for sales"
Agent: Runs Dimensional Modeling workflow, identifies fact table (sales), dimension tables (date, product, customer, region), creates ER diagram
- User: "Optimize a slow query"
Agent: Runs SQL Optimization workflow, analyzes execution plan, recommends indexes, rewrites query with CTEs
- User: "Set up incremental loads"
Agent: Runs ETL/ELT workflow, designs CDC pattern, implements watermark-based extraction, adds data quality checks
When to Use
- Diagnosing slow warehouse SQL and improving partition, cluster, or join plans
- Designing star/snowflake schemas, SCDs, and fact/dimension tables
- Building idempotent, incremental, or CDC ETL with observability and quality checks
- Comparing Snowflake, BigQuery, Databricks, or Redshift syntax and trade-offs
When NOT to Use
- Enterprise-wide data mesh, governance pillars, or compliance program design → use
data-architect - BI dashboard layout, chart selection, or stakeholder-facing metrics → use
bi-analyst - dbt layers, mart tests, exposures, and analytics engineering workflows → use
analytics-data-engineer - ML feature stores, model serving, or experiment analysis → use
data-scientist - On-call leadership for the full data platform org → use
data-system-ops-lead - Application runtime profiling, API load tests, OLTP latency SLOs → use
performance-engineer
Core Workflows
1. Query Performance Diagnostics
Step-by-step checklist (follow exactly):
1. Identify the slow query and capture its execution plan 2. Check for full table scans; add partitioning or clustering if present 3. Verify join order: smallest/ most selective table first when possible 4. Look for selective predicates pushed to the partition/clustering key 5. Check for redundant aggregations or exploding joins (many-to-many without bridge) 6. Compare estimated vs actual rows; cardinality misestimates indicate stale stats 7. Consider materialized views or pre-aggregated summary tables for repeated patterns 8. Document the before/after execution time and cost
2. Data Model Design
Decision tree:
- Need fast aggregations and simple joins? → Star schema
- Need normalized dimensions to reduce redundancy? → Snowflake schema
- Tracking historical changes in dimensions? → Slowly Changing Dimension (SCD) type 2
- Event-based data with high volume? → Fact table with partitioning on event date
- Need real-time-ish analytics? → Streaming ingestion + micro-batch fact tables
3. ETL Pipeline Design
Essential properties every pipeline must satisfy:
| Property | Pattern |
|---|---|
| Idempotency | MERGE / INSERT OVERWRITE with deterministic keys |
| Incrementality | WHERE updated_at > (SELECT MAX(updated_at) FROM target) |
| Atomicity | Wrap multi-step loads in a transaction or use staging → swap pattern |
| Observability | Row counts, null rates, freshness checks logged per run |
| Error handling | Dead-letter queue for bad records; fail loudly on schema drift |
4. Platform Selection Quick Reference
| Need | Best Fit |
|---|---|
| Semi-structured JSON, auto-scaling | Snowflake |
| Tight GCP integration, nested/repeated fields | BigQuery |
| ML + Spark + SQL in one lakehouse | Databricks |
| AWS-native, predictable cost at scale | Redshift |
Bud1 tslg1Scompassetslg1ScompassetsmoDDblob�y�k��AassetsmodDblob�y�k��Aassetsph1Scomp
referenceslg1Scomp.�
referencesmoDDbloba5y�k��A
referencesmodDbloba5y�k��A
referencesph1Scomp@scriptslg1ScompscriptsmoDDblob�=y�k��AscriptsmodDblob�=y�k��Ascriptsph1Scomp @� @� @� @E DSDB `� @� @� @Data Modeling
Dimensional Modeling
Star Schema
- One central fact table surrounded by denormalized dimension tables
- Best for: query simplicity, fast aggregations, BI tool compatibility
Snowflake Schema
- Dimensions normalized into sub-dimensions
- Best for: reducing storage redundancy, complex hierarchies
- Trade-off: more joins, slightly slower queries
Fact Table Design
| Property | Guidance |
|---|---|
| Grain | One row per business event (e.g., one order line item) |
| Degenerate dimensions | Store dimension-like attributes directly (order_number, transaction_id) |
| Foreign keys | Surrogate integer keys (not natural keys) for stability |
| Partition key | Event date or ingestion date for time-series data |
| Measures | Additive (sales_amount), semi-additive (balance), non-additive (unit_price) |
Dimension Table Patterns
Slowly Changing Dimension (SCD)
| Type | Behavior | Implementation |
|---|---|---|
| Type 0 | Fixed, never changes | Static reference data |
| Type 1 | Overwrite in place | Simple UPDATE; loses history |
| Type 2 | Track history with effective dates | Add valid_from, valid_to, is_current columns |
| Type 3 | Track limited history (previous + current) | Add previous_value column |
| Type 4 | Mini-dimension for high-change attributes | Separate table for volatile attributes |
SCD Type 2 SQL Template:
-- Close existing row
UPDATE dim_customer
SET valid_to = CURRENT_DATE, is_current = FALSE
WHERE customer_id = :id AND is_current = TRUE;
-- Insert new current row
INSERT INTO dim_customer (customer_id, name, region, valid_from, valid_to, is_current)
VALUES (:id, :name, :region, CURRENT_DATE, '9999-12-31', TRUE);Junk Dimensions
Combine low-cardinality flags into a single dimension to reduce fact table width.
Bridge Tables
Use for many-to-many relationships (e.g., patient → multiple diagnoses).
Naming Conventions
| Object | Convention | Example |
|---|---|---|
| Fact tables | f_<event> | f_order_line |
| Dimension tables | d_<entity> | d_customer |
| Date dimension | d_date | Standard calendar |
| Aggregate tables | agg_<grain>_<metric> | agg_daily_revenue |
| Staging tables | stg_<source>_<entity> | stg_shopify_orders |
Data Vault (Alternative)
Use when:
- Source systems change frequently
- Need full auditability and traceability
- Agility > query performance (sacrifice some speed for flexibility)
Components: Hubs (business keys), Links (relationships), Satellites (attributes).
ETL Pipeline Patterns
Incremental Load Strategies
1. Timestamp-Based
INSERT INTO target
SELECT * FROM source
WHERE updated_at > (SELECT MAX(updated_at) FROM target);- Pros: Simple, widely supported
- Cons: Misses hard deletes; clock skew risk
2. Change Data Capture (CDC)
| Method | Trigger | Best For |
|---|---|---|
| Debezium / Fivetran | Database binlog / WAL | Real-time, low-latency |
Audit columns (created_at, updated_at) | Application writes | Simple implementations |
Hash/compare (MD5 of row) | Scheduled batch | Detecting any change including deletes |
| DELETE + full INSERT | Scheduled batch | Small tables (<10M rows) |
CDC with Hash (Delete Detection)
-- Stage current source hash
CREATE TEMP TABLE staging AS
SELECT pk, MD5(CONCAT(col1, col2, col3)) AS row_hash FROM source;
-- Find deletes
SELECT pk FROM target_hash LEFT JOIN staging USING(pk) WHERE staging.pk IS NULL;
-- Find inserts/updates
SELECT s.pk, s.row_hash FROM staging s
LEFT JOIN target_hash t ON s.pk = t.pk
WHERE t.pk IS NULL OR s.row_hash != t.row_hash;3. Streaming Ingestion
- Kafka → Snowpipe / BigQuery Streaming API / Delta Live Tables
- Use for: event data, clickstreams, IoT telemetry
Idempotency Patterns
| Pattern | SQL Example |
|---|---|
| INSERT OVERWRITE | INSERT OVERWRITE TABLE target PARTITION (dt) SELECT ... |
| MERGE / UPSERT | MERGE INTO target USING source ON target.pk = source.pk WHEN MATCHED UPDATE ... WHEN NOT MATCHED INSERT ... |
| Delete + Insert (transactional) | BEGIN; DELETE FROM target WHERE dt = '2024-01-01'; INSERT INTO target ...; COMMIT; |
| Staging + Swap | Load into target_staging, then ALTER TABLE target SWAP WITH target_staging (Snowflake) |
Orchestration & Scheduling
dbt Patterns
{{ config(materialized='incremental', unique_key='order_id') }}- Use
is_incremental()macro to branch logic - Tests:
not_null,unique,accepted_values,relationships
Airflow Patterns
- One DAG per source system or business domain
- Use
TaskFlowAPI for simple pipelines - Sensor tasks to wait for upstream data readiness
on_failure_callbackto alert Slack/PagerDuty
Data Quality Checks
| Check | Implementation |
|---|---|
| Row count sanity | ABS(source_count - target_count) / source_count < 0.01 |
| Null rate | COUNT(*) FILTER (WHERE col IS NULL) / COUNT(*) < threshold |
| Freshness | MAX(event_time) > NOW() - INTERVAL '1 hour' |
| Referential integrity | Left join fact to dim; flag orphans |
| Distribution skew | MAX(bucket_count) / AVG(bucket_count) < 10 |
| Duplicate keys | SELECT key, COUNT(*) FROM table GROUP BY key HAVING COUNT(*) > 1 |
Error Handling
- Schema drift: Versioned schemas; fail pipeline on unexpected column additions
- Bad records: Dead-letter queue table with
reject_reason,raw_payload,loaded_at - Partial failures: Transaction wrap or staging table with rollback capability
- Retries: Exponential backoff for transient API/database errors
Backfilling
- Always backfill with the same idempotent logic as incremental loads
- Use
BETWEENdate ranges in small chunks to avoid resource exhaustion - For large backfills: disable indexes/constraints, load, rebuild
Platform Cheatsheets
Data Type Mapping
| Concept | Snowflake | BigQuery | Databricks | Redshift |
|---|---|---|---|---|
| Timestamp | TIMESTAMP_NTZ / TIMESTAMP_LTZ | TIMESTAMP | TIMESTAMP / TIMESTAMP_NTZ | TIMESTAMP |
| Auto-increment | SEQUENCE or IDENTITY | Not native; use GENERATE_UUID() | GENERATED ALWAYS AS IDENTITY | IDENTITY(1,1) |
| Variant/JSON | VARIANT | JSON / STRUCT / ARRAY | VARIANT (Spark) | SUPER (RA3) |
| Decimal | NUMBER(38,0) | NUMERIC / BIGNUMERIC | DECIMAL(38,0) | DECIMAL(38,0) |
| Large text | VARCHAR(16777216) | STRING | STRING | VARCHAR(MAX) |
Query Syntax Differences
| Task | Snowflake | BigQuery | Databricks | Redshift |
|---|---|---|---|---|
| Limit rows | LIMIT n | LIMIT n | LIMIT n | LIMIT n |
| Sample | SAMPLE (n) | TABLESAMPLE SYSTEM (n PERCENT) | TABLESAMPLE (n PERCENT) | Not native |
| Current timestamp | CURRENT_TIMESTAMP() | CURRENT_TIMESTAMP() | current_timestamp() | GETDATE() / SYSDATE |
| Date diff | DATEDIFF(day, start, end) | DATE_DIFF(end, start, DAY) | datediff(day, start, end) | DATEDIFF(day, start, end) |
| Cast | ::TYPE or CAST(x AS TYPE) | CAST(x AS TYPE) | CAST(x AS TYPE) | CAST(x AS TYPE) |
| String concat | `\ | \ | ` | `\ |
| Qualify | QUALIFY ROW_NUMBER() ... | QUALIFY supported | QUALIFY supported | Not native; use CTE + WHERE |
| Time travel | AT ({ TIMESTAMP => ... }) | SYSTEM_TIME AS OF | Not native (use Delta time travel VERSION AS OF) | Not native |
Loading Data
| Platform | Bulk Load Command | File Formats |
|---|---|---|
| Snowflake | COPY INTO table FROM @stage | CSV, JSON, Parquet, Avro, ORC |
| BigQuery | LOAD DATA INTO table FROM FILES or bq load | CSV, JSON, Parquet, Avro |
| Databricks | COPY INTO or Auto Loader | CSV, JSON, Parquet, Delta |
| Redshift | COPY table FROM 's3://bucket/file' | CSV, JSON, Parquet, Avro, ORC |
Cost Gotchas
| Platform | Watch Out For |
|---|---|
| Snowflake | Warehouse auto-resume; idle timeouts; compute cost per second |
| BigQuery | On-demand pricing per bytes scanned; use INFORMATION_SCHEMA.JOBS to audit |
| Databricks | DBU consumption; auto-scaling clusters can spike; photon vs non-photon |
| Redshift | Concurrency scaling charges; RA3 vs DC2 node types; spectrum external queries |
Security
| Platform | Role-Based Access | Column-Level | Row-Level |
|---|---|---|---|
| Snowflake | GRANT on roles | Dynamic Data Masking | Row Access Policies |
| BigQuery | IAM + Dataset ACL | Policy Tags / Column ACL | Row-level security views |
| Databricks | Unity Catalog | Unity Catalog column masks | Row filters in Unity Catalog |
| Redshift | GRANT + role hierarchy | Not native (use views) | RLS POLICY (Redshift RLS) |
Useful System Tables
| Platform | Query History | Table Sizes | Users/Roles |
|---|---|---|---|
| Snowflake | SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY | SNOWFLAKE.ACCOUNT_USAGE.TABLE_STORAGE_METRICS | SNOWFLAKE.ACCOUNT_USAGE.USERS |
| BigQuery | INFORMATION_SCHEMA.JOBS | __TABLES__ / INFORMATION_SCHEMA.TABLE_STORAGE | INFORMATION_SCHEMA.OBJECT_PRIVILEGES |
| Databricks | system.information_schema + Spark UI | DESCRIBE HISTORY / OPTIMIZE | Unity Catalog information_schema |
| Redshift | STL_QUERY / STV_INFLIGHT | SVV_TABLE_INFO | PG_USER / SVV_ROLE_GRANTS |
SQL Optimization & Query Tuning
Execution Plans
Capture and read execution plans per platform:
| Platform | Command | Key fields to inspect |
|---|---|---|
| Snowflake | EXPLAIN USING JSON | partitions_scanned, bytes_scanned, operator_statistics |
| BigQuery | EXPLAIN or Query Plan in UI | rows read, slot time, stages, shuffle |
| Databricks | EXPLAIN EXTENDED or Spark UI | Scan parquet, Exchange, SortMergeJoin vs BroadcastHashJoin |
| Redshift | EXPLAIN or SVL_QUERY_REPORT | XN Seq Scan vs XN Bitmap Scan, DS_DIST_NONE vs DS_DIST_ALL_NONE |
Common Anti-Patterns & Fixes
| Anti-Pattern | Fix | Platform Notes |
|---|---|---|
SELECT * in production | Project only needed columns | All — reduces IO significantly |
Functions on indexed columns (WHERE UPPER(email) = ...) | Use case-insensitive collation or computed column | BigQuery: COLLATE; Snowflake: COLLATE |
| Filtering on a non-partitioned date column | Partition by date; use WHERE event_date >= '2024-01-01' | Redshift: SORTKEY; BigQuery: partition by DATE |
| Many-to-many join without aggregation | Add bridge table or pre-aggregate | All |
| Correlated subquery in SELECT | Rewrite as JOIN or use LATERAL / CROSS APPLY | Databricks/Redshift prefer JOIN |
| Casting inside a JOIN predicate | Cast once in a CTE or materialized stage | All — prevents index usage |
Partitioning & Clustering
| Platform | Partitioning | Clustering / Sorting |
|---|---|---|
| Snowflake | Micro-partitions (automatic) | CLUSTER BY (col1, col2) |
| BigQuery | PARTITION BY DATE(timestamp) | CLUSTER BY customer_id |
| Databricks | PARTITIONED BY (date_col) | ZORDER BY (col) via OPTIMIZE |
| Redshift | DISTSTYLE KEY DISTKEY(col) + SORTKEY(col) | Compound or interleaved SORTKEY |
Materialization Patterns
- Materialized View: Platform-native auto-refresh (limited flexibility)
- Manual Summary Table: Full control; refresh via MERGE or INSERT OVERWRITE
- Pre-join: Flatten star schema into wide table for specific dashboards
Use manual summary tables when:
- Refresh logic is complex (e.g., SCD type 2 dimensions)
- You need incremental refreshes with custom business rules
- Platform MV limitations prevent required joins
Cost Optimization
| Technique | When |
|---|---|
| Short-circuit with partitions | Always filter on partition key first |
| Avoid cross-joins | Cartesian products explode cost; verify with row counts |
| Cache repeated CTEs | Materialize intermediate results in temp tables |
| Limit large sorts | Use approximate algorithms (APPROX_COUNT_DISTINCT, HyperLogLog) |