آموزش تابع PERCENTILE_CONT در SQL Server با ۱۰ مثال عملی | آموزش جامع و مثال عملی

آموزش تابع PERCENTILE_CONT در SQL Server با ۱۰ مثال عملی

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

نظرات 0

آموزش جامع تابع PERCENTILE_CONT در SQL Server با ۱۰ مثال عملی

مقدمه

تابع PERCENTILE_CONT یکی از ابزارهای مهم تحلیل پنجره‌ای در Microsoft SQL Server است و برای محاسبه میانه و صدک‌های عددی با درون‌یابی میان مقادیر مجاور به کار می‌رود. این مقاله از نحو پایه شروع می‌کند و سپس رفتار مرزی، NULL، ترتیب قطعی، سناریوی سازمانی و بهینه‌سازی را با Queryهای مستقل بررسی می‌کند.

مزیت تابع پنجره‌ای این است که جزئیات هر ردیف حفظ می‌شود و هم‌زمان محاسبه‌ای مبتنی بر ردیف‌های مرتبط در دسترس قرار می‌گیرد. این ویژگی گزارش‌سازی را از Self Joinهای شکننده، Cursor و پردازش تکراری در لایه برنامه بی‌نیاز می‌کند، مشروط بر اینکه ترتیب و پارتیشن درست تعریف شوند.

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

تعریف و منطق تابع PERCENTILE_CONT

PERCENTILE_CONT برای محاسبه میانه و صدک‌های عددی با درون‌یابی میان مقادیر مجاور استفاده می‌شود. پنجره تحلیل با OVER تعریف می‌گردد و موتور SQL Server نتیجه را بدون حذف ردیف‌های اصلی محاسبه می‌کند. این رفتار تفاوت بنیادی آن با GROUP BY است.

در طراحی حرفه‌ای باید سؤال کسب‌وکار به سه جزء تبدیل شود: مرز گروه با PARTITION BY، ترتیب منطقی با ORDER BY و در صورت نیاز Frame. سپس نوع خروجی، رفتار NULL و مقادیر هم‌رتبه بررسی می‌شود. PERCENTILE_DISC یک مقدار موجود را انتخاب می‌کند؛ PERCENTILE_CONT بین دو مقدار نیز درون‌یابی می‌کند.

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

PERCENTILE_CONT ( numeric_literal ) WITHIN GROUP ( ORDER BY numeric_expression ) OVER ( [ PARTITION BY ... ] )

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

  • scalar_expression یا عبارت مرتب‌سازی باید نوع داده مناسب و قابل پیش‌بینی داشته باشد.
  • PARTITION BY اختیاری است و در نبود آن، تمام ردیف‌های ورودی یک پارتیشن هستند.
  • ORDER BY ترتیب محاسبه را تعیین می‌کند و بهتر است با یک tie-breaker یکتا کامل شود.
  • Frame در توابع وابسته به مرز پنجره باید صریح نوشته شود؛ رفتار پیش‌فرض همیشه معادل کل پارتیشن نیست.
  • NULL باید با سیاست روشن مدیریت شود؛ صفر، رشته خالی و NULL معنای یکسان ندارند.

نوع خروجی

نوع خروجی PERCENTILE_CONT: float(53)؛ ممکن است مقداری خارج از داده‌های واقعی با درون‌یابی بسازد. در لایه گزارش، تبدیل به decimal یا متن فقط برای نمایش انجام شود و مقدار خام برای محاسبات بعدی نگه داشته شود.

نکته کلیدی: عبارت صدک باید بین صفر و یک باشد و ORDER BY این تابع فقط یک عبارت عددی می‌پذیرد.

مثال‌های عملی مستقل و قابل اجرا

مثال 1: محاسبه میانه کل داده

صدک 0.5 با PERCENTILE_CONT میانه درون‌یابی‌شده را می‌سازد.

WITH D AS (SELECT Value FROM (VALUES (10),(20),(30),(40))V(Value))
SELECT DISTINCT PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Value) OVER() AS Median FROM D;
تابعمیانه
PERCENTILE_CONT25.0

