تصور کنید داشبورد مدیریتی سازمان شما که همیشه در کمتر از یک ثانیه بارگذاری میشد، پس از اضافه شدن چند Measure جدید ناگهان به چندین ثانیه زمان نیاز پیدا میکند. بررسیها نشان میدهد مشکل نه از مدل داده است، نه از سختافزار و نه از Power BI؛ بلکه تنها انتخاب نادرست بین دو تابع ساده SUM و SUMX باعث شده بخش بزرگی از پردازش از Storage Engine به Formula Engine منتقل شود.
اگر مدتی با Power BI یا زبان DAX کار کرده باشید، احتمالاً با دو تابع SUM و SUMX برخورد کردهاید. در نگاه اول هر دو برای محاسبه مجموع استفاده میشوند و حتی در بسیاری از مثالهای ساده خروجی یکسانی تولید میکنند. همین شباهت ظاهری باعث شده است بسیاری از توسعهدهندگان تصور کنند SUMX فقط نسخه پیشرفتهتر SUM است و هر زمان بخواهند میتوانند یکی را جای دیگری استفاده کنند.
این تصور یکی از رایجترین دلایل ایجاد Measureهای کند، مصرف بیش از حد CPU و طراحی نادرست مدلهای تحلیلی است. تفاوت واقعی این دو تابع نه در خروجی، بلکه در نحوه اجرای آنها توسط موتور DAX است.
برای درک صحیح این تفاوت باید کمی عمیقتر به معماری DAX نگاه کنیم. زمانی که یک Measure اجرا میشود، موتور Power BI تصمیم میگیرد کدام بخش از پردازش را به موتور ذخیرهسازی واگذار کند و کدام بخش را خودش محاسبه کند. انتخاب بین SUM و SUMX دقیقاً روی همین تصمیم اثر میگذارد و میتواند اختلافی چند برابری در زمان اجرای یک گزارش ایجاد کند.
در این مقاله تنها به معرفی نحوی توابع اکتفا نمیکنیم. بلکه بررسی خواهیم کرد که موتور VertiPaq چگونه این توابع را اجرا میکند، در سناریوهایی که فقط جمع یک ستون موجود انجام میشود، SUM معمولاً سریعتر و کمهزینهتر از SUMX است؛ هرچند در برخی عبارتهای ساده، موتور DAX میتواند بخشی از پردازش SUMX را نیز به Storage Engine منتقل کند.، SUMX دقیقاً چه کاری انجام میدهد، چه زمانی استفاده از آن اجتنابناپذیر است و چگونه انتخاب اشتباه میتواند عملکرد مدلهای Power BI را تحت تأثیر قرار دهد.
در پایان نیز با استفاده از سناریوهای واقعی، ابزارهای تحلیل Performance و Best Practiceهای توسعه DAX، خواهیم دید که چگونه میتوان Measureهایی سریع، دقیق و مقیاسپذیر طراحی کرد.
چرا شناخت تفاوت SUM و SUMX اهمیت دارد؟
بسیاری از مدلهای تحلیلی در ابتدا با حجم کمی از داده طراحی میشوند. در چنین شرایطی تفاوت محسوسی بین SUM و SUMX مشاهده نمیشود و هر دو تقریباً در یک زمان پاسخ را تولید میکنند. اما زمانی که حجم دادهها به دهها یا صدها میلیون ردیف میرسد، انتخاب تابع مناسب اهمیت بسیار زیادی پیدا میکند.
در پروژههای سازمانی معمولاً مشکلات زیر به دلیل استفاده نادرست از SUMX مشاهده میشود.
- افزایش زمان اجرای Visualها
- مصرف زیاد CPU در هنگام اجرای Queryها
- افزایش بار روی Formula Engine
- کاهش تعداد Queryهای همزمان قابل پردازش
- تجربه کاربری نامناسب در داشبوردهای مدیریتی
در مقابل، استفاده صحیح از SUM در شرایط مناسب باعث میشود بخش بزرگی از پردازش مستقیماً توسط موتور VertiPaq انجام شود؛ موتوری که برای پردازش میلیونها مقدار عددی بهینه شده است.
به همین دلیل، انتخاب بین SUM و SUMX صرفاً یک انتخاب نحوی نیست، بلکه یک تصمیم معماری در طراحی مدل DAX محسوب میشود.
SUM چیست؟
تابع SUM سادهترین تابع تجمیع در زبان DAX است و تنها یک وظیفه دارد؛ جمع کردن مقادیر یک ستون عددی.
ساختار این تابع بسیار ساده است.
SUM ( Sales[Amount] )
این تابع فقط یک ستون را دریافت میکند و مقدار تمام سطرهای آن ستون را با توجه به Filter Context جاری جمع میکند.
برای مثال اگر جدول فروش زیر را در اختیار داشته باشیم:
| Product | Amount |
|---|---|
| Laptop | 1200 |
| Mouse | 80 |
| Keyboard | 150 |
| Monitor | 900 |
استفاده از Measure زیر مجموع فروش را محاسبه میکند.
Total Sales =
SUM ( Sales[Amount] )
اگر کاربر در گزارش فقط محصولات یک شهر یا یک سال خاص را انتخاب کند، موتور DAX ابتدا Filter Context را اعمال کرده و سپس فقط همان مقادیر را جمع میکند.
در ظاهر این فرآیند بسیار ساده است، اما اتفاق مهمی در پشت صحنه رخ میدهد.
SUM چگونه توسط موتور DAX اجرا میشود؟
یکی از مهمترین ویژگیهای SUM این است که در اغلب مواقع مستقیماً توسط Storage Engine اجرا میشود.
Storage Engine همان بخشی از موتور VertiPaq است که برای عملیاتهای تجمیعی مانند SUM، COUNT، MIN و MAX بهینه شده است.
در نتیجه موتور نیازی ندارد تکتک سطرها را بررسی کند یا برای هر ردیف یک عبارت را محاسبه نماید. بلکه کافی است ستون فشردهشده را بخواند و عملیات Aggregate را انجام دهد.
به صورت ساده، فرآیند اجرای SUM به شکل زیر است.
Visual
↓
DAX Query
↓
Storage Engine
↓
Aggregation
↓
Result
به همین دلیل، SUM یکی از سریعترین توابع DAX محسوب میشود و در بسیاری از مدلهای بزرگ نیز عملکرد بسیار مناسبی دارد.
محدودیتهای SUM
با وجود سرعت بالا، SUM محدودیت مهمی دارد.
این تابع فقط قادر است یک ستون را جمع کند و هیچ محاسبهای روی هر ردیف انجام نمیدهد.
برای مثال کد زیر معتبر است.
SUM ( Sales[Amount] )
اما عبارت زیر معتبر نیست.
SUM (
Sales[Quantity] *
Sales[UnitPrice]
)
دلیل این موضوع بسیار ساده است.
خروجی عبارت Quantity × UnitPrice یک ستون واقعی در مدل نیست، بلکه یک محاسبه است. SUM تنها ستونهای موجود در مدل را میتواند جمع کند و قادر به ارزیابی یک عبارت سطری نیست.
همین محدودیت، دلیل اصلی ایجاد تابع SUMX است.
SUMX چیست؟
SUMX یکی از مهمترین توابع گروه Iterator Functions در DAX است.
برخلاف SUM که تنها یک ستون را جمع میکند، SUMX ابتدا روی هر ردیف یک عبارت را ارزیابی میکند و سپس نتایج را با یکدیگر جمع میکند.
ساختار آن به شکل زیر است.
SUMX (
Sales,
Sales[Quantity] * Sales[UnitPrice]
)
در این مثال ابتدا برای هر سطر مقدار فروش محاسبه میشود.
Quantity × UnitPrice
سپس خروجی تمام سطرها با هم جمع میشوند.
به همین دلیل SUMX در بسیاری از سناریوهای واقعی تنها راه صحیح برای انجام محاسبات است.
حرف X در SUMX چه مفهومی دارد؟
بسیاری تصور میکنند حرف X فقط بخشی از نام تابع است، در حالی که این حرف مفهوم بسیار مهمی دارد.
وجود X نشان میدهد که تابع از نوع Iterator است.
Iterator به این معناست که موتور DAX جدول را ردیفبهردیف پیمایش میکند، برای هر ردیف عبارت موردنظر را محاسبه میکند و در نهایت نتایج را تجمیع میکند.
توابع زیر نیز همین رفتار را دارند.
- SUMX
- AVERAGEX
- MAXX
- MINX
- COUNTX
- PRODUCTX
درک مفهوم Iterator یکی از مهمترین پیشنیازهای یادگیری حرفهای DAX است، زیرا بسیاری از مفاهیم پیشرفته مانند Row Context، Context Transition و CALCULATE بر پایه همین رفتار شکل گرفتهاند.
Row Context چیست و چه ارتباطی با SUMX دارد؟
اگر بخواهیم تنها یک مفهوم را به عنوان مهمترین تفاوت SUM و SUMX معرفی کنیم، بدون تردید آن مفهوم Row Context است.
بسیاری از خطاهایی که در فرمولهای DAX مشاهده میشوند، نه به دلیل اشتباه در نوشتن تابع، بلکه به دلیل درک نادرست Row Context و Filter Context هستند.
برای درک بهتر، تصور کنید جدول فروش زیر را در اختیار داریم.
| Product | Quantity | Unit Price |
|---|---|---|
| Laptop | 2 | 1000 |
| Mouse | 5 | 40 |
| Keyboard | 3 | 120 |
اگر بخواهیم مجموع فروش را محاسبه کنیم، باید برای هر ردیف عملیات زیر انجام شود.
2 × 1000
5 × 40
3 × 120
سپس نتایج با هم جمع شوند.
سؤال اینجاست که موتور DAX چگونه متوجه میشود در هر مرحله باید از کدام Quantity و کدام Unit Price استفاده کند؟
پاسخ، Row Context است.
Row Context محیطی است که موتور DAX در هنگام پردازش هر ردیف ایجاد میکند و به واسطه آن، مقادیر ستونهای همان ردیف در دسترس قرار میگیرند.
در تابع SUM چنین محیطی وجود ندارد، اما SUMX هنگام پیمایش جدول، برای هر ردیف یک Row Context جدید ایجاد میکند.
به همین دلیل عبارت زیر کاملاً معتبر است.
Sales Amount =
SUMX (
Sales,
Sales[Quantity] * Sales[Unit Price]
)
در این Measure موتور دقیقاً مراحل زیر را انجام میدهد.
| Row | Quantity | Unit Price | Result |
|---|---|---|---|
| 1 | 2 | 1000 | 2000 |
| 2 | 5 | 40 | 200 |
| 3 | 3 | 120 | 360 |
در پایان نیز حاصل جمع این مقادیر را برمیگرداند.
2000 +200 + 360 = 2560
SUMX نتیجه عبارت را برای هر ردیف ارزیابی کرده و سپس مقادیر حاصل را تجمیع میکند. این فرایند الزاماً به معنای ایجاد یک ستون فیزیکی یا حتی یک ستون موقت در حافظه نیست.
چرا SUM قادر به انجام این کار نیست؟
حال همان مثال را با SUM بنویسیم.
SUM (
Sales[Quantity] * Sales[Unit Price]
)
این کد با خطا مواجه میشود.
دلیل این خطا بسیار مهم است.
SUM هیچ Row Contextی ایجاد نمیکند.
در نتیجه موتور نمیتواند تشخیص دهد منظور از Quantity و Unit Price کدام ردیف است.
SUM فقط انتظار دارد یک ستون واقعی از مدل دریافت کند.
به همین دلیل فقط عبارتهای زیر معتبر هستند.
SUM ( Sales[Quantity] )
یا
SUM ( Sales[Sales Amount] )
اما محاسبهای که از ترکیب چند ستون ساخته شده باشد، خارج از توان SUM است.
Row Context چگونه ایجاد میشود؟
زمانی که SUMX اجرا میشود، موتور Formula Engine عملیات زیر را انجام میدهد.
Read First Row
↓
Create Row Context
↓
Evaluate Expression
↓
Store Result
↓
Next Row
↓
Repeat
این فرآیند تا آخرین ردیف ادامه پیدا میکند.
هر بار که موتور به ردیف جدید میرسد،
موتور هنگام حرکت به ردیف بعدی، Row Context مربوط به ردیف قبلی را کنار گذاشته و Context جدیدی ایجاد میکند.
و یک Context جدید ایجاد میشود.
به همین دلیل مقدار ستونها در هر مرحله متفاوت خواهد بود.
تفاوت Row Context و Filter Context
یکی از رایجترین اشتباهات توسعهدهندگان، یکسان فرض کردن این دو مفهوم است.
در حالی که این دو کاملاً متفاوت هستند.
| Row Context | Filter Context |
|---|---|
| روی یک ردیف کار میکند. | مجموعهای از ردیفها را محدود میکند. |
| توسط Iteratorها ایجاد میشود. | توسط Slicer، Filter، Visual و CALCULATE ایجاد میشود. |
| مقدار ستونهای همان ردیف را در اختیار قرار میدهد. | مشخص میکند کدام ردیفها در محاسبه شرکت کنند. |
| در SUMX وجود دارد. | هم در SUM و هم در SUMX وجود دارد. |
به بیان ساده، Row Context مشخص میکند الان روی کدام ردیف هستیم، اما Filter Context مشخص میکند اصلاً کدام ردیفها باید پردازش شوند.
این تفاوت کوچک، پایه بسیاری از مفاهیم پیشرفته DAX است.
SUM و SUMX در حضور Filter Context
فرض کنید کاربر در گزارش فقط فروش سال ۲۰۲۶ را انتخاب کرده است.
در این حالت Filter Context باعث میشود فقط رکوردهای همان سال وارد محاسبات شوند.
اگر از SUM استفاده کنیم.
SUM ( Sales[Amount] )
مجموع Amount فقط برای سال ۲۰۲۶ محاسبه میشود.
اگر از SUMX استفاده کنیم.
SUMX (
Sales,
Sales[Quantity] * Sales[Unit Price]
)
ابتدا Filter Context رکوردهای سال ۲۰۲۶ را انتخاب میکند و سپس SUMX روی همان رکوردها Row Context ایجاد کرده و عبارت را برای هر ردیف محاسبه میکند.
بنابراین SUMX جایگزین Filter Context نیست بلکه Row Context را به آن اضافه میکند.
SUMX همیشه کندتر است؟
پاسخ کوتاه خیر است.
اما در بیشتر سناریوها، SUMX نسبت به SUM پردازش بیشتری انجام میدهد.
دلیل آن نیز روشن است.
SUM فقط یک عملیات Aggregate روی یک ستون انجام میدهد، در حالی که SUMX باید برای هر ردیف:
- Row Context ایجاد کند.
- عبارت را ارزیابی کند.
- نتیجه را در حافظه نگه دارد.
- در پایان عملیات تجمیع را انجام دهد.
هرچه عبارت پیچیدهتر باشد، زمان اجرای Formula Engine نیز افزایش پیدا میکند.
به همین دلیل در مدلهایی که میلیونها ردیف دارند، انتخاب نادرست SUMX میتواند زمان اجرای گزارش را چندین برابر افزایش دهد.
آیا باید همیشه از SUM استفاده کنیم؟
خیر.
یکی از بزرگترین اشتباهات توسعهدهندگان، حذف SUMX فقط به دلیل نگرانی از Performance است.
اگر مسئله نیازمند محاسبه سطری باشد، SUMX تنها انتخاب صحیح است.
بهینهسازی واقعی به معنای استفاده از تابع مناسب برای مسئله مناسب است، نه انتخاب سریعترین تابع در همه شرایط.
Storage Engine و Formula Engine تفاوت اصلی SUM و SUMX از نگاه موتور DAX
اگر از یک توسعهدهنده Power BI بپرسید مهمترین تفاوت SUM و SUMX چیست، احتمالاً پاسخ خواهد داد که SUMX یک Iterator است. این پاسخ درست است، اما کامل نیست.
تفاوت واقعی این دو تابع در نحوه همکاری Storage Engine و Formula Engine نهفته است. بسیاری از مشکلات Performance در Power BI زمانی ایجاد میشوند که بدون آگاهی، بخش زیادی از پردازش را از Storage Engine به Formula Engine منتقل میکنیم.
درک این معماری به شما کمک میکند Measureهایی بنویسید که علاوه بر صحت، در مدلهای بزرگ نیز عملکرد مطلوبی داشته باشند.
معماری موتور DAX
موتور تحلیلی Power BI از دو بخش اصلی تشکیل شده است.
- Storage Engine (VertiPaq)
- Formula Engine
هر دو موتور با یکدیگر همکاری میکنند، اما مسئولیتهای متفاوتی دارند.
Power BI Visual
│
▼
DAX Formula Engine
│
▼
Storage Engine (VertiPaq)
│
▼
Compressed Data
هرچه حجم بیشتری از عملیات توسط Storage Engine انجام شود، معمولاً Query سریعتر اجرا خواهد شد.
Storage Engine چیست؟
Storage Engine مسئول خواندن دادههای فشردهشده، اعمال فیلترها و انجام عملیات تجمیعی ساده است.
مهمترین ویژگیهای آن عبارتاند از:
- خواندن دادههای ستونی (Columnar Storage)
- استفاده از فشردهسازی VertiPaq
- انجام Aggregateهایی مانند SUM، COUNT، MIN و MAX
- پردازش موازی
- استفاده حداقلی از حافظه
به همین دلیل است که جمع کردن میلیونها مقدار عددی معمولاً تنها در چند میلیثانیه انجام میشود.
Formula Engine چیست؟
Formula Engine بخش هوشمند موتور DAX است.
وظیفه آن ارزیابی Expressionها، اجرای توابع منطقی، Iteratorها، Context Transition و محاسبات پیچیده است.
نمونههایی از وظایف Formula Engine عبارتاند از:
- اجرای SUMX
- اجرای FILTER
- اجرای ADDCOLUMNS
- اجرای RANKX
- اجرای CALCULATE
- ایجاد Row Context
- ارزیابی شرطها
هرچه وابستگی Measure به Formula Engine بیشتر شود، احتمال افزایش مصرف CPU و زمان اجرا نیز بیشتر خواهد شد.
SUMX چگونه اجرا میشود؟
اکنون همین مثال را به شکل دیگری بنویسیم.
Sales Amount =
SUMX (
Sales,
Sales[Quantity] *
Sales[Unit Price]
)
در اینجا وضعیت کاملاً متفاوت است.
موتور دیگر فقط یک ستون را جمع نمیکند.
ابتدا باید برای هر ردیف مقدار عبارت زیر را محاسبه کند.
Quantity × Unit Price
در بسیاری از سناریوها، اجرای SUMX الگوی زیر را دارد:
SUMX
↓
Formula Engine
↓
Create Row Context
↓
Evaluate Expression
↓
Storage Engine
↓
Read Columns
↓
Formula Engine
↓
Aggregate Results
در بسیاری از Measureها، نیاز به ارزیابی عبارت در Formula Engine و تبادل داده با Storage Engine میتواند زمان اجرای Query را افزایش دهد.
مثال
فرض کنید جدول فروش شامل ۵۰ میلیون رکورد باشد.
در حالت اول ستون TotalAmount از قبل در مدل وجود دارد.
SUM ( Sales[TotalAmount] )
موتور فقط یک ستون را جمع میکند.
اما در حالت دوم.
SUMX (
Sales,
Sales[Quantity] *
Sales[Unit Price]
)
موتور باید عبارت را برای تمام ردیفهای واجد شرایط ارزیابی کند. در جدول ۵۰ میلیونردیفی، این ارزیابی میتواند روی میلیونها ردیف انجام شود.
اگرچه VertiPaq همچنان دادهها را بسیار سریع میخواند، در بسیاری از سناریوها Formula Engine مسئول ارزیابی عبارت برای ردیفهای واجد شرایط است.
همین تفاوت میتواند زمان اجرای Query را از چند میلیثانیه به چند صد میلیثانیه یا حتی چند ثانیه افزایش دهد.
SUMX معمولاً وابستگی بیشتری به Formula Engine دارد
یکی از نکات کمتر شناختهشده این است که موتور DAX بسیار هوشمند است.
در برخی سناریوها، موتور DAX میتواند بخشی از عملیات را به Storage Engine Push Down کند، اما این موضوع به ساختار عبارت DAX و قابلیتهای موتور بستگی دارد.
به عنوان مثال اگر عبارت بسیار ساده باشد و امکان Pushdown وجود داشته باشد، موتور تلاش میکند هزینه اجرای Query را کاهش دهد.
اما در بیشتر Measureهای واقعی که شامل شرط، CALCULATE، RELATED، LOOKUPVALUE یا توابع منطقی هستند، بخش عمده پردازش همچنان توسط Formula Engine انجام میشود.
به همین دلیل نباید انتظار داشت SUMX همیشه همان سرعت SUM را داشته باشد.
چگونه تفاوت این دو را مشاهده کنیم؟
بهترین ابزار برای مشاهده رفتار واقعی موتور DAX، DAX Studio است.
در DAX Studio میتوان قابلیت Server Timings را فعال کرد و مشاهده نمود که چه مقدار از زمان اجرای Query صرف Storage Engine و چه مقدار صرف Formula Engine شده است.
برای مثال ممکن است خروجی مشابه زیر مشاهده کنید.
| Measure | Storage Engine | Formula Engine | Total |
|---|---|---|---|
| SUM | 18 ms | 2 ms | 20 ms |
| SUMX | 24 ms | 145 ms | 169 ms |
این اعداد نمونه هستند، اما الگوی آنها در بسیاری از مدلهای واقعی مشاهده میشود.
تحلیل این گزارشها یکی از مهارتهای مهم در بهینهسازی مدلهای Power BI است و به توسعهدهنده نشان میدهد که گلوگاه عملکرد در کدام بخش قرار دارد.
چه زمانی استفاده از SUMX منطقی است؟
SUMX انتخاب مناسبی است اگر:
- برای هر ردیف باید یک فرمول محاسبه شود.
- مقدار نهایی در جدول ذخیره نشده باشد.
- محاسبه به چند ستون وابسته باشد.
- از تخفیف، مالیات، کارمزد یا ضرایب استفاده شود.
- ایجاد ستون محاسباتی باعث افزایش غیرضروری حجم مدل شود.
در مقابل، اگر فقط قرار است یک ستون موجود جمع شود، SUM تقریباً همیشه انتخاب بهتری خواهد بود.
اشتباهی که بسیاری از توسعهدهندگان مرتکب میشوند
یکی از رایجترین Anti Patternها در پروژههای Power BI این است که توسعهدهنده برای تمام Measureهای تجمیعی از SUMX استفاده میکند، حتی زمانی که هیچ محاسبه سطری وجود ندارد.
این کار معمولاً هیچ مزیتی ایجاد نمیکند و فقط باعث افزایش بار Formula Engine و کاهش کارایی مدل میشود.
SUM یا SUMX؟ سناریوهای واقعی، Anti Patternها و بهترین روش انتخاب
تا اینجا با تفاوت معماری SUM و SUMX آشنا شدیم و دیدیم که هر دو تابع برای جمع کردن دادهها استفاده میشوند، اما نحوه اجرای آنها کاملاً متفاوت است. اکنون وقت آن است که این مفاهیم را در سناریوهای واقعی به کار بگیریم.
در پروژههای سازمانی، انتخاب نادرست بین SUM و SUMX یکی از رایجترین دلایل کاهش عملکرد مدلهای Power BI است. در بسیاری از موارد، خروجی هر دو Measure یکسان است، اما هزینه اجرای آنها تفاوت قابل توجهی دارد.
سناریوی اول: جمع یک ستون موجود
فرض کنید جدول Sales دارای ستونی به نام Amount باشد که مبلغ فروش هر سفارش در آن از قبل ذخیره شده است.
Total Sales =
SUM ( Sales[Amount] )
گاهی توسعهدهندگان همان Measure را به شکل زیر مینویسند.
Total Sales =
SUMX (
Sales,
Sales[Amount]
)
هر دو Measure خروجی یکسانی تولید میکنند، اما Measure دوم بدون هیچ دلیلی یک Iterator ایجاد میکند.
در چنین شرایطی استفاده از SUMX تنها باعث افزایش پیچیدگی Query و مصرف بیشتر Formula Engine میشود.
بهترین انتخاب:
SUM()
سناریوی دوم: محاسبه مبلغ فروش
حال فرض کنید جدول فقط شامل Quantity و Unit Price باشد.
| Product | Quantity | Unit Price |
|---|---|---|
| Laptop | 2 | 1000 |
| Mouse | 5 | 40 |
| Keyboard | 3 | 120 |
در اینجا ستونی به نام Amount وجود ندارد.
در نتیجه تنها راه صحیح محاسبه فروش، استفاده از SUMX است.
Sales Amount =
SUMX (
Sales,
Sales[Quantity] *
Sales[Unit Price]
)
اگر بخواهیم از SUM استفاده کنیم، DAX با خطا مواجه خواهد شد.
بنابراین زمانی که مقدار نهایی باید برای هر ردیف محاسبه شود، SUMX انتخاب صحیح است.
سناریوی سوم: تخفیف برای هر سفارش
فرض کنید میزان تخفیف هر سفارش متفاوت باشد.
| Quantity | Unit Price | Discount |
|---|---|---|
| 2 | 1000 | 0.10 |
| 5 | 40 | 0.05 |
| 3 | 120 | 0.20 |
فرمول فروش به صورت زیر خواهد بود.
SUMX (
Sales,
Sales[Quantity]
*
Sales[Unit Price]
*
(1 - Sales[Discount])
)
در این مثال هیچ راهی برای استفاده مستقیم از SUM وجود ندارد، زیرا مقدار هر ردیف ابتدا باید محاسبه شود.
سناریوی چهارم: مالیات
فرض کنید نرخ مالیات برای هر کالا متفاوت باشد.
SUMX (
Sales,
Sales[Amount] *
Sales[TaxRate]
)
باز هم SUM به تنهایی قادر به انجام این محاسبه نیست.
SUMX یا Calculated Column؟
یکی از سؤالات رایج این است که آیا بهتر نیست ستون Amount را از قبل ایجاد کنیم و سپس از SUM استفاده کنیم؟
برای مثال:
Sales[Amount] =
Sales[Quantity] *
Sales[Unit Price]
سپس
SUM ( Sales[Amount] )
این روش معمولاً سریعتر اجرا میشود، زیرا عملیات ضرب هنگام Refresh انجام شده است.
اما یک هزینه مهم دارد.
ستون جدید فضای بیشتری در مدل اشغال میکند.
اگر جدول فروش شامل ۲۰۰ میلیون رکورد باشد، ایجاد یک ستون جدید میتواند حجم مدل را به شکل قابل توجهی افزایش دهد.
در مقابل، SUMX هیچ دادهای را ذخیره نمیکند و محاسبه را هنگام اجرای Query انجام میدهد.
بنابراین انتخاب بین این دو روش به شرایط پروژه بستگی دارد.
| Calculated Column | SUMX |
|---|---|
| افزایش حجم مدل | بدون افزایش حجم مدل |
| Refresh طولانیتر | Query طولانیتر |
| اجرای سریعتر گزارش | انعطاف بیشتر |
| مناسب محاسبات ثابت | مناسب محاسبات پویا |
رایجترین Anti Patternها
یکی از اهداف توسعه حرفهای DAX، حذف الگوهای نادرست است.
استفاده از SUMX برای جمع یک ستون
SUMX (
Sales,
Sales[Amount]
)
در این مثال هیچ محاسبهای انجام نمیشود.
بنابراین SUM انتخاب مناسبتری است.
استفاده از SUMX داخل SUMX
گاهی Measureهایی مانند نمونه زیر مشاهده میشود.
SUMX (
Customer,
SUMX (
Sales,
Sales[Amount]
)
)
اگر ضرورتی برای Iterator دوم وجود نداشته باشد، این ساختار میتواند هزینه اجرای Query را چند برابر کند.
استفاده بیدلیل از FILTER داخل SUMX
SUMX (
FILTER (
Sales,
Sales[Quantity] > 0
),
Sales[Amount]
)
در بسیاری از مواقع میتوان همین شرط را از طریق Filter Context یا CALCULATE اعمال کرد و هزینه پردازش را کاهش داد.
چگونه تشخیص دهیم SUMX لازم است؟
پیش از نوشتن Measure، این سؤال را از خود بپرسید.
آیا لازم است برای هر ردیف یک محاسبه انجام شود؟
اگر پاسخ خیر است، احتمالاً SUM انتخاب مناسبتری خواهد بود.
اگر پاسخ بله است، SUMX گزینه صحیح است.
این سؤال ساده از ایجاد بسیاری از مشکلات عملکرد جلوگیری میکند.
Best Practiceهای استفاده از SUM و SUMX
تجربه پروژههای بزرگ Power BI نشان میدهد رعایت چند اصل ساده میتواند تأثیر قابل توجهی بر عملکرد مدل داشته باشد.
- برای جمع یک ستون واقعی همیشه از SUM استفاده کنید.
- فقط زمانی از SUMX استفاده کنید که محاسبه سطری لازم باشد.
- قبل از ایجاد Calculated Column، هزینه افزایش حجم مدل را ارزیابی کنید.
- برای تحلیل عملکرد از DAX Studio و Server Timings استفاده کنید.
- از Iteratorهای تو در تو مگر در صورت نیاز واقعی اجتناب کنید.
- منطق محاسبات را تا حد امکان ساده نگه دارید تا Formula Engine بار کمتری تحمل کند.
- پس از نوشتن هر Measure، آن را روی دادههای واقعی و حجیم آزمایش کنید؛ عملکرد مناسب روی چند هزار ردیف، تضمینی برای کارایی روی میلیونها ردیف نیست.
جمعبندی
SUM و SUMX ممکن است در بسیاری از سناریوها نتیجه یکسانی تولید کنند، اما مسیر رسیدن به این نتیجه کاملاً متفاوت است.
SUM یک تابع تجمیعی سریع است که در بیشتر موارد از توان Storage Engine و موتور VertiPaq بهره میگیرد و برای جمع کردن ستونهای موجود بهترین انتخاب است.
در مقابل، SUMX یک Iterator است که با ایجاد Row Context، امکان انجام محاسبات سطری را فراهم میکند. این قابلیت قدرت بسیار بیشتری در اختیار توسعهدهنده قرار میدهد، اما در صورت استفاده نادرست میتواند بار Formula Engine را افزایش داده و زمان اجرای Queryها را بیشتر کند.
در نهایت، انتخاب بین SUM و SUMX نباید بر اساس عادت یا سلیقه باشد، بلکه باید بر اساس ماهیت مسئله، ساختار مدل داده و نحوه اجرای موتور DAX انجام شود. توسعهدهندهای که این تفاوت را بهخوبی درک کند، Measureهایی خواهد نوشت که علاوه بر صحت، در مقیاس سازمانی نیز سریع، بهینه و قابل نگهداری باشند.
پرسشهای متداول FAQ
آیا SUM از SUMX سریعتر است؟
در بسیاری از مدلها، SUM سریعتر است، زیرا معمولاً عملیات جمع را مستقیماً به Storage Engine واگذار میکند؛ در حالی که SUMX اغلب نیازمند ارزیابی یک عبارت برای هر ردیف است و ممکن است وابستگی بیشتری به Formula Engine داشته باشد.
آیا SUMX همیشه کند است؟
خیر. اگر محاسبه سطری موردنیاز باشد، SUMX انتخاب صحیح است. کند بودن یا نبودن آن به پیچیدگی عبارت، حجم داده و میزان درگیری Formula Engine بستگی دارد.
آیا میتوان همیشه بهجای SUMX از ستون محاسباتی استفاده کرد؟
خیر. ستون محاسباتی حجم مدل را افزایش میدهد و فقط برای محاسبات ثابت مناسب است. اگر نتیجه باید بهصورت پویا و بر اساس Filter Context محاسبه شود، SUMX گزینه مناسبتری است.
چه زمانی باید از SUM استفاده کنم؟
هر زمان که فقط قصد جمع کردن یک ستون عددی موجود در مدل را دارید و نیازی به محاسبه روی هر ردیف وجود ندارد، SUM بهترین انتخاب است.
پیشنهاد مطالعه
از نوشتن DAX تا طراحی یک پلتفرم تحلیلی مقیاسپذیر
انتخاب صحیح بین SUM و SUMX تنها یکی از صدها تصمیمی است که بر عملکرد یک مدل تحلیلی تأثیر میگذارد. طراحی معماری داده، مدلسازی، بهینهسازی VertiPaq، نگارش Measureهای استاندارد، پیادهسازی Microsoft Fabric و تحلیل Performance همگی نیازمند تجربه عملی در پروژههای سازمانی هستند. اگر به دنبال ساخت داشبوردهایی سریع، مقیاسپذیر و قابل نگهداری هستید، کارشناسان توسعه فناوری اطلاعات لاندا آماده ارائه خدمات مشاوره، طراحی و بهینهسازی راهکارهای هوش تجاری و تحلیل داده برای سازمان شما هستند.
برای دریافت مشاوره تخصصی، ارزیابی Performance یا برگزاری دورههای آموزشی عملی DAX، با کارشناسان لاندا تماس ✆ بگیرید.


No comment