آموزش ORDER BY در SQL Server | ۱۰ مثال کاربردی و بهینه‌سازی

آموزش جامع عبارت ORDER BY در OVER در SQL Server

توسط admin | گروه SQL Server | 1405/04/29

نظرات 0

آموزش جامع عبارت ORDER BY در OVER در SQL Server با مثال‌های عملی

مقدمه

ORDER BY داخل OVER ترتیب منطقی ردیف‌ها را برای رتبه‌بندی، دسترسی به ردیف قبل و بعد و قاب‌های تجمعی تعیین می‌کند. این ترتیب تضمین نمی‌کند خروجی نهایی صفحه نیز مرتب باشد؛ برای آن باید ORDER BY جداگانه در انتهای SELECT نوشته شود. در این راهنما رفتار واقعی عبارت ORDER BY در OVER را از مثال پایه تا سناریوی سازمانی، حالت NULL، خطای رایج و بهینه‌سازی بررسی می‌کنیم.

برای دیدن جایگاه این موضوع در کل خانواده پنجره‌ای، راهنمای جامع عبارت‌های پنجره‌ای SQL Server را نیز مطالعه کنید. هدف این است که Query نهایی هم از نظر معنایی درست و هم در حجم واقعی قابل دفاع باشد.

تعریف، نحو و نوع خروجی

ORDER BY داخل OVER ترتیب منطقی ردیف‌ها را برای رتبه‌بندی، دسترسی به ردیف قبل و بعد و قاب‌های تجمعی تعیین می‌کند. این ترتیب تضمین نمی‌کند خروجی نهایی صفحه نیز مرتب باشد؛ برای آن باید ORDER BY جداگانه در انتهای SELECT نوشته شود.

نحو استاندارد

window_function() OVER (
    [PARTITION BY partition_expression]
    ORDER BY sort_expression [ASC | DESC]
             [, tie_breaker_expression]
)

پارامترها و اجزای مهم

  • تابع پنجره‌ای: تابعی مانند SUM، AVG، ROW_NUMBER، RANK، LAG یا LEAD که نتیجه تحلیلی را تولید می‌کند.
  • PARTITION BY: مرز اختیاری گروه‌های مستقل را تعیین می‌کند و در هر گروه محاسبه از نو آغاز می‌شود.
  • ORDER BY: ترتیب منطقی ردیف‌ها را برای محاسبات وابسته به توالی مشخص می‌کند.
  • Window Frame: در توابع سازگار، محدوده ردیف‌های مؤثر نسبت به ردیف جاری را تعریف می‌کند.

نوع خروجی

ORDER BY یک ورودی معنایی برای تابع پنجره‌ای است. خروجی از تابعی مانند ROW_NUMBER، LAG یا SUM می‌آید و در صورت نبود کلید رفع تساوی ممکن است انتساب میان ردیف‌های هم‌ارزش قطعی نباشد.

مدل ذهنی و ترتیب منطقی اجرا

برای تحلیل عبارت ORDER BY در OVER ابتدا Dataset پس از FROM، JOIN، WHERE و GROUP BY را در نظر بگیرید. تابع پنجره‌ای روی این مجموعه منطقی محاسبه می‌شود و سپس SELECT خروجی را شکل می‌دهد. به همین دلیل Alias یا خروجی پنجره در WHERE همان سطح قابل استفاده نیست و برای فیلتر باید CTE یا زیرپرس‌وجو ایجاد شود.

سه سؤال پیش از نوشتن Query مطرح کنید: هر محاسبه برای کدام گروه مستقل است، ترتیب دقیق و قطعی ردیف‌ها چیست، و قاب از کجا تا کجا امتداد دارد؟ پاسخ صریح به این سه سؤال بیشتر خطاهای ظریف گزارش‌های تحلیلی را حذف می‌کند.

وجود مقدارهای تکراری و NULL را بخشی از طراحی بدانید. نمونه‌ای که فقط داده یکتا دارد ممکن است در محیط آزمایشی درست به نظر برسد ولی با اولین تساوی در تولید، رتبه یا مانده متفاوتی بسازد. تست کوچک باید عمداً این حالت‌ها را وارد کند.