نکته کاربردی: DISTINCT فقط تکرار مقدار پنجره‌ای در خروجی نمایشی را حذف می‌کند؛ محاسبه روی همه ردیف‌ها انجام شده است.

مثال 2: صدک نودم زمان پاسخ

در پایش SLA، صدک 0.9 تجربه کاربران کند را بهتر از میانگین نشان می‌دهد.

WITH R AS (SELECT Ms FROM (VALUES (80),(90),(100),(120),(500))V(Ms))
SELECT DISTINCT PERCENTILE_CONT(0.9) WITHIN GROUP(ORDER BY Ms) OVER() AS P90 FROM R;
معیارمیلی‌ثانیه
P90348

نکته کاربردی: در گزارش SLA تعداد نمونه، بازه زمانی و سیاست حذف Outlier را کنار صدک ثبت کنید.

مثال 3: محاسبه میانه برای هر واحد

OVER(PARTITION BY) صدک را جداگانه برای هر دپارتمان محاسبه می‌کند.

WITH S AS (SELECT * FROM (VALUES (N'فروش',10),(N'فروش',30),(N'فنی',20),(N'فنی',40))V(Dept,Value))
SELECT DISTINCT Dept,PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Value) OVER(PARTITION BY Dept) AS Median FROM S;
واحدمیانه
فروش20
فنی30

نکته کاربردی: اندازه پارتیشن را نیز گزارش کنید؛ صدک گروه کوچک عدم‌قطعیت بیشتری دارد.

مثال 4: محاسبه چند صدک در یک Query

صدک‌های 25، 50 و 75 نمای فشرده‌ای از توزیع می‌سازند.

WITH D AS (SELECT Value FROM (VALUES (10),(20),(30),(40),(50))V(Value))
SELECT DISTINCT
 PERCENTILE_CONT(0.25) WITHIN GROUP(ORDER BY Value) OVER() AS P25,
 PERCENTILE_CONT(0.50) WITHIN GROUP(ORDER BY Value) OVER() AS P50,
 PERCENTILE_CONT(0.75) WITHIN GROUP(ORDER BY Value) OVER() AS P75
FROM D;
P25P50P75
203040

نکته کاربردی: مشخصات پنجره یکسان به Optimizer امکان اشتراک برخی عملیات را می‌دهد؛ طرح اجرا را بررسی کنید.

مثال 5: فیلتر براساس آستانه صدکی

ابتدا آستانه در CTE محاسبه و سپس ردیف‌های بزرگ‌تر یا مساوی آن انتخاب می‌شوند.

WITH D AS (SELECT * FROM (VALUES (1,10),(2,20),(3,30),(4,100))V(Id,Value)),
W AS (SELECT *,PERCENTILE_CONT(0.75) WITHIN GROUP(ORDER BY Value) OVER() AS P75 FROM D)
SELECT Id,Value,P75 FROM W WHERE Value>=P75 ORDER BY Value;
Idمقدارآستانه
410047.5

نکته کاربردی: محل فیلتر مهم است؛ اگر پیش از محاسبه صدک داده حذف شود، خود آستانه نیز تغییر می‌کند.

مثال 6: رفتار NULL

توابع صدکی NULLهای عبارت مرتب‌سازی را نادیده می‌گیرند، اما تعداد داده معتبر باید کنترل شود.

WITH D AS (SELECT Value FROM (VALUES (CAST(NULL AS int)),(10),(20),(30))V(Value))
SELECT COUNT(Value) AS ValidCount,MAX(P50) AS P50
FROM (SELECT Value,PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Value) OVER() AS P50 FROM D)X;
تعداد معتبرP50
320

نکته کاربردی: اگر همه مقادیر NULL باشند، نتیجه صدک NULL است؛ این حالت را در داشبورد از صفر متمایز کنید.

مثال 7: تفاوت پیوسته و گسسته

