در گزارشهای مدیریتی و تحلیلی که مبتنی بر SQL Server ساخته میشوند، یکی از نیازهای تکرارشونده، رتبهبندی دادهها بدون ایجاد شکاف در شماره رتبههاست. برای مثال وقتی چند فروشنده دقیقاً فروش یکسانی دارند، بسیاری از گزارشهای مدیریتی انتظار دارند این افراد رتبه یکسان بگیرند، اما رتبه نفر بعدی بدون هیچ پرشی، بلافاصله ادامه پیدا کند. این دقیقاً همان رفتاری است که تابع DENSE_RANK در SQL Server ارائه میدهد و آن را از RANK، که در برابر تساوی رتبه دچار جهش میشود، متمایز میکند.
DENSE_RANK یکی از توابع خانواده Window Functions در SQL Server است که از نسخه 2005 به بعد در دسترس بوده و به همراه ROW_NUMBER و RANK، مجموعهای از توابع Window برای رتبهبندی، شمارهگذاری و تحلیل ترتیب دادهها در سطح Query را تشکیل میدهد. تفاوت این سه تابع، بهخصوص در برخورد با مقادیر تکراری، یکی از رایجترین منابع خطا در گزارشهای تحلیلی است که در این مقاله بهطور کامل بررسی میشود.
در این مقاله بررسی میکنیم DENSE_RANK دقیقاً چگونه کار میکند، چه تفاوتی با RANK و ROW_NUMBER دارد، چگونه با PARTITION BY در سطح هر گروه رتبهبندی مستقل انجام میدهد، در چه سناریوهای سازمانی کاربرد دارد و چه نکاتی از منظر Performance و طراحی Index باید رعایت شود.
مقادیر:
100, 100, 90, 80
RANK: 1, 1, 3, 4
DENSE_RANK: 1, 1, 2, 3
تعریف DENSE_RANK و ساختار پایه آن
DENSE_RANK تابعی است که به هر ردیف نتیجه یک Query، بر اساس ترتیب مشخصشده در بند ORDER BY، یک رتبه اختصاص میدهد. ویژگی اصلی این تابع این است که به مقادیر یکسان رتبه یکسان میدهد و رتبه بعدی، بدون هیچ جهشی، بلافاصله پس از آخرین رتبه استفادهشده ادامه پیدا میکند.
ساختار پایه این تابع به شکل زیر است.
SELECT
SalesPersonName,
TotalSales,
DENSE_RANK() OVER (ORDER BY TotalSales DESC) AS SalesRank
FROM SalesPersonPerformance;
در این Query، فروشندگان بر اساس مجموع فروش بهصورت نزولی رتبهبندی میشوند و فروشنده با بیشترین فروش رتبه یک را میگیرد. بند OVER مشخص میکند این رتبهبندی بر چه اساسی انجام شود و ORDER BY داخل آن، معیار مرتبسازی و رتبهبندی را تعیین میکند.
مثال پایه: مقایسه رفتار DENSE_RANK با داده واقعی
فرض کنید جدول عملکرد فروشندگان یک شعبه به شکل زیر باشد.
| SalesPersonName | TotalSales |
|---|---|
| علی رضایی | 500,000,000 |
| مریم احمدی | 500,000,000 |
| سارا محمدی | 420,000,000 |
| نیما کریمی | 320,000,000 |
| رضا قاسمی | 320,000,000 |
با اجرای Query زیر:
SELECT
SalesPersonName,
TotalSales,
DENSE_RANK() OVER (ORDER BY TotalSales DESC) AS SalesRank
FROM SalesPersonPerformance;
نتیجه به شکل زیر خواهد بود.
| SalesPersonName | TotalSales | SalesRank |
|---|---|---|
| علی رضایی | 500,000,000 | 1 |
| مریم احمدی | 500,000,000 | 1 |
| سارا محمدی | 420,000,000 | 2 |
| نیما کریمی | 320,000,000 | 3 |
| رضا قاسمی | 320,000,000 | 3 |
همانطور که مشاهده میشود، دو فروشنده اول با فروش برابر، رتبه یک میگیرند و رتبه بعدی بدون هیچ پرشی، عدد دو است. به همین ترتیب، دو فروشنده آخر که فروش یکسانی دارند، هر دو رتبه سه میگیرند. بیشترین مقدار رتبه در این نتیجه برابر با سه است، زیرا سه مقدار متمایز در ستون TotalSales وجود دارد.
تفاوت DENSE_RANK با RANK
RANK رتبه را بر اساس موقعیت ردیف در مجموعه مرتب شده تعیین میکند، بنابراین در صورت وجود مقادیر همرتبه، رتبه بعدی با توجه به تعداد ردیفهای قبلی جهش پیدا میکند.
با استفاده از همان داده قبلی، اگر هر دو تابع را در کنار هم اجرا کنیم.
SELECT
SalesPersonName,
TotalSales,
RANK() OVER (ORDER BY TotalSales DESC) AS RankNum,
DENSE_RANK() OVER (ORDER BY TotalSales DESC) AS DenseRankNum
FROM SalesPersonPerformance;
نتیجه تفاوت این دو را بهروشنی نشان میدهد.
| SalesPersonName | TotalSales | RankNum | DenseRankNum |
|---|---|---|---|
| علی رضایی | 500,000,000 | 1 | 1 |
| مریم احمدی | 500,000,000 | 1 | 1 |
| سارا محمدی | 420,000,000 | 3 | 2 |
| نیما کریمی | 320,000,000 | 4 | 3 |
| رضا قاسمی | 320,000,000 | 4 | 3 |
در ستون RankNum، پس از دو فروشنده همرتبه در جایگاه یک، رتبه بعدی مستقیماً سه میشود، زیرا RANK دو ردیف قبلی را در محاسبه رتبه بعدی لحاظ میکند. در ستون DenseRankNum، این جهش رخ نمیدهد و رتبه بعدی بلافاصله دو است.
انتخاب میان این دو تابع باید بر اساس معنای واقعی رتبه در گزارش انجام شود. اگر رتبه باید نشاندهنده جایگاه واقعی یک عضو در میان تمام رکوردها باشد، از جمله تأثیر تعداد رکوردهای همرتبه بر رتبههای بعدی، RANK مناسبتر است. اگر هدف نمایش سطح یا رده یک عضو، بدون توجه به تعداد اعضای همسطح، است، مانند سطحبندی مشتریان بر اساس میزان خرید، DENSE_RANK انتخاب صحیحتری است.
تفاوت DENSE_RANK با ROW_NUMBER
ROW_NUMBER با هر دو تابع RANK و DENSE_RANK تفاوت بنیادی دارد، زیرا این تابع بدون توجه به تساوی مقادیر، همیشه یک شماره یکتا و پیوسته به هر ردیف اختصاص میدهد.
SELECT
SalesPersonName,
TotalSales,
ROW_NUMBER() OVER (ORDER BY TotalSales DESC) AS RowNum,
DENSE_RANK() OVER (ORDER BY TotalSales DESC) AS DenseRankNum
FROM SalesPersonPerformance;
| SalesPersonName | TotalSales | RowNum | DenseRankNum |
|---|---|---|---|
| علی رضایی | 500,000,000 | 1 | 1 |
| مریم احمدی | 500,000,000 | 2 | 1 |
| سارا محمدی | 420,000,000 | 3 | 2 |
| نیما کریمی | 320,000,000 | 4 | 3 |
| رضا قاسمی | 320,000,000 | 5 | 3 |
با اینکه دو فروشنده اول فروش کاملاً یکسانی دارند، ROW_NUMBER به آنها شمارههای متفاوت یک و دو میدهد، در حالی که DENSE_RANK هر دو را برابر و رتبه یک در نظر میگیرد. ROW_NUMBER معمولاً برای سناریوهایی مانند شناسایی یک رکورد مشخص در هر گروه یا Paging نتایج مناسب است، جایی که یکتا بودن شماره هر ردیف اهمیت دارد، نه رتبه واقعی آن از نظر تحلیلی.
استفاده از PARTITION BY برای رتبهبندی در سطح هر گروه
مشابه سایر توابع Window در SQL Server، DENSE_RANK نیز میتواند همراه با PARTITION BY استفاده شود تا رتبهبندی بهجای کل نتیجه Query، در داخل هر گروه مستقل انجام گیرد.
فرض کنید در یک سیستم فروش چندشعبهای سازمانی، میخواهیم رتبه هر فروشنده را در میان همکاران همان شعبه محاسبه کنیم، نه در میان تمام فروشندگان سازمان.
SELECT
BranchID,
SalesPersonName,
TotalSales,
DENSE_RANK() OVER (
PARTITION BY BranchID
ORDER BY TotalSales DESC
) AS BranchSalesRank
FROM SalesPersonPerformance;
در این Query، دادهها ابتدا بر اساس BranchID به گروههای مستقل تقسیم میشوند و سپس در هر گروه، رتبهبندی از عدد یک آغاز میشود. یعنی برای هر شعبه، فروشنده با بیشترین فروش در همان شعبه رتبه یک میگیرد، صرفنظر از میزان فروش او در مقایسه با فروشندگان سایر شعبهها.
تحلیل مسیر منطقی اجرا
داده خام جدول SalesPersonPerformance
│
▼
PARTITION BY BranchID
│
▼
تفکیک به گروههای مستقل بر اساس شعبه
│
▼
ORDER BY TotalSales DESC در هر گروه
│
▼
DENSE_RANK در هر گروه از یک آغاز میشود
│
▼
تساوی مقادیر در هر گروه، رتبه یکسان میگیرد
│
▼
رتبه بعدی بدون جهش ادامه مییابد
از نظر نتیجه منطقی، میتوان آن را مشابه رتبهبندی مستقل دادههای هر شعبه در نظر گرفت، با این تفاوت که Query بهصورت یک عملیات واحد روی کل مجموعه داده اجرا میشود.
کاربرد سازمانی: سطحبندی مشتریان بر اساس میزان خرید
یکی از رایجترین کاربردهای DENSE_RANK در پروژههای سازمانی، سطحبندی مشتریان بر اساس یک معیار پیوسته، مانند مجموع خرید، به تعداد محدودی سطح یا رده است.
WITH CustomerRanking AS
(
SELECT
CustomerID,
CustomerName,
TotalPurchase,
DENSE_RANK() OVER (ORDER BY TotalPurchase DESC) AS PurchaseTier
FROM CustomerPurchaseSummary
)
SELECT
CustomerID,
CustomerName,
TotalPurchase,
PurchaseTier,
CASE
WHEN PurchaseTier <= 3 THEN N'مشتری VIP'
WHEN PurchaseTier <= 10 THEN N'مشتری طلایی'
ELSE N'مشتری عادی'
END AS CustomerSegment
FROM CustomerRanking;
در این Query، ابتدا با DENSE_RANK سطح خرید هر مشتری محاسبه میشود و سپس بر اساس این سطح، مشتریان به دستههای VIP، طلایی و عادی تقسیم میشوند. استفاده از DENSE_RANK در این سناریو دقیقاً به این دلیل مناسب است که هدف، تعیین سطح واقعی هر مشتری در میان سطوح متمایز خرید است، نه شماره ردیف یکتای او؛ اگر چند مشتری دقیقاً خرید یکسانی داشته باشند، منطقی است که همگی در یک سطح مدیریتی قرار گیرند، رفتاری که RANK به دلیل جهش در رتبههای بعدی نمیتواند به همین سادگی ارائه دهد.
در این مدل، مرزهای VIP و طلایی بر اساس سطح خرید تعیین میشوند، نه تعداد ثابت مشتریان.
استفاده از DENSE_RANK برای شمارهگذاری سطوح متمایز
یکی از کاربردهای جالب DENSE_RANK، اختصاص یک شماره پیوسته به هر مقدار متمایز است. در نتیجه، اگر رتبهبندی بدون PARTITION BY انجام شود، بیشترین مقدار رتبه میتواند تعداد مقادیر متمایز ستون موردنظر را نشان دهد. البته برای صرفاً شمارش مقادیر متمایز، COUNT(DISTINCT) انتخاب مستقیمتر و خواناتری است.
SELECT
ProductID,
ProductName,
UnitPrice,
DENSE_RANK() OVER (ORDER BY UnitPrice DESC) AS PriceTier
FROM Products;
از آنجا که DENSE_RANK به هر سطح قیمتی متمایز یک رتبه یکتا و بدون شکاف اختصاص میدهد، بزرگترین مقدار PriceTier در نتیجه این Query، دقیقاً برابر با تعداد کل سطوح قیمتی متمایز موجود در جدول Products است. البته این موضوع فقط زمانی معتبر است که رتبهبندی روی کل داده انجام شده باشد و PARTITION BY استفاده نشده باشد؛ در صورت وجود PARTITION BY، این عدد صرفاً تعداد سطوح متمایز در همان بخش خاص را نشان میدهد، نه کل جدول. این ویژگی در گزارشهایی که نیاز به شناسایی تعداد دستهبندیهای قیمتی یا سطوح متمایز یک معیار دارند، بدون نیاز به Query تجمیعی جداگانه، کاربرد عملی دارد.
ترکیب PARTITION BY با چند ستون در DENSE_RANK
مشابه سایر توابع Window، PARTITION BY در DENSE_RANK نیز میتواند شامل چند ستون باشد، که در سناریوهای تحلیلی چندبعدی کاربرد دارد.
SELECT
Region,
ProductCategory,
SalesPersonName,
TotalSales,
DENSE_RANK() OVER (
PARTITION BY Region, ProductCategory
ORDER BY TotalSales DESC
) AS RankWithinRegionAndCategory
FROM SalesSummary;
در این Query، رتبهبندی برای هر ترکیب منحصربهفرد از منطقه و دستهبندی محصول بهصورت مستقل انجام میشود. این الگو در تحلیل عملکرد چندبعدی، مانند مقایسه عملکرد فروشندگان در هر ترکیب منطقه و دسته محصول، بسیار پرکاربرد است و امکان تحلیل دقیقتری نسبت به رتبهبندی صرفاً در سطح کل سازمان فراهم میکند.
فیلتر کردن نتیجه بر اساس DENSE_RANK با استفاده از CTE
از آنجا که توابع Window، از جمله DENSE_RANK، نمیتوانند مستقیماً در بند WHERE همان سطح از Query استفاده شوند، برای فیلتر کردن نتیجه بر اساس رتبه محاسبهشده باید از یک Common Table Expression یا Subquery استفاده کرد.
WITH RankedProducts AS
(
SELECT
ProductID,
ProductName,
UnitPrice,
DENSE_RANK() OVER (ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
)
SELECT ProductID, ProductName, UnitPrice, PriceRank
FROM RankedProducts
WHERE PriceRank <= 3;
این Query سه سطح قیمتی برتر را استخراج میکند. نکته مهمی که باید در نظر گرفت این است که تعداد رکوردهای بازگشتی میتواند بیشتر از سه باشد، اگر چند محصول در همان سطح قیمتی سوم قرار داشته باشند، زیرا DENSE_RANK به تمام آنها رتبه یکسان میدهد. این رفتار دقیقاً همان چیزی است که در بسیاری از سناریوهای سطحبندی مطلوب است، اما اگر هدف واقعی استخراج دقیقاً سه رکورد بدون در نظر گرفتن تساوی باشد، باید از ROW_NUMBER بهجای DENSE_RANK استفاده شود یا معیار دومی برای شکستن تساوی در ORDER BY اضافه گردد.
تأثیر DENSE_RANK بر Execution Plan و Performance
از منظر موتور SQL Server، اجرای DENSE_RANK همراه با ORDER BY، در بیشتر موارد نیازمند یک عملیات Sort است، مگر آنکه یک Index مناسب از قبل داده را به همان ترتیب موردنیاز فراهم کرده باشد. این رفتار دقیقاً مشابه سایر توابع Window مانند ROW_NUMBER و RANK است.
نقش Index در کاهش عملیات Sort
اگر روی جدول SalesPersonPerformance یک Index ترکیبی متناسب با ستونهای PARTITION BY و ORDER BY تعریف شده باشد، موتور میتواند بدون نیاز به Sort مجزا، مستقیماً از ترتیب موجود در Index استفاده کند.
CREATE NONCLUSTERED INDEX IX_SalesPersonPerformance_Branch_Sales
ON SalesPersonPerformance
(
BranchID,
TotalSales DESC
)
INCLUDE
(
SalesPersonID,
SalesPersonName
);
در تعریف این Index، علاوه بر ستون نام فروشنده، شناسه فروشنده نیز در بخش INCLUDE قرار گرفته است، زیرا در گزارشهای واقعی سازمانی معمولاً علاوه بر نام، شناسه رکورد نیز در خروجی یا Joinهای بعدی موردنیاز است.
با وجود این Index، موتور SQL Server در بسیاری از شرایط میتواند از ترتیب موجود در Index استفاده کند و نیاز به عملیات Sort اضافی را کاهش دهد یا حذف کند، هرچند تصمیم نهایی همیشه بر عهده Query Optimizer است و بسته به آمار جدول، حجم داده و سایر عوامل Query، ممکن است در برخی شرایط همچنان یک عملیات Sort اضافی در Execution Plan دیده شود. در صورت نبود ترتیب مناسب در ورودی، Query Optimizer ممکن است برای اجرای رتبهبندی به عملیات Sort نیاز داشته باشد. در جدولهای بزرگ، چنین Sortای میتواند هزینه CPU، حافظه و I/O قابلتوجهی ایجاد کند.
تفاوت هزینه پردازش DENSE_RANK نسبت به RANK و ROW_NUMBER
هزینه اجرای DENSE_RANK، RANK و ROW_NUMBER در بسیاری از Queryها بیشتر تحت تأثیر مرتبسازی موردنیاز برای PARTITION BY و ORDER BY قرار دارد تا منطق شمارهگذاری خود تابع. اگر ورودی Query از قبل با ترتیب مناسب در دسترس باشد، ممکن است نیاز به Sort جداگانه کاهش پیدا کند یا از بین برود. بنابراین انتخاب میان این سه تابع باید بر اساس منطق کسبوکار انجام شود، نه انتظار تفاوت محسوس Performance میان خود توابع.
اشتباهات رایج در استفاده از DENSE_RANK
استفاده از DENSE_RANK در جایی که ROW_NUMBER موردنیاز است
یکی از رایجترین اشتباهات، استفاده از DENSE_RANK برای شناسایی یک رکورد مشخص و یکتا در هر گروه، مانند آخرین سفارش هر مشتری، است. از آنجا که DENSE_RANK به مقادیر تکراری رتبه یکسان میدهد، اگر دو سفارش دقیقاً در یک لحظه ثبت شده باشند، فیلتر بر اساس رتبه یک میتواند بیش از یک رکورد بازگرداند، در حالی که هدف اصلی معمولاً شناسایی دقیقاً یک رکورد بوده است. در چنین سناریویی، ROW_NUMBER همراه با یک Tie Breaker مناسب انتخاب صحیحتری است.
فرض نادرست از برابری تعداد رتبهها با تعداد رکوردها
از آنجا که DENSE_RANK رتبههای تکراری تولید میکند، بزرگترین مقدار رتبه در نتیجه یک Query، لزوماً برابر با تعداد کل رکوردها نیست، بلکه برابر با تعداد سطوح متمایز است. این نکته باید در طراحی گزارشهایی که مستقیماً از عدد رتبه برای شمارش رکوردها استفاده میکنند، بهدقت در نظر گرفته شود.
فراموش کردن Tie Breaker در ORDER BY
اگر ستون ORDER BY مقادیر تکراری زیادی داشته باشد و هدف واقعی گزارش تفکیک دقیقتر رکوردهای همرتبه باشد، افزودن یک ستون دوم به ORDER BY، مانند تاریخ یا شناسه، میتواند به تفکیک بهتر کمک کند. البته باید توجه داشت که افزودن ستون دوم به ORDER BY در DENSE_RANK، معیار تساوی را نیز تغییر میدهد و ممکن است تعداد سطوح متمایز رتبه را افزایش دهد. بنابراین در DENSE_RANK، افزودن Tie Breaker ممکن است باعث شود رکوردهایی که قبلاً همرتبه بودند، رتبههای جداگانه دریافت کنند، بنابراین این تغییر باید با آگاهی کامل از تأثیر آن بر منطق رتبهبندی انجام شود.
استفاده از DENSE_RANK بهجای RANK در گزارشهای رقابتی
در سناریوهایی که رتبه باید بازتابدهنده جایگاه واقعی رقابتی یک عضو باشد، مانند مسابقات یا رتبهبندیهایی که تعداد افراد بهتر از یک نفر اهمیت دارد، استفاده نادرست از DENSE_RANK بهجای RANK میتواند تصویر نادرستی از جایگاه واقعی ارائه دهد، زیرا DENSE_RANK تأثیر تعداد اعضای همرتبه را بر رتبههای بعدی نادیده میگیرد.
Best Practiceهای استفاده از DENSE_RANK در پروژههای سازمانی
پیش از انتخاب میان DENSE_RANK، RANK و ROW_NUMBER، باید دقیقاً مشخص شود هدف واقعی گزارش، سطحبندی بدون شکاف، رتبهبندی رقابتی با احتساب تعداد همرتبهها، یا شمارهگذاری یکتای هر رکورد است.
طراحی Index متناسب با ترکیب PARTITION BY و ORDER BY باید پیش از استقرار نهایی Query در محیط عملیاتی بررسی شود، بهخصوص در Queryهایی که روی جداول با میلیونها رکورد اجرا میشوند. ستونهای موردنیاز خروجی، از جمله شناسههای کلیدی، باید در بخش INCLUDE این Index لحاظ شوند تا نیاز به Key Lookup اضافی کاهش یابد.
در گزارشهای سطحبندی مشتریان یا محصولات، DENSE_RANK باید ترجیح داده شود، زیرا نتیجه آن، تعداد سطوح واقعی و بدون شکاف را نشان میدهد که برای دستهبندی مدیریتی معنادارتر است.
در فیلتر کردن نتیجه بر اساس DENSE_RANK با استفاده از CTE، باید از قبل بررسی شود که آیا امکان بازگشت تعداد رکورد بیشتر از N، به دلیل تساوی رتبه در مرز فیلتر، از نظر کسبوکار قابل قبول است یا باید با معیار دوم مدیریت شود.
مستندسازی دلیل انتخاب DENSE_RANK بهجای RANK یا ROW_NUMBER در کامنت Query یا Stored Procedure، برای تیم توسعه بعدی که ممکن است این منطق را تغییر دهد، ارزش نگهداری بالایی دارد.
نتیجهگیری
DENSE_RANK یکی از توابع کلیدی خانواده Window Functions در SQL Server است که امکان رتبهبندی بدون شکاف در برابر مقادیر تکراری را فراهم میکند. برخلاف RANK که رتبههای بعدی را متناسب با تعداد رکوردهای همرتبه پیش رو جهش میدهد، و برخلاف ROW_NUMBER که به هیچوجه تساوی مقادیر را در نظر نمیگیرد، DENSE_RANK به مقادیر یکسان رتبه یکسان میدهد و رتبه بعدی را بدون هیچ پرشی ادامه میدهد.
این رفتار DENSE_RANK را به ابزاری مناسب برای سناریوهایی مانند سطحبندی مشتریان، دستهبندی محصولات بر اساس سطح قیمتی و شمارش تعداد سطوح متمایز یک معیار تبدیل میکند. با این حال، انتخاب صحیح میان DENSE_RANK، RANK و ROW_NUMBER باید همیشه بر اساس معنای واقعی رتبه در گزارش انجام شود، نه صرفاً بر اساس آشنایی بیشتر با یکی از این توابع. توجه به طراحی Index متناسب با PARTITION BY و ORDER BY نیز برای حفظ Performance این نوع Queryها در جداول سازمانی بزرگ ضروری است.
سوالات متداول (FAQ)
1. تفاوت اصلی DENSE_RANK و RANK در چیست؟
DENSE_RANK پس از یک گروه رکورد همرتبه، رتبه بعدی را بدون هیچ جهشی ادامه میدهد، در حالی که RANK رتبه بعدی را متناسب با تعداد رکوردهای همرتبه پیش رو جهش میدهد. برای مثال اگر دو رکورد رتبه یک بگیرند، رتبه بعدی در DENSE_RANK عدد دو و در RANK عدد سه خواهد بود.
2. آیا بزرگترین مقدار DENSE_RANK همیشه برابر با تعداد رکوردهاست؟
خیر، بزرگترین مقدار DENSE_RANK برابر با تعداد سطوح متمایز موجود در ستون ORDER BY است، نه تعداد کل رکوردها. اگر مقادیر تکراری زیادی وجود داشته باشد، این عدد میتواند بهطور محسوس کمتر از تعداد کل رکوردها باشد.
3. چه زمانی باید از DENSE_RANK بهجای ROW_NUMBER استفاده کرد؟
زمانی که هدف نشان دادن سطح یا رده واقعی هر رکورد است و رکوردهای با مقدار یکسان باید رتبه یکسان بگیرند، مانند سطحبندی مشتریان بر اساس میزان خرید. اگر هدف شناسایی یک رکورد یکتا و مشخص در هر گروه است، ROW_NUMBER مناسبتر است.
4. آیا PARTITION BY در DENSE_RANK میتواند شامل چند ستون باشد؟
بله، PARTITION BY میتواند ترکیبی از چند ستون باشد و در این حالت رتبهبندی برای هر ترکیب منحصربهفرد از آن ستونها بهصورت مستقل از یک آغاز میشود.
5. چرا Query مبتنی بر DENSE_RANK گاهی کند اجرا میشود؟
معمولاً دلیل اصلی نبود Index متناسب با ستونهای PARTITION BY و ORDER BY است که باعث میشود موتور مجبور به انجام یک عملیات Sort پرهزینه روی کل داده شود، رفتاری که در تمام توابع Window از جمله RANK و ROW_NUMBER نیز مشترک است.
6. آیا DENSE_RANK در SQL Server باعث تغییر داده اصلی میشود؟
خیر، DENSE_RANK یک تابع محاسباتی در زمان اجرای Query است و هیچ تغییری در داده ذخیرهشده جدول ایجاد نمیکند. این تابع فقط رتبه را در نتیجه Query تولید میکند و برای ذخیره دائمی رتبه باید مقدار خروجی آن در یک جدول یا فرآیند ETL جداگانه ذخیره شود.
طراحی Queryهای سریع و گزارشهای تحلیلی با SQL Server
استفاده صحیح از Window Functionهایی مانند DENSE_RANK، RANK و ROW_NUMBER تنها زمانی ارزش واقعی ایجاد میکند که در کنار طراحی صحیح مدل داده، Indexگذاری اصولی و بررسی Execution Plan انجام شود.
اگر در پروژه سازمانی خود با Queryهای کند، گزارشهای پیچیده یا نیاز به بهینهسازی SQL Server مواجه هستید، متخصصان توسعه فناوری اطلاعات لاندا آماده ارائه خدمات مشاوره، طراحی و بهینهسازی پایگاه داده هستند. برای بررسی معماری دیتابیس، بهبود Performance Queryها و طراحی راهکارهای تحلیلی مقیاسپذیر، با تیم فنی لاندا در ارتباط ✆ باشید.


No comment