مثال‌های عملی

مثال 1: رتبه قطعی

Salary ترتیب اصلی و EmployeeID کلید رفع تساوی است.

SELECT EmployeeID,Salary,ROW_NUMBER() OVER(ORDER BY Salary DESC,EmployeeID) AS rn
FROM (VALUES(1,90),(2,90),(3,70)) E(EmployeeID,Salary);
EmployeeIDSalaryrn
1901
2902
3703

بدون EmployeeID، دو ردیف حقوق 90 ترتیب تضمین‌شده‌ای ندارند و شماره آن‌ها می‌تواند با تغییر Plan عوض شود.

مثال 2: جمع تجمعی بر اساس تاریخ

ترتیب تاریخ و شناسه تراکنش توالی قابل اعتماد برای Running Total می‌سازد.

SELECT TxnID,Amount,SUM(Amount) OVER(ORDER BY TxnDate,TxnID ROWS UNBOUNDED PRECEDING) AS RunningTotal
FROM (VALUES(1,CONVERT(date,'2026-01-01'),10),(2,'2026-01-02',20)) T(TxnID,TxnDate,Amount);
TxnIDAmountRunningTotal
11010
22030

تاریخ به‌تنهایی در سامانه پرتراکنش معمولاً یکتا نیست. شناسه یا زمان دقیق‌تر را برای قطعیت اضافه کنید.

مثال 3: مقایسه با مقدار قبلی

LAG با ORDER BY مقدار رویداد قبلی را بدون Self Join می‌خواند.

SELECT DayNo,Amount,LAG(Amount) OVER(ORDER BY DayNo) AS PrevAmount
FROM (VALUES(1,10),(2,15),(3,12)) D(DayNo,Amount);
DayNoAmountPrevAmount
110NULL
21510
31215

ردیف اول سابقه ندارد و NULL طبیعی است. با پارامتر سوم LAG می‌توان Default صریح تعیین کرد.

مثال 4: انتخاب دو رکورد تازه

CTE رتبه را بر اساس تاریخ نزولی می‌سازد و سپس دو ردیف اول را انتخاب می‌کند.

WITH R AS(SELECT TicketID,CreatedAt,ROW_NUMBER() OVER(ORDER BY CreatedAt DESC,TicketID DESC) rn FROM (VALUES(1,CONVERT(datetime2,'2026-01-01')),(2,'2026-01-03'),(3,'2026-01-02')) T(TicketID,CreatedAt))
SELECT TicketID,CreatedAt FROM R WHERE rn<=2;
TicketIDCreatedAt
22026-01-03
32026-01-02

فیلتر رتبه در لایه بیرونی انجام می‌شود. برای Top ساده TOP مناسب‌تر است، اما الگو برای Top-N هر پارتیشن توسعه‌پذیر است.

مثال 5: مدیریت تساوی امتیاز

RANK برای امتیاز مساوی رتبه یکسان و فاصله بعدی ایجاد می‌کند.

SELECT StudentID,Score,RANK() OVER(ORDER BY Score DESC) AS RankNo
FROM (VALUES(1,95),(2,95),(3,80)) S(StudentID,Score);
StudentIDScoreRankNo
1951
2951
3803

اگر فاصله رتبه مطلوب نیست، DENSE_RANK نتیجه 1،1،2 می‌دهد. انتخاب تابع بخشی از قانون کسب‌وکار است.

مثال 6: کنترل جایگاه NULL

CASE مقادیر NULL را پس از مقادیر واقعی قرار می‌دهد.

SELECT ItemID,DueDate,ROW_NUMBER() OVER(ORDER BY CASE WHEN DueDate IS NULL THEN 1 ELSE 0 END,DueDate,ItemID) AS rn
FROM (VALUES(1,CONVERT(date,'2026-01-02')),(2,NULL),(3,'2026-01-01')) D(ItemID,DueDate);
ItemIDDueDatern
32026-01-011
12026-01-022
2NULL3

SQL Server گزینه NULLS LAST ندارد؛ CASE راه صریح است، ولی ممکن است Sort ایجاد کند و باید اثر آن در Plan سنجیده شود.