اجرای هر دو تابع روی داده زوج نشان می‌دهد درون‌یابی با انتخاب مقدار واقعی چه تفاوتی دارد.

WITH D AS (SELECT Value FROM (VALUES (10),(20),(30),(40))V(Value))
SELECT DISTINCT
 PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Value) OVER() AS ContinuousMedian,
 PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY Value) OVER() AS DiscreteMedian
FROM D;
پیوستهگسسته
2520

نکته کاربردی: برای گزارش قیمت یا سطح خدمت که باید مقدار واقعی باشد گسسته مناسب است؛ برای تحلیل آماری، پیوسته رایج‌تر است.

مثال 8: صدک حقوق در گزارش سازمانی

این سناریو آستانه حقوق را برای هر JobLevel استخراج می‌کند و مقدار را کنار هر کارمند نگه می‌دارد.

WITH E AS (SELECT * FROM (VALUES (N'کارشناس',40),(N'کارشناس',50),(N'کارشناس',70),(N'مدیر',90),(N'مدیر',120))V(LevelName,Salary))
SELECT LevelName,Salary,PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Salary) OVER(PARTITION BY LevelName) AS LevelMedian
FROM E ORDER BY LevelName,Salary;
سطححقوقمیانه سطح
کارشناس5050

نکته کاربردی: دسترسی به داده حقوق باید کنترل شود و خروجی گروه‌های کوچک برای حفظ حریم خصوصی محدود گردد.

مثال 9: اصلاح محاسبه میانگین به‌جای صدک

AVG مرکز حسابی است و در داده دارای مقدار دورافتاده جایگزین میانه یا P90 نیست.

WITH D AS (SELECT Value FROM (VALUES (10),(11),(12),(1000))V(Value))
SELECT DISTINCT AVG(1.0*Value) OVER() AS AverageValue,
 PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY Value) OVER() AS MedianValue
FROM D;
میانگینمیانه
258.2511.5

نکته کاربردی: انتخاب شاخص باید از سؤال تحلیلی بیاید؛ میانگین و صدک مکمل‌اند و یکی همیشه جای دیگری را نمی‌گیرد.

مثال 10: آماده‌سازی ایندکس و کاهش ورودی

فیلتر تاریخ قبل از محاسبه، داده نامرتبط را حذف و ایندکس پنجره را قابل استفاده‌تر می‌کند.

CREATE TABLE #Metric(ServiceId int,EventDate date,Value int);
INSERT #Metric VALUES(1,'2026-07-01',80),(1,'2026-07-02',100),(1,'2026-07-03',500),(2,'2026-07-01',50);
CREATE INDEX IX_Metric_Window ON #Metric(ServiceId,Value) INCLUDE(EventDate);
SELECT DISTINCT ServiceId,PERCENTILE_CONT(0.9) WITHIN GROUP(ORDER BY Value) OVER(PARTITION BY ServiceId) AS P90
FROM #Metric WHERE EventDate>='2026-07-01';
DROP TABLE #Metric;
کنترلمقدار
شاخص طرح اجراSort، Memory Grant و Spill

نکته کاربردی: فیلتر فقط وقتی مجاز است که دوره آماری موردنظر را دقیقاً نمایندگی کند؛ حذف داده برای سریع‌تر شدن نباید تعریف KPI را عوض کند.

خطاهای رایج و روش اصلاح

  • عبارت صدک باید بین صفر و یک باشد و ORDER BY این تابع فقط یک عبارت عددی می‌پذیرد.
  • استفاده از ORDER BY غیرقطعی؛ یک کلید یکتا به انتهای ترتیب اضافه کنید.
  • اعمال WHERE در سطح اشتباه؛ ابتدا مشخص کنید فیلتر باید جمعیت پنجره را عوض کند یا فقط خروجی را محدود نماید.
  • تبدیل نوع ضمنی در عبارت یا مقدار پیش‌فرض؛ نوع‌ها را صریح و سازگار تعریف کنید.
  • فرض اینکه خروجی تابع همیشه deterministic است؛ مستندات و ترتیب داده را برای امکان تکرار نتیجه کنترل کنید.

