آموزش sys.dm_os_wait_stats در SQL Server؛ تحلیل حرفهای Wait Statistics
نمای مدیریتی sys.dm_os_wait_stats تصویر تجمعی انتظارهایی را نشان میدهد که از زمان راهاندازی سرویس SQL Server یا آخرین پاکسازی شمارندهها ثبت شدهاند. این دادهها پاسخ نهایی نیستند، اما مسیر بررسی را از حدس و گمان به یک تشخیص مبتنی بر شواهد تبدیل میکنند.
هر درخواست هنگام اجرا ممکن است بخشی از زمان خود را روی CPU و بخشی را در انتظار منبعی مانند دیسک، قفل، حافظه، شبکه یا صف زمانبندی بگذراند. جمع شدن این توقفها در سطح نمونه کمک میکند الگوی غالب فشار را ببینیم، ولی برای رسیدن به علت ریشهای باید بازه زمانی، بار کاری و تغییرات سامانه را نیز لحاظ کنیم.
مهمترین اصل این است که مقادیر DMV تجمعیاند. بنابراین مرتبسازی یک Snapshot قدیمی ممکن است مشکلاتی را برجسته کند که دیگر وجود ندارند. روش حرفهای، ثبت دو Snapshot و تحلیل اختلاف آنها در بازهای مشخص و مرتبط با رخداد کندی است.
همچنین همه Wait Typeها مشکل نیستند. انتظارهای پسزمینه و صفهای داخلی مانند چرخههای خواب موتور میتوانند عدد بزرگی بسازند، در حالی که هیچ اثر مستقیمی بر تجربه کاربر ندارند. فهرست حذف باید مستند، متناسب با نسخه و قابل بازبینی باشد.
این مقاله یکی از بخشهای راهنمای جامع Wait Statistics در SQL Server است و مثالها را از مشاهده پایه تا نمونهبرداری و نکات عملیاتی پیش میبرد.
DMV یک منبع شواهد است، نه نسخه درمان. بازه، Uptime، شدت بار و اثر کاربری را پیش از هر تصمیم ثبت کنید.
تعریف و کاربرد sys.dm_os_wait_stats
sys.dm_os_wait_stats برای آمار انتظارهای تجمعی در سطح نمونه SQL Server استفاده میشود. خروجی آن باید در کنار هدف تشخیص، نسخه SQL Server و Counterهای مکمل خوانده شود تا میان نشانه و علت ریشهای اشتباه نشود.
در محیط Production بهتر است Query مشاهدهای، محدود و قابل ثبت باشد. هر اقدام تغییردهنده مانند Reset Counter یا خاتمه Session باید جدا از مرحله مشاهده، با مجوز و برنامه بازگشت انجام شود.
نحو پایه
SELECT *
FROM sys.dm_os_wait_stats;
ستونها و معنای آنها
| ستون | توضیح |
|---|
| wait_type | نام نوع انتظار که حوزه منبع یا فعالیت داخلی را مشخص میکند. |
| waiting_tasks_count | تعداد دفعاتی که Taskها وارد این نوع انتظار شدهاند. |
| wait_time_ms | کل زمان انتظار شامل زمان منبع و زمان صف Runnable، بر حسب میلیثانیه. |
| max_wait_time_ms | بیشترین زمان ثبتشده برای یک انتظار از این نوع. |
| signal_wait_time_ms | بخشی از زمان که Task پس از آمادهشدن منبع، برای دریافت CPU منتظر مانده است. |
نوع خروجی و دامنه Counter
خروجی یک Rowset از Counterهای تجمعی است. مقادیر از زمان آغاز دامنه مربوط رشد میکنند و برای تحلیل بازهای باید دو Snapshot معتبر با زمان ثبتشده مقایسه شوند.
پیشنیاز دسترسی و ملاحظات نسخه
مشاهده DMVهای سطح سرور نیازمند مجوز مناسب است. در نسخههای قدیمی معمولاً VIEW SERVER STATE مطرح است و در SQL Server 2022 بسیاری از اطلاعات کارایی به VIEW SERVER PERFORMANCE STATE منتقل شدهاند. در Azure SQL و سرویسهای مدیریتشده، دامنه دید و نقش لازم ممکن است متفاوت باشد.
برای حفظ اصل کمترین دسترسی، مجوز را به حساب Collector یا نقش مانیتورینگ محدود کنید و دسترسی به متن Query را جداگانه ارزیابی نمایید. خروجی تشخیصی ممکن است نام کاربر، برنامه، Object یا متن حساس داشته باشد.
مثالهای عملی
مثال ۱: نمایش ده انتظار غالب
این Query یک نمای اولیه از Wait Typeهای دارای زمان مثبت میسازد و برای شروع بررسی مناسب است.
SELECT TOP (10)
wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_time_ms > 0
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | wait_time_ms |
| CXPACKET | 125000 |
| PAGEIOLATCH_SH | 82000 |
خروجی فقط جهت اولویتبندی است؛ انتظار اول الزاماً علت ریشهای کندی نیست.
مثال ۲: حذف انتظارهای معمول پسزمینه
در گزارش مدیریتی میتوان چند انتظار شناختهشده پسزمینه را حذف کرد تا سیگنال مفیدتر دیده شود.
SELECT TOP (15)
wait_type,
wait_time_ms,
waiting_tasks_count
FROM sys.dm_os_wait_stats
WHERE wait_type NOT IN
(
N'SLEEP_TASK',
N'BROKER_TASK_STOP',
N'LAZYWRITER_SLEEP',
N'SQLTRACE_BUFFER_FLUSH'
)
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | کاربرد بررسی |
| WRITELOG | مسیر Transaction Log |
| LCK_M_X | Blocking و تراکنش |
فهرست حذف را نسخهبندی کنید؛ یک Wait Type در همه سامانهها بیاهمیت نیست.
مثال ۳: محاسبه زمان انتظار منبع و سیگنال
تفکیک Resource از Signal کمک میکند فشار منبع را از صف CPU جدا کنیم.
SELECT TOP (10)
wait_type,
wait_time_ms,
signal_wait_time_ms,
wait_time_ms - signal_wait_time_ms AS resource_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_time_ms > 0
ORDER BY resource_wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | resource_wait_time_ms |
| PAGEIOLATCH_SH | 76000 |
| SOS_SCHEDULER_YIELD | 4000 |
برای نتیجه قطعی، این محاسبه را با CPU سیستمعامل و sys.dm_os_schedulers تطبیق دهید.
مثال ۴: محاسبه سهم درصدی انتظارها
در این مثال سهم هر Wait Type از مجموع انتظارهای انتخابشده محاسبه میشود و NULLIF از تقسیم بر صفر جلوگیری میکند.
WITH W AS
(
SELECT wait_type, wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_time_ms > 0
), T AS
(
SELECT SUM(wait_time_ms) AS total_wait_ms
FROM W
)
SELECT TOP (10)
W.wait_type,
CAST(100.0 * W.wait_time_ms /
NULLIF(T.total_wait_ms, 0) AS decimal(6,2)) AS wait_percent
FROM W
CROSS JOIN T
ORDER BY wait_percent DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | wait_percent |
| CXCONSUMER | 31.40 |
| WRITELOG | 18.75 |
در بازههای کمبار درصد بزرگ ممکن است از مقدار مطلق ناچیز ساخته شده باشد؛ هر دو را گزارش کنید.
مثال ۵: فیلتر یک خانواده انتظار
برای تمرکز روی I/O مربوط به صفحات داده میتوان خانواده PAGEIOLATCH را جدا کرد.
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
max_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type LIKE N'PAGEIOLATCH%'
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | max_wait_time_ms |
| PAGEIOLATCH_SH | 940 |
| PAGEIOLATCH_EX | 510 |
این الگو را همراه Latency فایلها، Page Life Expectancy و Execution Planهای Scan-heavy بررسی کنید.
مثال ۶: محاسبه میانگین هر انتظار با مدیریت صفر
تقسیم زمان کل بر تعداد رخداد، شدت متوسط را نشان میدهد. NULLIF جلوی خطای تقسیم بر صفر را میگیرد.
SELECT TOP (20)
wait_type,
waiting_tasks_count,
CAST(wait_time_ms * 1.0 /
NULLIF(waiting_tasks_count, 0) AS decimal(18,2)) AS avg_wait_ms
FROM sys.dm_os_wait_stats
WHERE wait_time_ms > 0
ORDER BY avg_wait_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | avg_wait_ms |
| LCK_M_X | 420.50 |
| WRITELOG | 3.25 |
میانگین بالا با تعداد بسیار کم را از الگوی پرتکرار جدا تحلیل کنید.
مثال ۷: ساخت Snapshot اول برای تحلیل Delta
این Query Snapshot فعلی را در جدول موقت نگه میدارد تا پس از یک بازه کاری اختلاف محاسبه شود.
DROP TABLE IF EXISTS #WaitStart;
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms
INTO #WaitStart
FROM sys.dm_os_wait_stats;
SELECT COUNT(*) AS captured_wait_types
FROM #WaitStart;
| ستون یا شاخص | خروجی نمونه |
|---|
| captured_wait_types | وضعیت |
| 184 | Snapshot اول ثبت شد |
جدول موقت فقط در همان Session باقی میماند؛ برای مانیتورینگ دائمی از جدول مدیریتی استفاده کنید.
مثال ۸: محاسبه Delta پس از Snapshot
پس از اجرای Snapshot قبلی و گذشت بازه موردنظر، اختلاف شمارندههای جاری با مقادیر آغاز محاسبه میشود.
SELECT TOP (10)
C.wait_type,
C.wait_time_ms - S.wait_time_ms AS delta_wait_ms,
C.waiting_tasks_count - S.waiting_tasks_count AS delta_tasks
FROM sys.dm_os_wait_stats AS C
INNER JOIN #WaitStart AS S
ON S.wait_type = C.wait_type
WHERE C.wait_time_ms >= S.wait_time_ms
ORDER BY delta_wait_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_type | delta_wait_ms |
| WRITELOG | 12400 |
| LCK_M_S | 7800 |
اگر سرویس یا شمارندهها در میانه بازه Reset شوند، اختلاف منفی یا نامعتبر است و باید Snapshot کنار گذاشته شود.
مثال ۹: ثبت Snapshot قابل گزارشگیری
در پروژه سازمانی میتوان Snapshot را با زمان UTC در یک جدول موقت ساخت و سپس به مخزن مانیتورینگ منتقل کرد.
DROP TABLE IF EXISTS #WaitSnapshot;
SELECT
SYSUTCDATETIME() AS captured_at_utc,
@@SERVERNAME AS server_name,
wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms
INTO #WaitSnapshot
FROM sys.dm_os_wait_stats;
SELECT TOP (5) *
FROM #WaitSnapshot
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| captured_at_utc | server_name |
| 2026-07-22 08:30:00 | SQL-PROD-01 |
برای ذخیره دائمی، ایندکس زمان و سرور را متناسب با الگوی نگهداری و گزارش طراحی کنید.
مثال ۱۰: پاکسازی کنترلشده شمارندهها
این دستور شمارندههای Wait Statistics را صفر میکند و فقط باید با مجوز، Snapshot قبلی و برنامه مانیتورینگ اجرا شود.
-- فقط در بازه کنترلشده و پس از ثبت Snapshot اجرا شود.
DBCC SQLPERF(N'sys.dm_os_wait_stats', CLEAR);
SELECT SUM(wait_time_ms) AS wait_time_after_clear
FROM sys.dm_os_wait_stats;
| ستون یا شاخص | خروجی نمونه |
|---|
| wait_time_after_clear | تفسیر |
| مقدار نزدیک صفر | شمارندهها تازه آغاز شدهاند |
در Production معمولاً محاسبه Delta بهتر از Clear است، زیرا تاریخچه و پیوستگی Baseline حفظ میشود.
نکات فنی و تفسیر حرفهای
اختلاف wait_time_ms و signal_wait_time_ms نمای تقریبی زمان انتظار منبع را میسازد. بالا بودن نسبت Signal میتواند نشانه فشار CPU، Runnable Queue طولانی، تعداد Worker نامتناسب یا کوئریهای پرمصرف باشد؛ با این حال تصمیم باید با Schedulerها، مصرف CPU سیستمعامل و Query Store تطبیق داده شود.
آمار زیاد PAGEIOLATCH معمولاً توجه را به مسیر I/O، حافظه و الگوی Scan جلب میکند، در حالی که WRITELOG میتواند به سرعت Log، اندازه تراکنش و دفعات Commit مربوط باشد. انتظارهای Lock نیز باید همراه Blocking Chain و متن درخواستهای فعال بررسی شوند.
مقایسه مقدار مطلق میان دو سرور یا دو بازه بدون نرمالسازی گمراهکننده است. مدت Uptime، تعداد درخواست، حجم تراکنش و شدت بار باید در کنار مجموع میلیثانیه انتظار ثبت شود. نرخ انتظار در ثانیه یا انتظار بهازای هر تراکنش برای مقایسه مناسبتر است.
پاکسازی شمارندهها یک عمل تشخیصی کنترلشده است، نه کاری روزمره. این کار تاریخچه تجمعی را از بین میبرد و میتواند روندهای مانیتورینگ را قطع کند. در محیط Production معمولاً ذخیره Snapshotها و محاسبه Delta انتخاب ایمنتری است.
این DMV داده سطح نمونه میدهد و بهتنهایی نام Query یا Session عامل را مشخص نمیکند. پس از شناسایی خانواده انتظار، باید به DMVهای زنده، Query Store، Extended Events، Execution Plan و شاخصهای سیستمعامل حرکت کرد.
برای هر مشاهده، زمان UTC، نام سرور، نسخه، Uptime و شناسه رخداد را همراه خروجی ثبت کنید. این Metadata امکان تشخیص Restart، مقایسه درست Snapshotها و ممیزی تصمیمها را فراهم میکند.
همبستگی زمانی به معنی علت قطعی نیست. اگر Counter با کندی همزمان رشد کرد، فرضیهای بسازید که با Query، Plan، شاخص سیستمعامل یا آزمایش کنترلشده قابل رد یا تأیید باشد.
خطاهای رایج
- تفسیر بزرگترین مقدار تجمعی بدون دانستن زمان شروع شمارندهها.
- حذف یک فهرست ثابت از Wait Typeها بدون توجه به نسخه و معماری سامانه.
- برابر دانستن Correlation با Causation و تغییر تنظیمات سرور فقط بر اساس یک انتظار.
- تمرکز بر درصدها هنگامی که مجموع انتظار در بازه بسیار کم است.
- اجرای DBCC SQLPERF با گزینه CLEAR بدون ثبت Snapshot و هماهنگی تیم مانیتورینگ.
خطای مشترک دیگر، ارائه خروجی DMV بدون واحد، زمان Capture و توضیح دامنه Counter است. گزارش حرفهای باید به خواننده بگوید عدد دقیقاً چه چیزی را در چه بازهای اندازه گرفته است.
ملاحظات کارایی
Query مانیتورینگ را با ستونهای موردنیاز، فیلتر مشخص و TOP معقول بنویسید. دریافت همه ردیفها در فاصله بسیار کوتاه، بهویژه همراه متن SQL یا Plan، حجم داده و سربار پردازش مخزن را افزایش میدهد.
محاسبههای تاریخی و نمودارها را روی مخزن مانیتورینگ انجام دهید. سرور Production بهتر است فقط Snapshot خام و سبک را تولید کند. خطا، Timeout، Reset و Failover را بهعنوان وضعیت داده نگه دارید و با صفر ساختگی جایگزین نکنید.
بهترین روشها
- Snapshotها را با زمان UTC، نام سرور، Uptime و شناسه بازه نگهداری کنید.
- Delta را در بازه رخداد کندی محاسبه و با Baseline همان روز و ساعت مقایسه کنید.
- هم مقدار کل، هم تعداد انتظار، هم میانگین و هم Resource/Signal را کنار هم ببینید.
- برای هر خانواده انتظار Playbook مشخص و شواهد تکمیلی تعریف کنید.
- پس از هر تغییر، همان شاخصها را دوباره اندازهگیری و اثر واقعی را ثبت کنید.
پیش از تغییر، معیار موفقیت قابل اندازهگیری تعریف کنید و پس از تغییر همان بار و همان شاخصها را دوباره بسنجید. کاهش یک Counter داخلی زمانی ارزشمند است که Latency، Throughput یا پایداری سرویس نیز بهتر شود.
کاربرد واقعی در پروژه سازمانی
در سامانهای با چند سرویس، Snapshotهای sys.dm_os_wait_stats باید با شناسه سرور، برنامه، بازه Incident و رخدادهای Deploy در یک Timeline قرار گیرند. این کار امکان میدهد تیم DBA، توسعه و زیرساخت بهجای تبادل Screenshotهای پراکنده روی یک مجموعه داده مشترک گفتگو کنند.
در Runbook تعیین کنید چه کسی Collector را اجرا میکند، چه آستانهای Incident میسازد، چه دادهای حساس است و کدام اقدام نیازمند تأیید مدیر شیفت است. فرایند روشن معمولاً بیش از یک Query پیچیده زمان رفع مشکل را کاهش میدهد.
برای داشبورد، مقدار خام، Delta، نرخ بر ثانیه، Baseline و اثر کاربری را کنار هم نمایش دهید. رنگ هشدار باید از انحراف پایدار و چندشاخصی ساخته شود تا تیم با هشدارهای بیعمل خسته نشود.
سؤالات متداول
پرسش ۱: sys.dm_os_wait_stats دقیقاً چه چیزی را اندازهگیری میکند؟
زمان و تعداد انتظارهای تجمعی Taskهای SQL Server را به تفکیک Wait Type نشان میدهد. این آمار از شروع سرویس یا آخرین Reset جمع شده و برای تعیین جهت بررسی کارایی استفاده میشود.
پرسش ۲: آیا بزرگترین Wait Type همیشه مشکل اصلی است؟
خیر. بعضی انتظارها فعالیت طبیعی پسزمینهاند و مقدار تجمعی نیز ممکن است مربوط به گذشته باشد. باید Delta بازه کندی و شواهد مکمل مانند Plan، I/O و Blocking را بررسی کرد.
پرسش ۳: برای گزارش مدیریتی Wait Statistics چه خروجیای مناسب است؟
نمودار Delta زمان انتظار، نرخ انتظار در ثانیه، تعداد رخداد و تفکیک Resource و Signal در کنار Baseline خروجی قابلفهمی میسازد. طراحی داشبورد و مشاوره مانیتورینگ میتواند این داده خام را عملیاتی کند.
پرسش ۴: آیا تحلیل این DMV میتواند هزینه زیرساخت را کاهش دهد؟
بله، زیرا پیش از خرید CPU، RAM یا Storage مشخص میکند فشار واقعی در کدام مسیر است. این تحلیل مانع ارتقای حدسی میشود و سرمایهگذاری را به گلوگاه اندازهگیریشده هدایت میکند.
پرسش ۵: تفاوت sys.dm_os_wait_stats و sys.dm_exec_session_wait_stats چیست؟
اولی آمار تجمعی کل نمونه را میدهد و دومی انتظارها را به Session تفکیک میکند. برای دید کلان از اولی و برای نزدیک شدن به مصرفکننده یا برنامه خاص از دومی استفاده میشود.
پرسش ۶: چه زمانی به خدمات Performance Tuning نیاز داریم؟
وقتی Wait غالب پایدار است اما علت در Plan، طراحی ایندکس، معماری تراکنش یا زیرساخت روشن نیست، بررسی تخصصی میتواند زنجیره علت را کامل و تغییر کمریسک پیشنهاد کند.
پرسش ۷: رایجترین خطا در تحلیل wait_time_ms چیست؟
نادیده گرفتن تجمعی بودن مقدار و مقایسه دو Snapshot با Uptime متفاوت است. زمان نمونهبرداری و Reset باید جزئی از داده مانیتورینگ باشد.
پرسش ۸: چگونه سربار جمعآوری را کم کنیم؟
ستونهای لازم را با فاصله نمونهبرداری معقول ثبت کنید، محاسبههای سنگین را روی مخزن مانیتورینگ انجام دهید و از اجرای Queryهای متعدد و بیهدف در فاصله کوتاه خودداری کنید.
پرسش ۹: بهترین روش برای تعیین Baseline چیست؟
چند هفته داده را در ساعتها و الگوهای کاری مشابه نگه دارید و صدکها را بهجای یک میانگین ساده بسنجید. رخدادهای Deploy و نگهداری نیز باید روی Timeline ثبت شوند.
پرسش ۱۰: این DMV در کدام نسخههای SQL Server قابل استفاده است؟
در نسخههای پشتیبانیشده SQL Server در دسترس است، اما Wait Typeها و مجوز لازم میتوانند میان نسخهها تغییر کنند. در SQL Server 2022 معمولاً VIEW SERVER PERFORMANCE STATE لازم است و باید مستندات همان نسخه کنترل شود.
سؤالات مصاحبهای
دامنه داده sys.dm_os_wait_stats چیست؟
Counterهای تجمعی را بر اساس کلید اصلی DMV ارائه میکند و برای بازه باید Delta محاسبه شود.
چرا Snapshot زماندار ضروری است؟
بدون زمان Capture نمیتوان نرخ، Delta، همبستگی با Incident یا اعتبار بازه پس از Restart را تعیین کرد.
چگونه تقسیم بر صفر را در نرخها مدیریت میکنید؟
در مخرج از NULLIF استفاده میکنیم و NULL را بهعنوان داده غیرقابل محاسبه نگه میداریم، نه اینکه همیشه آن را صفر فرض کنیم.
چه زمانی مقدار تجمعی گمراهکننده است؟
وقتی Uptime طولانی، workload تغییرکرده یا Counter در میانه مقایسه Reset شده باشد. Delta بازه همنوع راهحل اصلی است.
چگونه سربار Collector را کنترل میکنید؟
ستون و ردیف محدود، Interval هدفمند، جداسازی Snapshot خام از تحلیل و Retention چندلایه استفاده میشود.
چرا Correlation برای اثبات علت کافی نیست؟
دو متریک ممکن است از علت سوم اثر بگیرند. Query، Plan یا آزمایش کنترلشده برای کامل کردن زنجیره علت لازم است.
چکلیست نهایی
- مجوز و دامنه دید کنترل شده است.
- زمان UTC و Uptime ثبت شده است.
- واحد و دامنه Counter مشخص است.
- Snapshot با Baseline مناسب مقایسه شده است.
- NULL، Restart و Reset مدیریت شدهاند.
- شواهد مکمل برای فرضیه جمع شدهاند.
- معیار موفقیت تغییر و روش بازگشت تعریف شده است.
جمعبندی
sys.dm_os_wait_stats وقتی بیشترین ارزش را دارد که در یک فرایند منظم اندازهگیری، تفسیر و آزمون استفاده شود. مثالهای این مقاله الگوی Query ایمن را نشان میدهند، اما آستانه و اقدام باید از Baseline و معماری واقعی شما استخراج شود.
برای دیدن ارتباط این DMV با چهار ابزار دیگر، به مقاله مادر Wait Statistics در SQL Server بازگردید.