مثال 7: ترتیب نزولی تغییرات

LEAD مقدار روز بعد را بر اساس ترتیب تعیین‌شده می‌خواند.

SELECT DayNo,Amount,LEAD(Amount) OVER(ORDER BY DayNo DESC) AS NextInDescendingOrder
FROM (VALUES(1,10),(2,20),(3,30)) D(DayNo,Amount);
DayNoAmountNextInDescendingOrder
33020
22010
110NULL

معنای قبل و بعد تابعی از جهت ORDER BY است. نام Alias را طوری انتخاب کنید که جهت تحلیل برای خواننده روشن باشد.

مثال 8: تحلیل روند فروش

تفاضل مبلغ با LAG رشد یا افت هر دوره را نشان می‌دهد.

SELECT MonthNo,Amount,Amount-LAG(Amount) OVER(ORDER BY MonthNo) AS ChangeAmount
FROM (VALUES(1,100),(2,130),(3,120)) S(MonthNo,Amount);
MonthNoAmountChangeAmount
1100NULL
213030
3120-10

برای درصد رشد، مخرج را با NULLIF محافظت کنید و نوع اعشاری مناسب به کار ببرید.

مثال 9: تفاوت ترتیب پنجره و خروجی

شماره بر اساس Amount ساخته می‌شود ولی نمایش نهایی بر اساس ItemID است.

SELECT ItemID,Amount,ROW_NUMBER() OVER(ORDER BY Amount DESC,ItemID) AS ValueRank
FROM (VALUES(2,50),(1,70),(3,40)) D(ItemID,Amount)
ORDER BY ItemID;
ItemIDAmountValueRank
1701
2502
3403

دو ORDER BY مسئولیت جدا دارند. حذف مرتب‌سازی نهایی اجازه می‌دهد SQL Server خروجی را با هر ترتیب فیزیکی برگرداند.

مثال 10: کاهش Sort با ایندکس

ایندکس ترتیب موردنیاز پارتیشن و پنجره را فراهم می‌کند.

CREATE TABLE #O(CustomerID int,OrderDate date,OrderID int,Amount int);
INSERT #O VALUES(1,'2026-01-01',1,10),(1,'2026-01-02',2,20);
CREATE INDEX IX_O_POC ON #O(CustomerID,OrderDate,OrderID) INCLUDE(Amount);
SELECT OrderID,SUM(Amount) OVER(PARTITION BY CustomerID ORDER BY OrderDate,OrderID ROWS UNBOUNDED PRECEDING) AS rt FROM #O;
DROP TABLE #O;
OrderIDrt
110
230

وجود ایندکس تضمین حذف Sort نیست؛ فیلترها، Joinها و تخمین‌ها می‌توانند شکل Plan را تغییر دهند. Actual Plan مرجع تصمیم است.

خطاهای رایج

  • فرض اینکه ORDER BY داخل OVER خروجی نهایی را مرتب می‌کند
  • نبود کلید یکتای رفع تساوی
  • استفاده از تابع روی ستون مرتب‌سازی و از بین بردن امکان بهره‌گیری از ایندکس
  • نادیده‌گرفتن ترتیب پیش‌فرض NULLها در SQL Server

برای عیب‌یابی ابتدا نتیجه را روی Dataset بسیار کوچک دستی محاسبه کنید. سپس Actual Execution Plan را جدا از صحت منطقی بررسی کنید؛ سریع‌بودن Query پاسخ نادرست را قابل قبول نمی‌کند و پاسخ درست با Sort و Spill بزرگ نیز برای تولید آماده نیست.

ملاحظات کارایی

Sort پرهزینه‌ترین بخش بسیاری از Queryهای پنجره‌ای است. ایندکس POC یعنی Partitioning، Ordering و Covering را ارزیابی کنید و با Actual Execution Plan، Memory Grant و هشدار Spill تصمیم بگیرید.

