نمذجة البيانات والتخزين
الأبعاد المتغيرة ببطء
الأبعاد المتغيرة ببطء (SCDs) تتعامل مع التتبع التاريخي في النماذج البعدية. هذا موضوع مقابلة كلاسيكي—توقع شرح الأنواع والمقايضات والتنفيذ.
نظرة عامة على أنواع SCD
| النوع | الوصف | التاريخ | التخزين |
|---|---|---|---|
| النوع 0 | احتفظ بالقيمة الأصلية | لا شيء | أدنى |
| النوع 1 | استبدل القيمة القديمة | لا شيء | أدنى |
| النوع 2 | أضف صف جديد مع الإصدار | كامل | عالي |
| النوع 3 | أضف عمود للقيمة السابقة | محدود | متوسط |
| النوع 4 | جدول تاريخ منفصل | كامل | متوسط |
| النوع 6 | هجين (1+2+3) | كامل | أعلى |
النوع 1: الاستبدال
لا تاريخ محفوظ—ببساطة استبدل القيم القديمة.
التنفيذ
-- قبل التحديث
SELECT * FROM dim_customer WHERE customer_id = 100;
-- customer_key=1, customer_id=100, email='old@email.com'
-- تحديث النوع 1
UPDATE dim_customer
SET email = 'new@email.com',
updated_at = CURRENT_TIMESTAMP
WHERE customer_id = 100;
-- بعد التحديث
-- customer_key=1, customer_id=100, email='new@email.com'
حالات الاستخدام
- تصحيح أخطاء إدخال البيانات
- السمات غير المهمة تحليلياً
- عندما لا يكون التاريخ مطلوباً
النوع 2: إضافة صف جديد
التاريخ الكامل محفوظ مع أعمدة الإصدار.
تصميم المخطط
CREATE TABLE dim_customer (
customer_key INT PRIMARY KEY, -- مفتاح بديل
customer_id VARCHAR(50), -- مفتاح طبيعي
customer_name VARCHAR(100),
segment VARCHAR(50),
region VARCHAR(50),
effective_date DATE, -- الصف صالح من
expiration_date DATE, -- الصف صالح إلى
is_current BOOLEAN, -- علامة السجل الحالي
version INT -- رقم الإصدار
);
التنفيذ
-- الخطوة 1: انتهاء صلاحية السجل الحالي
UPDATE dim_customer
SET expiration_date = CURRENT_DATE - 1,
is_current = FALSE
WHERE customer_id = 100
AND is_current = TRUE;
-- الخطوة 2: إدراج الإصدار الجديد
INSERT INTO dim_customer (
customer_key, customer_id, customer_name, segment, region,
effective_date, expiration_date, is_current, version
)
SELECT
nextval('customer_key_seq'),
100,
'John Smith',
'Premium', -- تغير من 'Standard'
'West',
CURRENT_DATE,
'9999-12-31', -- تاريخ عالي للحالي
TRUE,
(SELECT MAX(version) + 1 FROM dim_customer WHERE customer_id = 100);
أنماط الاستعلام
-- الحالة الحالية فقط
SELECT * FROM dim_customer WHERE is_current = TRUE;
-- البحث في نقطة زمنية
SELECT * FROM dim_customer
WHERE customer_id = 100
AND '2024-06-15' BETWEEN effective_date AND expiration_date;
-- التحليل التاريخي مع الحقائق
SELECT
f.sale_date,
f.amount,
d.segment -- الشريحة وقت البيع
FROM fact_sales f
JOIN dim_customer d ON f.customer_key = d.customer_key;
سؤال المقابلة: "لماذا نستخدم المفاتيح البديلة مع SCD النوع 2؟"
الجواب: "المفاتيح البديلة (customer_key) تسمح لكل إصدار أن يكون له معرف فريد. جداول الحقائق تشير إلى المفتاح البديل، تلتقط تلقائياً حالة البُعد وقت المعاملة. بدون المفاتيح البديلة، ستحتاج ربط معقد قائم على التاريخ لكل استعلام."
النوع 3: عمود القيمة السابقة
تتبع تاريخ محدود مع أعمدة إضافية.
تصميم المخطط
CREATE TABLE dim_customer (
customer_key INT PRIMARY KEY,
customer_id VARCHAR(50),
current_segment VARCHAR(50),
previous_segment VARCHAR(50),
segment_change_date DATE
);
التنفيذ
UPDATE dim_customer
SET previous_segment = current_segment,
current_segment = 'Premium',
segment_change_date = CURRENT_DATE
WHERE customer_id = 100;
حالات الاستخدام
- عندما تهم قيمة سابقة واحدة فقط
- تحليل سيناريوهات "قبل وبعد"
- البيئات المقيدة بالتخزين
النوع 4: جدول التاريخ
جدول منفصل للسجلات التاريخية.
تصميم المخطط
-- البُعد الحالي (تحديثات النوع 1)
CREATE TABLE dim_customer (
customer_key INT PRIMARY KEY,
customer_id VARCHAR(50),
customer_name VARCHAR(100),
segment VARCHAR(50),
updated_at TIMESTAMP
);
-- التتبع التاريخي
CREATE TABLE dim_customer_history (
history_id SERIAL PRIMARY KEY,
customer_key INT,
customer_name VARCHAR(100),
segment VARCHAR(50),
effective_date DATE,
expiration_date DATE,
change_type VARCHAR(20) -- INSERT, UPDATE, DELETE
);
الفوائد
- الاستعلامات الحالية تبقى بسيطة وسريعة
- التاريخ متاح عند الحاجة
- فصل أنظف للمسؤوليات
النوع 6: الهجين (1+2+3)
يجمع نهج متعددة للمرونة القصوى.
تصميم المخطط
CREATE TABLE dim_customer (
customer_key INT PRIMARY KEY,
customer_id VARCHAR(50),
customer_name VARCHAR(100),
-- أعمدة النوع 3
current_segment VARCHAR(50),
previous_segment VARCHAR(50),
original_segment VARCHAR(50), -- النوع 0
-- أعمدة النوع 2
effective_date DATE,
expiration_date DATE,
is_current BOOLEAN
);
حالات الاستخدام
- تحتاج كلاً من المقارنة الحالية والتاريخ الكامل
- متطلبات تحليلية معقدة
- عندما تحتاج سمات مختلفة معاملة SCD مختلفة
التنفيذ مع dbt
لقطة النوع 2
# models/snapshots/dim_customer_snapshot.sql
{% snapshot dim_customer_snapshot %}
{{
config(
target_schema='snapshots',
unique_key='customer_id',
strategy='timestamp',
updated_at='updated_at',
)
}}
SELECT
customer_id,
customer_name,
email,
segment,
region,
updated_at
FROM {{ source('raw', 'customers') }}
{% endsnapshot %}
مخطط النتيجة (مولد تلقائياً بواسطة dbt)
customer_id | customer_name | segment | dbt_scd_id | dbt_valid_from | dbt_valid_to | dbt_updated_at
اعتبارات الأداء
| الجانب | النوع 1 | النوع 2 | النوع 3 | النوع 4 |
|---|---|---|---|---|
| التخزين | منخفض | عالي | متوسط | متوسط |
| الاستعلام الحالي | سريع | متوسط | سريع | سريع |
| الاستعلام التاريخي | غير متاح | معقد | محدود | متوسط |
| تعقيد ETL | منخفض | عالي | متوسط | متوسط |
| ربط جدول الحقائق | بسيط | بسيط | بسيط | معقد |
سؤال تصميم المقابلة
السؤال: "صمم استراتيجية SCD لبُعد عميل تجارة إلكترونية"
الجواب:
| السمة | نوع SCD | المبرر |
|---|---|---|
customer_name |
النوع 1 | تصحيحات الاسم، غير مهمة تحليلياً |
email |
النوع 1 | معلومات الاتصال الحالية مطلوبة |
segment |
النوع 2 | حرج للتحليل التاريخي |
lifetime_value_tier |
النوع 2 | يدفع تحليل التسويق |
address |
النوع 2 أو 4 | يعتمد على احتياجات تحليل الشحن |
phone |
النوع 1 | الاتصال الحالي فقط |
registration_date |
النوع 0 | لا يتغير أبداً |
اختيار التنفيذ: "سأستخدم النوع 2 للشريحة والمستوى، النوع 1 لمعلومات الاتصال، وأفكر في النوع 4 إذا احتجنا تاريخ تغيير العنوان المفصل لكشف الاحتيال."
نصيحة المقابلة: عند مناقشة SCDs، دائماً اربط اختيارك بمتطلبات الأعمال. لا يوجد نوع "صحيح" عالمياً—أفضل اختيار يعتمد على الاحتياجات التحليلية وقيود التخزين.
الوحدة التالية تغطي أنابيب ETL وأنماط التنسيق. :::