Data Mart Concepts: Design, Types, and Implementation Patterns
A data mart is a subset of a data warehouse focused on a specific business domain, department, or subject area. While a data warehouse stores enterprise-wide data, a data mart contains only the data relevant to a particular use case â sales, marketing, finance, HR, or supply chain.
Why Data Marts Matter
Data marts solve a critical problem: query performance and access control. When every department queries the same massive warehouse, performance degrades and security becomes complex. Data marts partition data by domain, giving each team fast, focused access to exactly the data they need.
For data engineers, understanding when to build a data mart, how to design it, and how to keep it synchronized with the warehouse is a core skill.
đ¯
Interview Question: "When would you choose an independent data mart over a dependent one?" Answer: Choose independent when: (1) Domain team needs rapid prototyping without waiting for warehouse, (2) Data source is simple and well-understood, (3) Team has strong data engineering skills, (4) Budget is limited and warehouse resources are constrained.
Data Mart vs Data Warehouse
| Dimension | Data Warehouse | Data Mart |
|---|---|---|
| Scope | Enterprise-wide | Single domain/department |
| Data Volume | Petabytes | Gigabytes to Terabytes |
| Users | All analysts, data scientists | Domain-specific analysts |
| Schema | 3NF or dimensional | Star or snowflake |
| Latency | Batch (daily/hourly) | Near real-time to daily |
| Governance | Central IT | Domain team + IT |
| Cost | High | Low-Medium |
đ
Key Insight: A data warehouse is the single source of truth. Data marts are optimized views of that truth for specific business needs. Think of the warehouse as a library and data marts as curated bookshelves.
Types of Data Marts
1. Dependent Data Mart
A dependent data mart sources data from an existing data warehouse. The warehouse remains the single source of truth, and the mart is a filtered, aggregated subset.
Pros:
- Single source of truth maintained
- Consistent data across all marts
- Centralized governance and quality
Cons:
- Dependent on warehouse availability
- Latency introduced by warehouse-to-mart ETL
- Warehouse becomes a bottleneck
2. Independent Data Mart
An independent data mart sources data directly from operational systems, bypassing the warehouse entirely.
Pros:
- Fastest time to value
- No dependency on warehouse
- Domain teams have full control
Cons:
- Data silos and inconsistencies
- No single source of truth
- Duplication of effort and storage
3. Logical Data Mart
A logical data mart is a virtual view over the warehouse â no physical data movement occurs. The mart is defined as a set of views or queries that filter warehouse data for a specific domain.
Pros:
- No data duplication
- Always up-to-date (real-time)
- Minimal storage cost
Cons:
- Performance depends on warehouse query speed
- No physical separation for access control
- Complex view management
đ
Choosing the Right Mart Type:
- Dependent: When you need a dedicated, high-performance subset with SLA guarantees
- Independent: When domain teams need rapid prototyping without warehouse dependency
- Logical: When storage cost is a concern and query performance is acceptable
Data Mart Design Patterns
Star Schema Design
The most common pattern for data marts uses a star schema with a central fact table and surrounding dimension tables.
-- Sales Data Mart: Star Schema
CREATE TABLE fact_sales (
sale_id BIGINT PRIMARY KEY,
date_key INT REFERENCES dim_date(date_key),
product_key INT REFERENCES dim_product(product_key),
customer_key INT REFERENCES dim_customer(customer_key),
store_key INT REFERENCES dim_store(store_key),
quantity INT,
unit_price DECIMAL(10,2),
discount DECIMAL(10,2),
total_amount DECIMAL(12,2),
tax_amount DECIMAL(10,2),
sale_timestamp TIMESTAMP
);
CREATE TABLE dim_date (
date_key INT PRIMARY KEY,
date DATE,
year INT,
quarter INT,
month INT,
day_of_week INT,
is_weekend BOOLEAN,
fiscal_year INT
);
CREATE TABLE dim_product (
product_key INT PRIMARY KEY,
product_id VARCHAR(50),
product_name VARCHAR(200),
category VARCHAR(100),
subcategory VARCHAR(100),
brand VARCHAR(100),
unit_cost DECIMAL(10,2)
);
CREATE TABLE dim_customer (
customer_key INT PRIMARY KEY,
customer_id VARCHAR(50),
customer_name VARCHAR(200),
email VARCHAR(200),
segment VARCHAR(50),
city VARCHAR(100),
state VARCHAR(50),
country VARCHAR(50)
);
Aggregated Data Mart
For dashboards and reporting, pre-aggregate data at the mart level to avoid expensive joins at query time.
-- Pre-aggregated monthly sales by product category
CREATE TABLE agg_monthly_sales_by_category (
year INT,
month INT,
category VARCHAR(100),
total_revenue DECIMAL(12,2),
total_units INT,
avg_order_value DECIMAL(10,2),
unique_customers INT,
PRIMARY KEY (year, month, category)
);
-- Refresh strategy: Daily incremental
INSERT INTO agg_monthly_sales_by_category
SELECT
EXTRACT(YEAR FROM sale_timestamp) as year,
EXTRACT(MONTH FROM sale_timestamp) as month,
p.category,
SUM(s.total_amount) as total_revenue,
SUM(s.quantity) as total_units,
AVG(s.total_amount) as avg_order_value,
COUNT(DISTINCT s.customer_key) as unique_customers
FROM fact_sales s
JOIN dim_product p ON s.product_key = p.product_key
WHERE sale_timestamp >= CURRENT_DATE - INTERVAL '1 day'
GROUP BY 1, 2, 3;
Data Mart Refresh Strategies
| Strategy | Latency | Cost | Use Case |
|---|---|---|---|
| Full Refresh | Hours | High | Small marts, nightly batch |
| Incremental | Minutes-Hours | Medium | Large marts, daily/hourly |
| CDC-based | Seconds-Minutes | Medium-High | Real-time dashboards |
| View-based | Real-time | Low | Logical marts, ad-hoc queries |
| Micro-batch | Minutes | Medium | Near-real-time reporting |
Incremental Refresh Pattern
-- Incremental refresh: only process new/changed records
MERGE INTO fact_sales target
USING (
SELECT *
FROM stg_sales
WHERE updated_at > (SELECT MAX(last_refresh) FROM refresh_log WHERE table_name = 'fact_sales')
) source
ON target.sale_id = source.sale_id
WHEN MATCHED THEN UPDATE SET
quantity = source.quantity,
unit_price = source.unit_price,
total_amount = source.total_amount,
updated_at = source.updated_at
WHEN NOT MATCHED THEN INSERT VALUES (
source.sale_id, source.date_key, source.product_key,
source.customer_key, source.quantity, source.unit_price,
source.total_amount, source.updated_at
);
-- Log refresh
INSERT INTO refresh_log (table_name, last_refresh, records_processed)
VALUES ('fact_sales', CURRENT_TIMESTAMP, (SELECT COUNT(*) FROM stg_sales WHERE updated_at > (SELECT MAX(last_refresh) FROM refresh_log WHERE table_name = 'fact_sales')));
â ī¸
Common Mistake: Don't skip the fundamentals. Many production issues stem from misunderstanding basic concepts like data types, null handling, and idempotency. Always validate your assumptions.
Common Data Mart Scenarios
Sales Mart
- Fact: Daily sales transactions
- Dimensions: Date, Product, Customer, Store, Promotion
- Aggregations: Monthly revenue, quarterly trends, YoY growth
- Users: Sales analysts, revenue operations, executives
Marketing Mart
- Fact: Campaign performance, lead scoring
- Dimensions: Campaign, Channel, Segment, Landing Page, UTM
- Aggregations: ROI by campaign, conversion rates, cost per lead
- Users: Marketing analysts, growth team
Finance Mart
- Fact: GL entries, journal entries, budget vs actual
- Dimensions: Account, Cost Center, Entity, Period, Currency
- Aggregations: P&L by entity, budget variance, cash flow
- Users: Financial analysts, controllers, CFO
HR Mart
- Fact: Headcount, attrition, compensation
- Dimensions: Employee, Department, Manager, Location, Grade
- Aggregations: Turnover rate, comp bands, diversity metrics
- Users: HR analysts, CHRO
Supply Chain Mart
- Fact: Inventory levels, shipments, demand forecast
- Dimensions: Product, Warehouse, Supplier, Carrier, Region
- Aggregations: Fill rate, days of inventory, forecast accuracy
- Users: Supply chain analysts, operations
Data Mart Implementation on AWS
# AWS Glue job to create a Sales Data Mart from warehouse data
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
sc = SparkContext.getOrCreate()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
# Read from data warehouse (Redshift)
fact_sales = spark.read.format("jdbc") \
.option("url", "jdbc:redshift://warehouse-cluster:5439/dev") \
.option("dbtable", "public.fact_sales") \
.option("user", "admin") \
.option("password", secrets_manager.get_secret("redshift-password")) \
.load()
dim_product = spark.read.format("jdbc") \
.option("url", "jdbc:redshift://warehouse-cluster:5439/dev") \
.option("dbtable", "public.dim_product") \
.option("user", "admin") \
.option("password", secrets_manager.get_secret("redshift-password")) \
.load()
dim_customer = spark.read.format("jdbc") \
.option("url", "jdbc:redshift://warehouse-cluster:5439/dev") \
.option("dbtable", "public.dim_customer") \
.option("user", "admin") \
.option("password", secrets_manager.get_secret("redshift-password")) \
.load()
# Create Sales Data Mart: join fact with dimensions
sales_mart = fact_sales \
.join(dim_product, "product_key") \
.join(dim_customer, "customer_key") \
.select(
"sale_id", "date_key", "product_name", "category",
"customer_name", "segment", "quantity", "unit_price",
"total_amount", "sale_timestamp"
)
# Write to S3 as Parquet (data mart layer)
sales_mart.write \
.mode("overwrite") \
.partitionBy("category") \
.parquet("s3://data-lake/sales-mart/")
# Load into Redshift Sales Mart table
sales_mart.write.format("jdbc") \
.option("url", "jdbc:redshift://mart-cluster:5439/sales_mart") \
.option("dbtable", "public.fact_sales") \
.mode("overwrite") \
.save()
Best Practices
- Start with the warehouse â Build dependent marts first to maintain a single source of truth
- Align with domain teams â Each data mart should have a clear domain owner
- Use conformed dimensions â Share dimension tables across marts for consistency
- Pre-aggregate for dashboards â Create aggregate tables for common query patterns
- Implement incremental refresh â Avoid full refreshes for large marts
- Monitor query patterns â Track which queries hit the warehouse vs marts
- Enforce SLAs â Define freshness guarantees per mart
- Version your schemas â Use schema registries for mart table definitions
- Test mart data quality â Validate mart data against warehouse source
- Document lineage â Track data flow from sources â warehouse â marts
Knowledge Check
Key Takeaways
- Data marts are domain-specific subsets of data warehouses
- Three types: dependent (from warehouse), independent (from sources), logical (virtual views)
- Star schema is the standard design pattern for data marts
- Incremental refresh and CDC are critical for performance
- Each mart should have a clear domain owner and SLA
- Conformed dimensions ensure consistency across marts