آمارهای به‌روز، تخمین درست تعداد ردیف‌ها و Memory Grant کافی روی عملکرد اثر مستقیم دارند. قبل و بعد از تغییر ایندکس، SET STATISTICS IO, TIME ON و Actual Execution Plan را روی حجم نماینده ثبت کنید. از نتیجه یک اجرای گرم یا داده آزمایشی کوچک حکم قطعی نسازید.

ایندکس پیشنهادی باید با بار نوشتن، فضای دیسک و سایر Queryها سنجیده شود. یک ایندکس پوششی عریض ممکن است یک گزارش را سریع کند اما درج و به‌روزرسانی کل سامانه را گران‌تر سازد. Query Store برای مشاهده رفتار در طول زمان و تشخیص Regression مفید است.

بهترین روش‌ها

  • ترتیب و پارتیشن را مستقیماً از تعریف کسب‌وکار استخراج و در مستند فنی ثبت کنید.
  • برای کلیدهای تکراری سیاست روشن داشته باشید و در صورت نیاز کلید یکتای رفع تساوی اضافه کنید.
  • قاب پنجره را صریح بنویسید تا رفتار با تغییر داده یا توسعه Query مبهم نشود.
  • حالت‌های NULL، پارتیشن تک‌ردیفی، پارتیشن بزرگ و داده تکراری را در تست رگرسیون قرار دهید.
  • کارایی را با Plan واقعی و آمار IO و زمان روی حجم نماینده بسنجید، نه با حدس یا فقط Estimated Plan.
  • از Aliasهای توصیفی استفاده کنید تا معنای ستون محاسباتی برای گزارش و API روشن بماند.

سؤالات متداول

برای شروع یادگیری عبارت ORDER BY در OVER چه پیش‌نیازی لازم است؟

آشنایی با SELECT، مرتب‌سازی، توابع تجمیعی و ترتیب منطقی اجرای Query کافی است. سپس عبارت ORDER BY در OVER را روی چند ردیف کوچک با مقدار تکراری و NULL آزمایش کنید تا مرز پنجره فقط حفظ نشود، بلکه مشاهده شود.

چگونه صحت نتیجه عبارت ORDER BY در OVER را با یک تست کوچک بررسی کنیم؟

یک مجموعه داده VALUES با سه تا پنج ردیف بسازید، نتیجه مورد انتظار را دستی حساب کنید و ستون حاصل از عبارت ORDER BY در OVER را مقایسه نمایید. تست باید حالت عادی، تساوی، NULL و مرز پارتیشن را جداگانه پوشش دهد.

کاربرد تجاری عبارت ORDER BY در OVER در گزارش مدیریتی چیست؟

عبارت ORDER BY در OVER امکان ساخت KPI، رتبه‌بندی، روند، سهم از کل و مانده تجمعی را بدون حذف جزئیات فراهم می‌کند. این ویژگی Dataset گزارش را ساده‌تر می‌کند و تعداد رفت‌وبرگشت‌های لایه برنامه به دیتابیس را کاهش می‌دهد.

آیا عبارت ORDER BY در OVER برای سامانه‌های مالی و فروش مناسب است؟

بله، به شرط آنکه ترتیب قطعی، نوع داده دقیق و مرز محاسبه مستند باشد. در پروژه مالی لازم است خروجی با داده مرجع تطبیق داده شود و برای حجم واقعی، Query Store و Actual Execution Plan نیز بررسی شوند.

تفاوت عبارت ORDER BY در OVER با GROUP BY یا روش تجمیع سنتی چیست؟

GROUP BY ردیف‌ها را در سطح گروه خلاصه می‌کند، ولی عبارت ORDER BY در OVER در چارچوب تابع پنجره‌ای معمولاً جزئیات را حفظ می‌کند. انتخاب درست به شکل خروجی نیازمند وابسته است و هیچ‌یک جایگزین مطلق دیگری نیست.

برای پیاده‌سازی حرفه‌ای عبارت ORDER BY در OVER چه خدماتی مفید است؟

بازبینی مدل داده، طراحی شاخص‌ها، تهیه تست رگرسیون، تحلیل Execution Plan و مشاوره SQL Server بیشترین ارزش را دارند. در پروژه حساس بهتر است منطق عبارت ORDER BY در OVER همراه تعریف KPI و نمونه مورد انتظار تحویل شود.

