فصل چهارم — مدلسازی داده؛ Fact، Dimension، Relationship و Star Schema
مدلسازی داده؛ Fact، Dimension، Relationship و Star Schema
بخشی از آموزش جامع Power BI
محتوای درس مدلسازی داده؛ Fact، Dimension، Relationship و Star Schema
کتاب جامع Power BI — آموزش پروژهمحور و کاربردی
مقدمه؛ اینجا قلب Power BI است
تا اینجا داده را وارد و با Power Query تمیز کردیم. حالا یک سؤال مهم داریم: این جدولها را چطور کنار هم بچینیم که هم گزارش درست جواب بدهد، هم DAX سادهتر شود و هم مدل بیدلیل سنگین نشود؟
مدلسازی داده همان جایی است که یک فایل نمایشی Power BI از یک راهکار تحلیلی حرفهای جدا میشود. ممکن است داشبورد خیلی زیبا باشد، ولی اگر مدل اشتباه طراحی شده باشد، دیر یا زود با محاسبات غلط، Relationshipهای عجیب و گزارش کند روبهرو میشویم.
۴.۱. Data Model یعنی چه؟
Data Model یعنی ساختار منطقی جدولها، ستونها و ارتباط بین آنها. به زبان خودمانی، داریم مشخص میکنیم «چه دادهای کجاست و این دادهها چه ربطی به هم دارند».
Customers ─┐
Products ─┼──> Sales <── Date
Branches ─┘
این ساختار به Power BI کمک میکند وقتی کاربر مثلاً شعبه تهران را انتخاب کرد، بفهمد کدام رکوردهای فروش باید فیلتر شوند.
۴.۲. اول Grain را بفهم
قبل از هر Relationship باید بفهمیم هر سطر جدول دقیقاً نماینده چیست. به این سطح جزئیات Grain میگوییم.
مثلاً اگر هر ردیف Sales یک «آیتم سفارش» باشد، OrderID ممکن است در چند ردیف تکرار شود؛ چون یک سفارش چند محصول دارد. اگر این نکته را نفهمیم، ممکن است Duplicate را اشتباه حذف کنیم یا تعداد سفارشها را غلط حساب کنیم.
نکته: قبل از مدلسازی یک جمله بنویس: «هر ردیف این جدول نماینده ... است.»
۴.۳. Fact Table چیست؟
Fact Table معمولاً رویدادهای قابل اندازهگیری کسبوکار را نگه میدارد. در سناریوی شرکت هانا، فروش یک رویداد است.
| نمونه ستون FactSales | کاربرد |
|---|---|
| OrderID | شناسه سفارش |
| DateKey | ارتباط با تاریخ |
| ProductKey | ارتباط با محصول |
| CustomerKey | ارتباط با مشتری |
| BranchKey | ارتباط با شعبه |
| Quantity | مقدار قابل محاسبه |
| UnitPrice | قیمت |
| Discount | تخفیف |
Fact معمولاً ردیفهای زیادی دارد و کلیدهای Dimensionها داخل آن دیده میشوند.
۴.۴. Dimension Table چیست؟
Dimension اطلاعات توصیفی را نگه میدارد؛ چیزهایی که با آنها Fact را دستهبندی، فیلتر یا تحلیل میکنیم.
| Dimension | نمونه اطلاعات |
|---|---|
| DimProduct | نام محصول، گروه، برند |
| DimCustomer | نام مشتری، شهر، نوع مشتری |
| DimBranch | نام شعبه، منطقه |
| DimDate | روز، ماه، فصل، سال |
| DimSalesPerson | نام فروشنده، تیم فروش |
اگر Fact جواب «چه اتفاقی افتاده؟» باشد، Dimension معمولاً کمک میکند بپرسیم «برای چه محصولی، چه زمانی، کدام مشتری و کدام شعبه؟»
۴.۵. Star Schema؛ مدل ستارهای
در Star Schema یک یا چند Fact در مرکز قرار میگیرند و Dimensionها اطرافشان هستند. شکل کلی شبیه ستاره میشود.
DimDate
|
DimCustomer — FactSales — DimProduct
|
DimBranch
|
DimSalesPerson
این الگو در بسیاری از مدلهای تحلیلی انتخاب بسیار خوبی است، چون مسیر فیلتر و منطق مدل را قابلفهمتر میکند.
۴.۶. چرا یک جدول بزرگ همیشه ایده خوبی نیست؟
ممکن است وسوسه شویم Customer، Product، Branch و Sales را با Merge تبدیل به یک جدول خیلی بزرگ کنیم. برای پروژههای خیلی ساده شاید کار کند، اما در پروژه جدی باعث تکرار اطلاعات توصیفی و سختتر شدن نگهداری مدل میشود.
مثلاً نام و مشخصات محصول برای هزاران ردیف فروش تکرار میشود. Star Schema کمک میکند اطلاعات محصول یکبار در DimProduct نگهداری شود و Fact فقط کلید آن را داشته باشد.
۴.۷. Relationship چیست؟
Relationship به Power BI میگوید دو جدول از چه طریقی به هم مرتبطاند.
DimProduct[ProductKey] 1 ───── * FactSales[ProductKey]
سمت ۱ یعنی مقدار کلید در Dimension یکتا است و سمت * یعنی همان ProductKey میتواند در Fact بارها تکرار شود.
۴.۸. One-to-Many
رایجترین ارتباط در مدل ستارهای One-to-Many است. یک محصول در DimProduct یک ردیف دارد، ولی همان محصول میتواند در هزاران فروش حضور داشته باشد.
یک Product
↓
چندین Sales Row
برای همین Dimension باید کلید یکتا و تمیز داشته باشد.
۴.۹. Many-to-Many؛ با احتیاط
گاهی هر دو سمت Relationship مقدار تکراری دارند و وارد Many-to-Many میشویم. این مدل در بعضی سناریوها لازم است، ولی نباید اولین انتخاب ما باشد.
اگر Many-to-Many دیدی، قبل از ادامه بررسی کن آیا Grain جدولها درست است، Dimension مناسب داری و آیا Bridge Table میتواند مدل را شفافتر کند.
۴.۱۰. Filter Direction
Relationship فقط اتصال نیست؛ جهت انتقال فیلتر هم مهم است. در مدل ستارهای معمولاً Dimension، Fact را فیلتر میکند.
DimBranch ──filter──> FactSales
استفاده بیدلیل از Both/Bidirectional میتواند مسیرهای مبهم و رفتارهای غیرمنتظره ایجاد کند. اول مدل را ساده نگه دار و فقط با دلیل مشخص جهت دوطرفه بساز.
۴.۱۱. Active و Inactive Relationship
فرض کن FactSales دو تاریخ دارد: OrderDate و DeliveryDate. هر دو به DimDate مربوطاند، ولی یک Relationship میتواند مسیر فعال اصلی باشد و دیگری غیرفعال باقی بماند.
DimDate → FactSales[OrderDate] Active
DimDate → FactSales[DeliveryDate] Inactive
در فصل DAX یاد میگیریم چطور در محاسبات خاص از Relationship غیرفعال استفاده کنیم.
۴.۱۲. جدول تاریخ؛ چرا مهم است؟
تحلیل زمانی حرفهای بدون یک Date Table درست خیلی زود دردسر میشود. DimDate فقط یک ستون تاریخ نیست؛ میتواند سال، ماه، فصل، شماره ماه، روز هفته و ویژگیهای تقویمی موردنیاز کسبوکار را نگه دارد.
| Date | Year | MonthNo | MonthName | Quarter |
|---|---|---|---|---|
| 2026-01-01 | 2026 | 1 | January | Q1 |
| 2026-02-01 | 2026 | 2 | February | Q1 |
برای تقویم شمسی هم باید ساختار مناسب نیاز پروژه طراحی شود؛ صرفاً تغییر ظاهر تاریخ جای Date Dimension درست را نمیگیرد.
۴.۱۳. کلیدها؛ Business Key و Surrogate Key
گاهی کدی که در سیستم عملیاتی داریم Business Key است؛ مثلاً ProductCode. در انبار داده یا مدل تحلیلی ممکن است یک کلید داخلی عددی هم داشته باشیم که Surrogate Key نامیده میشود.
ProductKey = 101
ProductCode = P-4587
در این کتاب فعلاً روی مفهوم تمرکز میکنیم؛ در پروژههای بزرگتر طراحی کلیدها روی تاریخچه Dimension و کیفیت مدل اثر جدی دارد.
۴.۱۴. Snowflake Schema چیست؟
در Snowflake بعضی Dimensionها خودشان به جدولهای توصیفی دیگری شکسته میشوند. مثلاً Product به SubCategory و Category متصل شود.
FactSales → DimProduct → DimSubCategory → DimCategory
Snowflake لزوماً بد نیست، ولی در Power BI معمولاً باید بررسی کنیم آیا این شکستن واقعاً ارزش پیچیدگی اضافه را دارد یا میتوان Dimension را برای تحلیل سادهتر کرد.
۴.۱۵. Calculated Column یا Measure؟
یکی از سؤالهای پرتکرار این است که محاسبه را Column بسازیم یا Measure. Calculated Column برای هر ردیف مقدار دارد و داخل مدل ذخیره میشود؛ Measure هنگام تحلیل و بر اساس Filter Context محاسبه میشود.
| ویژگی | Calculated Column | Measure |
|---|---|---|
| سطح | ردیفی | وابسته به Context |
| ذخیره در مدل | بله | نتیجه محاسبه به شکل ستون ذخیره نمیشود |
| کاربرد رایج | دستهبندی/ویژگی ردیفی | KPI و محاسبات تحلیلی |
جواب همیشه «Measure بهتر است» نیست؛ باید نوع مسئله را بفهمیم.
۴.۱۶. مدل شرکت هانا را طراحی کنیم
برای نسخه فعلی پروژه، یک مدل ساده میتواند شامل FactSales و Dimensionهای Date، Product، Customer، Branch و SalesPerson باشد.
DimDate 1 ─── *
DimProduct 1 ─── *
DimCustomer 1 ─── * FactSales
DimBranch 1 ─── *
DimSalesPerson1 ─── *
هر Dimension باید کلید یکتا داشته باشد و Fact کلید متناظر را نگه دارد.
۴.۱۷. Hide کردن ستونهای فنی
کاربر گزارش لازم نیست همه کلیدهای فنی را ببیند. ستونهایی مثل ProductKey یا CustomerKey برای Relationship مهماند، ولی در Field List نهایی ممکن است فقط باعث شلوغی شوند.
ستونهای فنی لازم را حذف نکن؛ در صورت مناسب بودن آنها را از Report View مخفی کن.
۴.۱۸. Hierarchy
Hierarchy کمک میکند مسیر طبیعی Drill Down را تعریف کنیم. مثلاً برای تاریخ:
Year
└── Quarter
└── Month
└── Date
یا برای محصول میتوانیم Category → SubCategory → Product داشته باشیم. Hierarchy باید واقعاً با نحوه تحلیل کاربر همخوان باشد.
۴.۱۹. اشتباه رایج: Relationship روی نام
گاهی تازهکارها جدولها را با ProductName یا CustomerName به هم وصل میکنند. نامها ممکن است تکراری، تغییرپذیر یا دارای اختلاف نگارشی باشند.
تا جای ممکن Relationship را روی کلید پایدار و مناسب بساز.
۴.۲۰. اشتباه رایج: Dimension با کلید تکراری
اگر سمت «۱» Relationship باید ProductKey یکتا باشد ولی تکراری داریم، Power BI نمیتواند همان رابطه مورد انتظار را بسازد.
این مشکل را با تبدیل عجولانه رابطه به Many-to-Many پنهان نکن. اول علت Duplicate را پیدا کن.
۴.۲۱. اشتباه رایج: حلقه و مسیر فیلتر مبهم
Relationshipهای زیاد و Bidirectional ممکن است چند مسیر فیلتر بین جدولها ایجاد کنند. نتیجه میتواند خطا یا محاسباتی باشد که فهمشان سخت است.
مدل خوب معمولاً قابل توضیح است. اگر برای توضیح مسیر فیلتر نیاز به یک سخنرانی یکساعته داری، احتمالاً مدل بیش از حد پیچیده شده است!
۴.۲۲. Best Practiceهای مدلسازی
Grain هر Fact را قبل از ساخت Relationship مشخص کن.
Dimensionها را با کلید یکتا طراحی کن.
مدل ستارهای را به عنوان نقطه شروع جدی بگیر.
جهت فیلتر را تا جای ممکن ساده نگه دار.
ستونهای غیرضروری را وارد مدل نکن.
نام جدولها و ستونها را خوانا و یکدست انتخاب کن.
Date Table مشخص و قابل اعتماد داشته باش.
مدل را برای تحلیل طراحی کن، نه اینکه ساختار دیتابیس عملیاتی را بدون فکر کپی کنی.
۴.۲۳. تمرین پایه
یک جدول Sales و یک جدول Products بساز. Products باید ProductID یکتا داشته باشد و Sales چند رکورد برای هر ProductID.
بین دو جدول Relationship یکبهچند ایجاد کن و بررسی کن انتخاب Category چگونه Sales را فیلتر میکند.
۴.۲۴. تمرین متوسط
به مدل قبلی DimBranch و DimCustomer اضافه کن. مدل را روی کاغذ به شکل Star Schema بکش و Grain هر جدول را در یک جمله بنویس.
۴.۲۵. تمرین کاربردی
یک DimDate بساز و آن را به FactSales متصل کن. سپس گزارش فروش بر اساس Year و Month طراحی کن.
بررسی کن چرا استفاده از MonthName بدون MonthNo میتواند ترتیب ماهها را بههم بزند.
۴.۲۶. تمرین چالشی
در Fact دو ستون OrderDate و DeliveryDate ایجاد کن. هر دو را با DimDate مرتبط کن و ببین Power BI درباره Relationship فعال چه رفتاری دارد.
فعلاً فقط مدل را تحلیل کن؛ استفاده از Relationship غیرفعال را در فصل DAX کامل میکنیم.
۴.۲۷. پروژه فصل چهارم؛ مدل تحلیلی شرکت هانا
داده تمیزشده فصل قبل را به یک مدل ستارهای تبدیل کن. هدف این است که FactSales در مرکز باشد و Dimensionهای اصلی اطراف آن قرار بگیرند.
| جدول | Grain پیشنهادی |
|---|---|
| FactSales | هر ردیف = یک آیتم فروش |
| DimProduct | هر ردیف = یک محصول |
| DimCustomer | هر ردیف = یک مشتری |
| DimBranch | هر ردیف = یک شعبه |
| DimSalesPerson | هر ردیف = یک فروشنده |
| DimDate | هر ردیف = یک تاریخ |
در پایان پنج چیز را کنترل کن: یکتایی کلید Dimensionها، Cardinality، جهت فیلتر، Active Relationshipها و نبود مسیرهای مبهم.
جمعبندی فصل چهارم
در این فصل فهمیدیم مدلسازی فقط وصلکردن چند جدول نیست. باید Grain، Fact، Dimension، کلید، Cardinality و مسیر فیلتر را بشناسیم.
Clean Data
↓
Fact + Dimensions
↓
Star Schema
↓
Clear Relationships
↓
Simpler DAX + Reliable Reports
در فصل بعد وارد DAX میشویم؛ از Measureهای پایه شروع میکنیم و کمکم به CALCULATE، Filter Context، Row Context و محاسبات واقعی فروش و سود شرکت هانا میرسیم.