ملاحظات کارایی و تحلیل Execution Plan

روی داده حجیم، پیش‌تجمیع معتبر، پارتیشن‌بندی محدود و کنترل Sort/Spill اثر زیادی بر زمان اجرا دارد.

ابتدا با SET STATISTICS IO, TIME ON خط مبنا بگیرید و Actual Execution Plan را ذخیره کنید. وجود Sort بزرگ، Memory Grant بیش از نیاز یا هشدار Spill به tempdb نشانه‌ای است که ترتیب داده، برآورد Cardinality یا ظرفیت حافظه باید بررسی شود.

ایندکس پیشنهادی معمولاً با ستون‌های فیلتر برابری و PARTITION BY آغاز می‌شود، سپس ستون‌های ORDER BY و tie-breaker می‌آیند و ستون خروجی در INCLUDE قرار می‌گیرد. این یک نسخه عمومی است؛ ترتیب نهایی باید با Query واقعی، Selectivity و هزینه نگهداری DML سنجیده شود.

چند تابع پنجره‌ای با Window Specification یکسان را در یک SELECT بنویسید تا Optimizer امکان استفاده مشترک از ترتیب را داشته باشد. تفاوت کوچک در ترتیب صعودی، نزولی یا Frame می‌تواند عملگر جداگانه بسازد؛ پس طرح اجرا را پس از هر تغییر مقایسه کنید.

فیلتر دوره زمانی و ستون‌های غیرضروری را در جایی اعمال کنید که معنای تحلیل حفظ شود. کاهش عرض و تعداد ردیف ورودی، مصرف حافظه و I/O را کم می‌کند، ولی بهینه‌سازی نباید جمعیت آماری مورد نیاز را ناخواسته حذف کند.

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

  1. تعریف کسب‌وکار را پیش از نوشتن Query به پارتیشن، ترتیب و Frame تبدیل کنید.
  2. در ORDER BY از کلید یکتای پایدار برای شکستن tie استفاده کنید.
  3. NULL، پارتیشن تک‌ردیفی، مقادیر مساوی و مرزهای ابتدا و انتها را آزمون کنید.
  4. نوع داده خروجی و گرد کردن را مستند کنید و گرد کردن را تا لایه نمایش عقب بیندازید.
  5. Execution Plan، IO، CPU، Memory Grant و tempdb Spill را قبل و بعد از تغییر ثبت کنید.
  6. ایندکس را براساس بار کاری کامل طراحی کنید؛ بهبود SELECT نباید هزینه INSERT و UPDATE را نادیده بگیرد.

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

۱. تابع PERCENTILE_CONT دقیقاً چه مسئله‌ای را حل می‌کند؟

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

۲. اجزای OVER در PERCENTILE_CONT چه نقشی دارند؟

PARTITION BY مرز گروه منطقی را تعیین می‌کند و ORDER BY توالی تحلیل را می‌سازد. در توابع حساس به Frame، عبارت ROWS نیز دامنه ردیف‌های قابل مشاهده از هر ردیف را مشخص می‌کند.

۳. آیا استفاده از PERCENTILE_CONT هزینه توسعه گزارش را کم می‌کند؟

در بسیاری از گزارش‌ها حذف Self Join، Cursor یا کد میانی باعث Query کوتاه‌تر و نگهداری ساده‌تر می‌شود. برای برآورد تجاری باید حجم داده، SLA، دفعات اجرا و هزینه ایندکس نیز اندازه‌گیری شود.

۴. چه زمانی بازطراحی Queryهای قدیمی با PERCENTILE_CONT ارزش اقتصادی دارد؟

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

۵. تفاوت PERCENTILE_CONT با گزینه نزدیک آن چیست؟

PERCENTILE_DISC یک مقدار موجود را انتخاب می‌کند؛ PERCENTILE_CONT بین دو مقدار نیز درون‌یابی می‌کند. انتخاب نهایی باید براساس تعریف دقیق خروجی، رفتار tie، NULL و مرز پنجره انجام شود.