رایج‌ترین خطای توسعه‌دهندگان هنگام استفاده از عبارت ORDER BY در OVER چیست؟

خطای پرتکرار، فرض‌کردن ترتیب یا قاب پیش‌فرض و بی‌توجهی به مقادیر مساوی است. نسخه صحیح باید کلید رفع تساوی، رفتار NULL و تفاوت ترتیب پنجره با ترتیب نهایی را صریح کند.

چگونه کارایی Query دارای عبارت ORDER BY در OVER را بهبود دهیم؟

ابتدا تعداد ردیف ورودی را با فیلتر SARGable کاهش دهید، سپس ایندکس هماهنگ با پارتیشن و ترتیب را ارزیابی کنید. Sort، Window Spool، Memory Grant و Spill به tempdb در طرح واقعی باید اندازه‌گیری شوند.

بهترین روش نگهداری Queryهای مبتنی بر عبارت ORDER BY در OVER چیست؟

نام‌گذاری روشن Aliasها، قاب صریح، کامنت درباره سیاست تساوی، تست داده مرزی و ثبت Baseline کارایی بهترین روش است. Query باید در Code Review همراه Execution Plan نمونه و انتظار کسب‌وکار بررسی شود.

عبارت ORDER BY در OVER در کدام نسخه‌های SQL Server قابل استفاده است؟

قابلیت‌های اصلی Window Functions از SQL Server 2012 به بعد گسترده و پایدارند، هرچند برخی توابع یا بهبودهای Optimizer میان نسخه‌ها تفاوت دارند. Compatibility Level و مستندات نسخه مقصد را پیش از استقرار کنترل کنید.

سؤالات مصاحبه

  1. تفاوت نقش عبارت ORDER BY در OVER در تعریف پنجره با مرتب‌سازی نهایی نتیجه چیست؟
  2. در چه شرایطی استفاده نادرست از عبارت ORDER BY در OVER پاسخ تحلیلی را غیرقطعی می‌کند؟
  3. برای بررسی کارایی Query دارای عبارت ORDER BY در OVER کدام بخش‌های Execution Plan را کنترل می‌کنید؟
  4. چگونه یک تست کوچک برای اثبات رفتار عبارت ORDER BY در OVER در حضور مقادیر تکراری می‌نویسید؟
  5. چه ایندکسی می‌تواند Sort و خواندن داده در سناریوی عبارت ORDER BY در OVER را کاهش دهد؟

چک‌لیست نهایی

  • صحت پارتیشن تأیید شده است.
  • ORDER BY قطعی و سیاست تساوی مشخص است.
  • قاب پیش‌فرض یا صریح آگاهانه انتخاب شده است.
  • نتیجه NULL و داده مرزی تست شده است.
  • Actual Execution Plan و Spill بررسی شده است.
  • ایندکس پیشنهادی با هزینه نوشتن سنجیده شده است.

جمع‌بندی

عبارت ORDER BY در OVER زمانی قابل اعتماد است که مرز داده، ترتیب و رفتار ردیف‌های هم‌ارزش صریح باشند. مثال‌های این مقاله نشان دادند چگونه از پاسخ ساده به Query قابل استقرار برسیم و هم‌زمان صحت، خوانایی و کارایی را کنترل کنیم.

برای مقایسه این قابلیت با سایر اجزای پنجره‌ای، به مقاله مادر Window Clauses در SQL Server بازگردید و نمونه‌ها را روی ساختار جدول واقعی پروژه خود بازنویسی کنید.

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

حرف 500 حداکثر

اطلاعات تماس

  • آدرس:اصفهان-خیابان ام کلثوم غربی - بعد خیابان تخم چی - بیست متر بعد از پیتزا ننه شب - کوچه تعمیر گاه سمار زغالی - پلاک 354 - درب مشکی - طبقه هفتم
  • آدرس ایمیل:najafzade@gmail.com
  • وب سایت:http://www.a00b.com/
  • تلفن ثابت:(+98)9131253620
  • تلفن همراه:09131253620