در طراحی مدلهای داده Power BI، همیشه امکان ایجاد یک رابطه فیزیکی مستقیم بین دو جدول وجود ندارد. گاهی ستون کلید در دو جدول از نوع دادهای متفاوت است، گاهی رابطه موردنیاز فقط در یک Measure خاص کاربرد دارد و ایجاد آن بهصورت دائمی در مدل توجیهی ندارد، و گاهی مدل از چند منبع داده جداگانه تشکیل شده که ترکیب مستقیم آنها در سطح Relationship ممکن نیست.
تابع TREATAS دقیقاً برای حل همین دسته از مسائل طراحی شده است. این تابع به توسعهدهنده اجازه میدهد بدون نیاز به تعریف رابطه فیزیکی در مدل، یک Filter Context را از یک ستون به ستون دیگر منتقل کند، درست به همان شکلی که یک رابطه واقعی این کار را انجام میدهد. در پروژههای سازمانی که مدل داده پیچیده و چندلایه است، تسلط بر TREATAS تفاوت میان یک راهحل موقت و شکننده با یک طراحی پایدار و قابل نگهداری را رقم میزند.
در این مقاله بررسی میکنیم TREATAS دقیقاً چه کاری انجام میدهد، چگونه Virtual Relationship میسازد، در چه سناریوهایی جایگزین USERELATIONSHIP میشود، چه تفاوتی با CROSSFILTER دارد و چگونه باید از نظر Performance آن را در مدلهای Star Schema به کار برد.
تعریف TREATAS و مفهوم Virtual Relationship
TREATAS تابعی است که مقادیر یک جدول یا Expression را میگیرد و آنها را بهعنوان فیلتر روی یک یا چند ستون از جدول دیگری اعمال میکند، بدون آنکه نیازی به وجود رابطه فیزیکی بین آن دو جدول در مدل داده باشد. ساختار کلی این تابع به شکل زیر است.
TREATAS ( <Table>, <Column1>, <Column2>, ... )
پارامتر اول جدولی است که مقادیر آن بهعنوان منبع فیلتر استفاده میشود و پارامترهای بعدی ستونهایی از جدول مقصد هستند که باید فیلتر روی آنها اعمال شود. تعداد ستونهای مشخصشده باید با تعداد ستونهای جدول ورودی مطابقت داشته باشد و ترتیب آنها نیز اهمیت دارد.
نکته کلیدی در TREATAS این است که این تابع صرفاً مقادیر را منتقل میکند، نه ساختار رابطهای مدل را. یعنی موتور DAX هیچ Relationship جدیدی در مدل ایجاد نمیکند، بلکه در لحظه اجرای Query، مقادیر ستون منبع را بهعنوان یک فیلتر مستقیم روی ستون مقصد اعمال میکند. به همین دلیل به این رفتار Virtual Relationship گفته میشود.
چرا این قابلیت اهمیت دارد
در یک مدل استاندارد Star Schema، فیلترها از طریق روابط فیزیکی از جدول Dimension به جدول Fact منتقل میشوند. اما در بسیاری از سناریوهای واقعی، دادهای که باید فیلتر کننده باشد، در قالب یک جدول مستقل، یک Virtual Table تولیدشده در همان Measure یا حتی یک جدول از منبع داده دیگری وجود دارد که امکان برقراری رابطه فیزیکی با آن در مدل ممکن نیست یا صلاح نیست. TREATAS دقیقاً پلی است که این فاصله را پر میکند.
مثال پایه: انتقال فیلتر بدون رابطه فیزیکی
فرض کنید در یک سیستم فروش سازمانی، جدول Sales به هیچ رابطه فیزیکی با یک جدول موقت از کدهای محصول منتخب متصل نیست. جدول Sales به شکل زیر است.
| ProductCode | Amount |
|---|---|
| P100 | 1200 |
| P200 | 800 |
| P300 | 1500 |
فرض کنید یک جدول جداگانه از کدهای محصولات اولویتدار سازمان داریم که در قالب یک Measure یا Calculated Table تولید میشود و هیچ رابطهای با Sales ندارد.
Priority Products Sales =
CALCULATE (
SUM ( Sales[Amount] ),
TREATAS (
VALUES ( PriorityList[ProductCode] ),
Sales[ProductCode]
)
)
در این Measure، مقادیر ستون ProductCode از جدول PriorityList گرفته میشود و بهعنوان فیلتر روی ستون ProductCode در جدول Sales اعمال میگردد. با اینکه هیچ Relationship فیزیکی بین این دو جدول تعریف نشده، نتیجه دقیقاً همان رفتاری را نشان میدهد که یک رابطه واقعی ایجاد میکرد.
تحلیل مسیر اجرا
VALUES ( PriorityList[ProductCode] )
│
▼
مجموعه مقادیر کد محصول
│
▼
TREATAS
│
▼
اعمال بهعنوان فیلتر روی Sales[ProductCode]
│
▼
CALCULATE محاسبه را در Context جدید اجرا میکند
این مسیر نشان میدهد TREATAS در واقع یک لایه میانی است که مقادیر را از یک منبع به فیلتر یک جدول دیگر تبدیل میکند، بدون آنکه ساختار مدل داده تغییر کند.
کاربرد TREATAS در مدلهای چند منبعی
یکی از رایجترین سناریوهایی که TREATAS در آن ارزش واقعی خود را نشان میدهد، مدلهایی است که از ترکیب چند منبع داده تشکیل شدهاند و امکان تعریف مستقیم Relationship بین آنها وجود ندارد یا مدل به دلایل معماری اجازه ایجاد رابطه مستقیم نمیدهد.
فرض کنید در یک سازمان، جدول Budget از یک سیستم مالی جداگانه وارد Power BI شده و ستون Department در آن با فرمتی متفاوت از جدول Sales ذخیره شده است.
اگر مقادیر کلید در دو جدول از نظر معنا و مقدار با یکدیگر منطبق باشند اما به دلایل معماری امکان یا تمایل به ایجاد Relationship فیزیکی وجود نداشته باشد، میتوان از TREATAS برای انتقال Filter Context بین آنها استفاده کرد. در مقابل، اگر اختلاف در قالب یا مقدار دادهها وجود داشته باشد، ابتدا باید این اختلاف در مرحله ETL یا Power Query برطرف شود؛ زیرا TREATAS مسئول تبدیل یا یکسانسازی دادهها نیست.
Budget Comparison =
CALCULATE (
SUM ( Budget[Amount] ),
TREATAS (
VALUES ( Sales[DepartmentCode] ),
Budget[DepartmentCode]
)
)
این الگو بهویژه در مدلهایی که Composite Model هستند یا شامل چند DirectQuery Source جداگانهاند، کاربرد زیادی دارد، زیرا در بسیاری از این حالتها ایجاد Relationship فیزیکی بین منابع مختلف یا امکانپذیر نیست یا با محدودیتهای Performance همراه است.
مقایسه TREATAS با USERELATIONSHIP
USERELATIONSHIP برای فعال کردن یک رابطه غیرفعال که از قبل در مدل تعریف شده استفاده میشود. این تابع نیاز دارد که رابطه فیزیکی بین دو جدول از قبل در مدل داده وجود داشته باشد، حتی اگر آن رابطه بهصورت پیشفرض غیرفعال باشد.
Delivery Sales =
CALCULATE (
[Total Sales],
USERELATIONSHIP ( Sales[DeliveryDate], 'Date'[Date] )
)
TREATAS برعکس عمل میکند. این تابع برای شرایطی طراحی شده که اصلاً هیچ رابطهای، چه فعال و چه غیرفعال، بین دو جدول وجود ندارد و امکان تعریف آن رابطه در مدل هم وجود ندارد یا صلاح نیست.
چه زمانی TREATAS جایگزین مناسبی برای USERELATIONSHIP است
اگر بین دو جدول یک ستون کلید مشترک با نوع داده یکسان وجود داشته باشد اما تیم مدلسازی به دلایلی مانند جلوگیری از افزایش تعداد Relationshipهای غیرفعال، یا وجود چندین رابطه بالقوه با یک جدول Dimension، ترجیح میدهد رابطه فیزیکی تعریف نکند، TREATAS میتواند بدون تغییر ساختار مدل، همان رفتار انتقال فیلتر را در سطح Measure پیادهسازی کند.
Sales By Ship Date TreatAs =
CALCULATE (
[Total Sales],
TREATAS (
VALUES ( 'Date'[Date] ),
Sales[ShipDate]
)
)
در این سناریو، نتیجه Measure از نظر انتقال Filter Context رفتاری مشابه استفاده از USERELATIONSHIP خواهد داشت، بدون آنکه رابطه دومی بین Sales و Date در مدل تعریف شده باشد. با این حال، TREATAS جایگزین کامل Relationship فیزیکی نیست و رفتار آن باید در Context واقعی مدل بررسی شود. این رویکرد در مدلهایی که چندین رابطه بالقوه با جدول Date دارند، میتواند پیچیدگی بصری مدل را کاهش داده و کنترل بیشتری روی منطق هر Measure فراهم کند.
مقایسه TREATAS با CROSSFILTER
CROSSFILTER برای تغییر جهت یا نوع فیلتر یک رابطه فیزیکی موجود در مدل استفاده میشود. این تابع میتواند جهت فیلتر یک Relationship را از Single به Both تغییر دهد یا حتی بهطور موقت یک رابطه را غیرفعال کند.
Total Sales No Filter =
CALCULATE (
[Total Sales],
CROSSFILTER ( Sales[ProductID], Product[ProductID], None )
)
تفاوت بنیادی این است که CROSSFILTER روی یک رابطه فیزیکی موجود عمل میکند و صرفاً رفتار آن را تغییر میدهد، در حالی که TREATAS برای جدولی که اصلاً رابطهای با جدول مقصد ندارد، فیلتر تولید میکند. اگر رابطه فیزیکی از قبل وجود دارد و فقط جهت یا نوع فیلترینگ آن باید تغییر کند، CROSSFILTER انتخاب درستی است. اگر اصلاً رابطهای وجود ندارد یا نمیتوان آن را در مدل تعریف کرد، TREATAS گزینه مناسب است.
کاربرد TREATAS در مدلهای Star Schema
در یک Star Schema استاندارد، معمولاً نیازی به TREATAS برای ارتباط بین Fact و Dimension اصلی نیست، زیرا این رابطه بهصورت فیزیکی و مستقیم وجود دارد. اما در سناریوهای زیر، حتی در یک مدل Star Schema درستطراحیشده، TREATAS نقش مهمی پیدا میکند.
فیلتر کردن بر اساس نتیجه یک محاسبه پیچیده
فرض کنید میخواهیم فروش را فقط برای مشتریانی محاسبه کنیم که در یک Measure جداگانه بهعنوان مشتری VIP شناسایی شدهاند، بدون آنکه این وضعیت بهصورت ستون ثابت در جدول Dimension مشتری ذخیره شده باشد.
VIP Customers Sales =
VAR VIPCustomers =
FILTER (
VALUES ( Customer[CustomerID] ),
[Total Sales] > 100000
)
RETURN
CALCULATE (
[Total Sales],
TREATAS ( VIPCustomers, Customer[CustomerID] )
)
در این مثال، ابتدا یک جدول مجازی از مشتریانی که فروش آنها از یک آستانه مشخص عبور کرده تولید میشود و سپس با TREATAS این مقادیر بهعنوان فیلتر روی Customer اعمال میشوند. این الگو در KPIهای مدیریتی که بر اساس نتیجه یک محاسبه پویا فیلتر میشوند، بسیار کاربردی است.
اتصال جدولهای Disconnected برای پارامترهای انتخابی کاربر
الگوی رایج دیگر در گزارشهای سازمانی، استفاده از یک جدول Disconnected برای انتخاب سناریو یا آستانه توسط کاربر است.
Threshold Sales =
VAR SelectedThreshold =
SELECTEDVALUE ( ThresholdParameter[ThresholdValue] )
VAR QualifyingProducts =
FILTER (
VALUES ( Product[ProductID] ),
[Total Sales] >= SelectedThreshold
)
RETURN
CALCULATE (
[Total Sales],
TREATAS ( QualifyingProducts, Product[ProductID] )
)
در این سناریو، جدول ThresholdParameter هیچ رابطهای با مدل اصلی ندارد و اصلاً نباید داشته باشد، زیرا صرفاً برای دریافت ورودی کاربر طراحی شده است. TREATAS این امکان را میدهد که نتیجه انتخاب کاربر، پس از پردازش در یک Variable، بهعنوان فیلتر روی جدول Fact اعمال شود.
| قابلیت | Relationship | USERELATIONSHIP | CROSSFILTER | TREATAS |
|---|---|---|---|---|
| نیاز به Relationship | ✅ | ✅ | ✅ | ❌ |
| ایجاد Virtual Relationship | ❌ | ❌ | ❌ | ✅ |
| تغییر جهت فیلتر | ❌ | ❌ | ✅ | ❌ |
| مناسب برای Disconnected Table | ❌ | ❌ | ❌ | ✅ |
| مناسب برای Composite Model | محدود | محدود | محدود | ✅ |
بررسی Performance تابع TREATAS
هزینه اجرای TREATAS بیش از هر چیز به تعداد مقادیر منتقلشده، Cardinality ستونها، پیچیدگی Expression ورودی و نوع داده ستونهای درگیر بستگی دارد. زمانی که مجموعه کوچکی از مقادیر یکتا و ستونهایی با نوع داده یکسان استفاده شوند، سربار این تابع معمولاً ناچیز است. اما اگر جدول ورودی بسیار بزرگ باشد یا موتور DAX مجبور به انجام تبدیل ضمنی نوع داده شود، هزینه اجرای Query افزایش پیدا میکند.
تأثیر Cardinality جدول ورودی
هرچه Cardinality ستون یا جدول ورودی TREATAS بیشتر باشد، حجم فیلتر تولیدشده نیز افزایش مییابد و این موضوع میتواند هزینه اجرای Query را افزایش دهد و در برخی سناریوها باعث افزایش فعالیت Formula Engine نیز شود. برای مثال، اگر VALUES(Sales[ProductCode]) تعداد بسیار زیادی مقدار یکتا تولید کند، Performance نسبت به حالتی که مجموعه کوچکی از مقادیر منتقل میشود، کاهش خواهد یافت.
غیربهینه در حجم بالا:
CALCULATE (
[Total Sales],
TREATAS(
VALUES(Sales[ProductCode]),
Budget[ProductCode]
)
)
در چنین سناریوهایی، بهتر است پیش از استفاده از TREATAS، جدول ورودی با یک FILTER یا شرط مشخص محدود شود تا فقط مقادیر واقعاً موردنیاز بهعنوان فیلتر منتقل شوند.
تفاوت نوع داده ستونها
اگر نوع داده ستون منبع در TREATAS با نوع داده ستون مقصد یکسان نباشد، موتور DAX باید تبدیل ضمنی انجام دهد که این موضوع میتواند مانع از بهینهسازی کامل توسط Storage Engine شود. توصیه میشود پیش از استفاده از TREATAS، اطمینان حاصل شود که نوع داده دو ستون دقیقاً یکسان است، در غیر این صورت بهتر است تبدیل نوع داده در لایه Power Query یا در سطح مدل انجام شود، نه در داخل Expression مربوط به TREATAS.
مقایسه Pushdown در TREATAS نسبت به رابطه فیزیکی
رابطه فیزیکی در مدل داده معمولاً بهینهترین مسیر از نظر Performance است، زیرا موتور VertiPaq از ساختار داخلی رابطه برای فیلتر کردن سریع استفاده میکند. TREATAS در بیشتر موارد رفتار نزدیکی به رابطه فیزیکی دارد و توسط موتور بهخوبی بهینه میشود، اما در Cardinalityهای بسیار بالا یا Expressionهای پیچیدهتر ورودی، همیشه به همان اندازه رابطه فیزیکی سریع نیست. به همین دلیل، اگر یک رابطه ثابت و پرتکرار در مدل نیاز است، طراحی آن بهصورت Relationship فیزیکی همچنان گزینه اول است و TREATAS باید برای سناریوهایی رزرو شود که ایجاد رابطه فیزیکی ممکن یا منطقی نیست.
اشتباهات رایج در استفاده از TREATAS
استفاده از TREATAS بهجای رابطه فیزیکی موجود
اگر دو جدول از قبل رابطه فیزیکی مناسبی دارند، استفاده از TREATAS برای همان هدف تنها پیچیدگی غیرضروری به کد اضافه میکند و از بهینهسازی داخلی موتور برای روابط فیزیکی بهره نمیبرد.
غیرضروری:
CALCULATE (
[Total Sales],
TREATAS ( VALUES ( Product[ProductID] ), Sales[ProductID] )
)
اگر Product و Sales از قبل رابطه فیزیکی فعال دارند، این Expression هیچ ارزش اضافهای نسبت به فیلتر مستقیم روی Product ایجاد نمیکند و صرفاً یک لایه محاسباتی زائد است.
عدم تطابق تعداد و ترتیب ستونها
یکی از خطاهای رایج در نگارش TREATAS، ناهماهنگی بین ترتیب ستونهای جدول ورودی و ستونهای مقصد است. اگر جدول ورودی شامل دو ستون باشد اما فقط با یک ستون مقصد مقایسه شود یا ترتیب مفهومی رعایت نشود، نتیجه میتواند کاملاً نادرست باشد بدون آنکه خطای اجرایی رخ دهد.
استفاده از TREATAS روی جداول بسیار بزرگ بدون فیلتر اولیه
انتقال کل یک جدول Fact بزرگ بهعنوان ورودی TREATAS، بدون هیچ محدودیت اولیه، میتواند فشار زیادی به Formula Engine وارد کند. توصیه میشود همیشه ورودی TREATAS از طریق VALUES یا FILTER به حداقل مقادیر موردنیاز محدود شود.
Best Practice استفاده از TREATAS در پروژههای سازمانی
پیش از استفاده از TREATAS، باید بررسی شود که آیا امکان ایجاد رابطه فیزیکی مناسب در مدل وجود دارد یا خیر.
اگر یک Relationship پایدار و دائمی در مدل وجود دارد، معمولاً استفاده از Relationship فیزیکی انتخاب مناسبتری است. TREATAS بیشتر برای سناریوهایی مناسب است که ایجاد چنین رابطهای ممکن، منطقی یا مطلوب نیست.
ورودی TREATAS همیشه باید محدودترین مجموعه ممکن از مقادیر باشد. استفاده از VALUES روی یک ستون فیلترشده یا یک جدول مجازی کوچک، بسیار بهینهتر از انتقال یک جدول بزرگ بدون فیلتر است.
نوع داده ستونهای درگیر در TREATAS باید از قبل هماهنگ باشد. هرگونه نیاز به تبدیل نوع داده باید در لایه Power Query یا مدل انجام شود، نه در داخل Expression.
مستندسازی دلیل استفاده از TREATAS در کامنت Measure توصیه میشود، زیرا برخلاف Relationshipهای فیزیکی که در Diagram View مدل قابل مشاهده هستند، Virtual Relationshipهای ایجادشده توسط TREATAS در Metadata مدل نمایش داده نمیشوند و تنها از طریق Expressionهای DAX قابل شناسایی هستند. این مستندسازی در نگهداری و توسعه مدل توسط اعضای دیگر تیم اهمیت زیادی دارد.
جمعبندی
تابع TREATAS یکی از ابزارهای پیشرفته DAX برای ایجاد Virtual Relationship است که امکان انتقال فیلتر بین دو ستون را بدون نیاز به رابطه فیزیکی در مدل داده فراهم میکند. این تابع در مواردی که ایجاد رابطه فیزیکی ممکن نیست، مانند مدلهای چند منبعی، جداول Disconnected یا فیلتر کردن بر اساس نتیجه یک محاسبه پویا، نقش کلیدی دارد.
TREATAS جایگزین مناسبی برای USERELATIONSHIP در سناریوهایی است که رابطه فیزیکی نمیتواند یا نباید در مدل تعریف شود و از نظر مفهومی با CROSSFILTER متفاوت است، زیرا CROSSFILTER روی رابطه فیزیکی موجود عمل میکند در حالی که TREATAS برای جدولهای بدون رابطه طراحی شده است. با این حال، استفاده از این تابع باید همیشه با در نظر گرفتن Cardinality جدول ورودی، هماهنگی نوع داده ستونها و امکان استفاده از رابطه فیزیکی بهعنوان جایگزین بهینهتر انجام شود.
در پروژههای سازمانی که مدل داده از چند منبع تشکیل شده یا نیاز به سناریوهای تحلیلی پویا وجود دارد، استفاده صحیح از TREATAS میتواند پیچیدگی مدل را بدون افزایش تعداد Relationshipهای فیزیکی کاهش دهد و در عین حال انعطاف تحلیلی موردنیاز تیمهای BI را فراهم کند.
سوالات متداول FAQ
آیا TREATAS رابطه واقعی در مدل داده ایجاد میکند؟
خیر. TREATAS هیچ Relationship فیزیکی در مدل ایجاد نمیکند. این تابع صرفاً در لحظه اجرای Query، مقادیر یک ستون را بهعنوان فیلتر روی ستون دیگری اعمال میکند و رفتار آن شبیه یک رابطه است، بدون آنکه در Diagram View مدل قابل مشاهده باشد.
تفاوت اصلی TREATAS و USERELATIONSHIP چیست؟
USERELATIONSHIP نیاز دارد رابطه فیزیکی، حتی بهصورت غیرفعال، از قبل در مدل تعریف شده باشد. TREATAS برای شرایطی طراحی شده که اصلاً هیچ رابطهای بین دو جدول وجود ندارد و نیازی به تعریف آن در مدل نیست.
آیا TREATAS همیشه کندتر از رابطه فیزیکی است؟
نه لزوماً. در Cardinality پایین و با تطابق کامل نوع داده، TREATAS معمولاً توسط موتور بهخوبی بهینه میشود. اما در حجم داده بسیار بالا یا عدم تطابق نوع داده، ممکن است هزینه اجرایی آن از یک رابطه فیزیکی بیشتر باشد.
چه زمانی باید از TREATAS بهجای CROSSFILTER استفاده کرد؟
اگر رابطه فیزیکی بین دو جدول از قبل وجود دارد و فقط جهت یا فعال بودن آن فیلتر باید تغییر کند، CROSSFILTER مناسب است. اگر اصلاً رابطهای بین دو جدول وجود ندارد، TREATAS باید استفاده شود.
آیا میتوان از TREATAS با چند ستون همزمان استفاده کرد؟
بله. TREATAS از چند ستون پشتیبانی میکند، به شرطی که تعداد و ترتیب ستونهای جدول ورودی دقیقاً با تعداد و ترتیب ستونهای مقصد مطابقت داشته باشد.
مشاوره تخصصی Power BI و طراحی مدل داده سازمانی
طراحی یک مدل داده سریع، مقیاسپذیر و قابل نگهداری در Power BI تنها به نوشتن فرمولهای DAX محدود نمیشود. انتخاب صحیح Relationshipهای فیزیکی، Virtual Relationshipها، طراحی Star Schema و مدیریت Filter Context تأثیر مستقیمی بر Performance، دقت تحلیلها و قابلیت توسعه مدل در آینده دارد.
اگر در پروژههای Power BI با چالشهایی مانند طراحی مدل داده، بهینهسازی DAX، کاهش زمان اجرای گزارشها، مدیریت Relationshipهای پیچیده یا توسعه داشبوردهای سازمانی مواجه هستید، توسعه فناوری اطلاعات لاندا با تکیه بر تجربه در طراحی معماری داده، مدلسازی تحلیلی و بهینهسازی Performance، آماده ارائه مشاوره تخصصی و پیادهسازی راهکارهای مقیاسپذیر برای سازمان شما است.


No comment