۶. برای پیاده‌سازی حرفه‌ای PERCENTILE_CONT در پروژه سازمانی چه خدمتی لازم است؟

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

۷. رایج‌ترین خطا در PERCENTILE_CONT چیست؟

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

۸. چگونه Performance تابع PERCENTILE_CONT را بسنجیم؟

روی داده حجیم، پیش‌تجمیع معتبر، پارتیشن‌بندی محدود و کنترل Sort/Spill اثر زیادی بر زمان اجرا دارد. Actual Execution Plan، SET STATISTICS IO/TIME، Memory Grant، هشدار Spill و تعداد ردیف واقعی ابزارهای اصلی اندازه‌گیری هستند.

۹. بهترین روش نوشتن PERCENTILE_CONT چیست؟

ترتیب قطعی با tie-breaker یکتا، پارتیشن متناسب با منطق کسب‌وکار، تبدیل نوع صریح و آزمون NULL و مرزها را رعایت کنید. ابتدا صحت و سپس سرعت را بهینه سازید.

۱۰. PERCENTILE_CONT با کدام نسخه‌های SQL Server سازگار است؟

SQL Server 2012 و Compatibility Level 110 یا بالاتر. در Azure SQL نیز اصل قابلیت در دسترس است، اما Compatibility Level و اصلاحات تجمعی مرتبط با IGNORE NULLS یا Optimizer باید بررسی شود.

سؤالات مصاحبه و پاسخ کوتاه

چرا PERCENTILE_CONT یک تابع پنجره‌ای است؟

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

چرا ORDER BY باید قطعی باشد؟

اگر چند ردیف کلید ترتیب یکسان داشته باشند، موتور می‌تواند ترتیب داخلی متفاوتی انتخاب کند. افزودن کلید یکتا نتیجه را تکرارپذیر و آزمون‌پذیر می‌سازد.

تفاوت WHERE داخلی و خارجی چیست؟

WHERE داخلی جمعیت ورودی پنجره را کاهش می‌دهد؛ WHERE خارجی فقط خروجی محاسبه‌شده را فیلتر می‌کند. بنابراین این دو از نظر معنا معادل نیستند.

چه چیزی را در Execution Plan بررسی می‌کنید؟

Sort، Segment، Sequence Project یا Window Aggregate، Memory Grant، Spill به tempdb، برآورد ردیف و هم‌راستایی ایندکس با PARTITION و ORDER BY بررسی می‌شوند.

آزمون واحد مناسب چیست؟

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

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

  • نحو PERCENTILE_CONT و Compatibility Level کنترل شده است.
  • پارتیشن دقیقاً مرز موجودیت کسب‌وکار است.
  • ترتیب با tie-breaker یکتا قطعی شده است.
  • Frame در صورت اثرگذاری صریح نوشته شده است.
  • حالت NULL، tie و پارتیشن کوچک آزمون شده است.
  • فیلتر داخلی و خارجی آگاهانه انتخاب شده‌اند.
  • طرح اجرا و آمار IO/TIME ثبت شده‌اند.
  • لینک مقاله مادر و نمونه‌ها پیش از انتشار کنترل شده‌اند.

جمع‌بندی

تابع PERCENTILE_CONT وقتی ارزشمند است که برای محاسبه میانه و صدک‌های عددی با درون‌یابی میان مقادیر مجاور به یک بیان مجموعه‌محور، خوانا و قابل بهینه‌سازی نیاز داشته باشیم. صحت ترتیب و پارتیشن مهم‌تر از کوتاهی ظاهری Query است و سنجش کارایی باید با داده و Plan واقعی انجام شود.

برای مقایسه PERCENTILE_CONT با هفت تابع دیگر، به مقاله مادر توابع Analytic و Window در SQL Server بازگردید.

 

0 نظر

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

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

حرف 500 حداکثر

اطلاعات تماس

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