Click a heading to bookmark it

Data Warehouses and Analytics - Study Notes

Slowly Changing Dimensions (SCDs)

Introduction and Purpose

Slowly Changing Dimensions (SCDs) are a core technique in data warehousing that enables the preservation of historical integrity in analytical systems. Unlike operational databases that overwrite past information, data warehouses use SCDs to meticulously track every change to descriptive attributes within dimension tables (e.g., Customer, Product). This allows analytical queries to reflect past states accurately, enabling trend analysis, performance measurement, and strategic decision-making based on complete history.

SCDs transform data warehouses into a living history book, providing robust business intelligence. The foundation is historical integrity, managed through specific SCD strategies (Type 1 overwrite, Type 2 versioning, Type 3 partial), which ultimately deliver analytical value for informed decision-making.

What are Slowly Changing Dimensions?

Different types of SCDs offer varying levels of historical preservation and complexity. The primary types are:

SCD Type 0

Once set, ignore any changes; these values are considered immutable. For example, in a Customer dimension, attributes like FirstDesignation, JoinedDate, and DateFirstPurchase would use Type 0 — they are never updated.

SCD Type 1

Simply overwrite data when changes occur. Used for filling in missing/null values or correcting errors where historical context is not critical (e.g., updating AnnualIncome).

SCD Type 2

The most popular method — history is preserved by adding new rows. Uses additional columns: StartDate, EndDate, and IsCurrent flag.

Key columns for SCD 1 & 2:

SCD Type 3

History kept in additional columns. Simple but limited to the last version only.

SCD Type 4 — Rapidly Changing Dimensions

Designed for attributes that change very frequently, which would create an explosion of rows in Type 2. Attributes that change rapidly (e.g., customer risk type updated monthly) are moved to a separate mini-dimension table.

SCD Type 6

A hybrid combining Type 2 and Type 3 — uses both rows and columns for enhanced analysis.

Load Process

MERGE example for SCD Type 2 (simplified): Use a MERGE statement to update existing current records (set end date and iscurrent to 'No') and insert new rows for changes.

Additional Recommendations

Conclusion

Type 1 and Type 2 are the most commonly used. SCDs are fundamental for preserving historical data in data warehouses, ensuring accurate time-based analysis. Choosing the appropriate type (e.g., Type 2 for full history, Type 6 for combined row/column tracking) is crucial for meeting specific analytical requirements. Proper implementation ensures data integrity, supports complex business intelligence, and facilitates informed decision-making over time.


Handling Late-Arriving Dimensions

Problem Definition

In a star schema, every foreign key in a fact table must join to its associated dimension. However, new fact data may arrive before the corresponding dimension records are available (late-arriving dimensions), causing join failures. This can happen due to:

Three common solutions exist:

  1. Put fact records into "suspense" (process now and hydrate later).

  2. Use a special <unknown> dimension record.

  3. Detect early-arriving facts and retry (reconciliation pattern).

Solution 1: Process Now and Hydrate Later

How it works: Incoming fact data is stored in a dedicated "suspense" or "retry" table with default values in dimension columns. A separate hydration process periodically tries to update missing dimension keys.

Limitations:

Solution 2: Using a Special <unknown> Dimension

Widely used for optional relationships. For example, in an aviation bus matrix, a dim_delay_reason dimension might contain a "N/A" record for flights that were not delayed. Similarly, for late-arriving dimensions, create a specially-created dimension record with description "Not known yet".

Solution 3: Early Detection and Reconciliation Pattern (Recommended)

Detect early-arriving facts (facts for which the corresponding dimension has not arrived yet), put them on hold, and retry after a period until they are processed or exhaust retries. This ensures data quality and consistency.

Reconciliation pattern using streaming data (Kafka, Spark, Delta Lake):

  1. Read from source: Read new events (e.g., from Kafka).

  2. Transform and join: Transform facts and left-join to dimension tables.

  3. Flag retryable: If dimension missing, flag the fact record as is_retryable = true.

  4. Write errors: Write retryable records to a streaming_pipeline_errors delta table (append-only).

  5. Merge valid: MERGE valid (non-retryable) records into the target delta table.

  6. Reconciliation: A scheduled batch job consolidates multiple failed retries for the same event into a single row in a reconciliation table, with updated retry count and status.

  7. Retry loop: The streaming pipeline reads from the reconciliation table (UNION with new Kafka data) and retries the join. If still missing, write back to errors; if resolved, proceed to merge.

Key advantages:

Example: Login Events Pipeline

Best practices:

Conclusion

The reconciliation pattern is easy to plug into existing pipelines with a small boilerplate framework. It provides automated retries with built-in alerting and monitoring, ensuring data quality without manual intervention.


Columnar Data Formats

Columnar vs Row-Oriented Storage

The fundamental difference is data layout on disk.

Key differences:

Popular Columnar Storage Formats

When to Choose Columnar Storage

Compression Techniques in Column Stores

Because identical values are often adjacent, columnar storage compresses exceptionally well:

Performance Edge of Columnar Databases

Challenges and Compromises

Delta Lake vs. Parquet

Delta Lake is a storage layer that builds on Parquet, adding critical features.

Parquet:

Delta Lake:

When to use Parquet instead of Delta Lake:

Conclusion: Delta Lake Wins Almost Always

For any production data system, especially in the cloud, Delta Lake provides reliability, performance, and operational simplicity that plain Parquet cannot match. It makes common operations (dropping/renaming columns, deleting rows, DML) simple and efficient. Transactions and schema enforcement prevent costly corruption. The transaction log enables fast queries via Z-Ordering and file skipping.


Apache Spark Architecture

The Big Data Challenge and HDFS

Data growth requires distributed processing. Hadoop's MapReduce was disk-intensive and slow. Spark was designed to solve these flaws.

HDFS (Hadoop Distributed File System):

Apache Spark Overview

Apache Spark is a unified computing engine and set of libraries for parallel data processing on computer clusters. It provides one platform for batch, streaming, SQL, machine learning, and graph processing.

Origins:

Key features:

Architecture Components

Spark operates on a master-worker architecture:

  1. Driver Program: Central coordinator containing SparkContext. Translates logical plans into physical execution plans, coordinates with cluster manager, monitors job execution.

  2. Cluster Manager: Allocates CPU and memory resources. Supports Standalone, YARN, Apache Mesos, Kubernetes.

  3. Executors: Worker processes that execute tasks, report results to driver, store cached data, handle shuffle operations.

  4. Worker Nodes: Machines hosting multiple executors.

Execution flow:

Memory allocation in executors:

Data Abstractions: RDDs and Structured APIs

RDD (Resilient Distributed Dataset):

Structured APIs (DataFrame, Dataset, SQL):

RDD vs Structured API comparison:

Execution Model: DAG, Jobs, Stages, Tasks

DAG (Directed Acyclic Graph):

DAG vs MapReduce:

Job, Stage, Task:

Catalyst Optimizer and Tungsten

Catalyst Optimizer:

Tungsten Engine:

Adaptive Query Execution (AQE):

PySpark and SparkSQL

PySpark:

SparkSQL Examples:

Cheat Sheet (common operations):

Spark vs Hadoop

Spark is often used with Hadoop for storage (HDFS), combining strengths.

Key Optimization Best Practices

Key Takeaways