مثالهای عملی
مثال 1: نمای پایه Taskهای منتظر
در این سناریو هدف، مرتبسازی انتظارهای زنده از طولانیترین مورد است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
session_id,
exec_context_id,
wait_duration_ms,
wait_type,
blocking_session_id,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id IS NOT NULL
ORDER BY wait_duration_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| 64 | 0 | 8120 | LCK_M_X | 57 | keylock hobtid=... | نتیجه نمایشی مثال 1؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
این Snapshot است؛ برای روند تاریخی باید دوره و Timestamp نمونهبرداری را ذخیره کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 2: فقط انتظارهای دارای Blocker
در این سناریو هدف، حذف انتظارهایی است که Blocker Session ندارند. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
session_id AS blocked_session_id,
blocking_session_id,
wait_type,
wait_duration_ms,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id IS NOT NULL
AND blocking_session_id > 0
ORDER BY wait_duration_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| 64 | 57 | LCK_M_X | 8120 | keylock ... | نتیجه نمایشی مثال 2؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
برخی مقادیر منفی blocking_session_id معنای داخلی دارند؛ آنها را با Session واقعی اشتباه نگیرید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 3: افزودن Login و Program
در این سناریو هدف، نسبت دادن Task منتظر به Application و Login است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
wt.session_id,
wt.blocking_session_id,
s.login_name,
s.program_name,
wt.wait_type,
wt.wait_duration_ms
FROM sys.dm_os_waiting_tasks AS wt
LEFT JOIN sys.dm_exec_sessions AS s
ON s.session_id = wt.session_id
WHERE wt.session_id IS NOT NULL;
| خروجی نمونه | تفسیر |
|---|
| 64 | 57 | app_user | OrderApi | LCK_M_X | 8120 | نتیجه نمایشی مثال 3؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
برای شناخت Blocker باید یک Join جداگانه با alias دوم sessions روی blocking_session_id اضافه شود. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 4: اتصال Wait به Request جاری
در این سناریو هدف، قرار دادن Wait سطح Task کنار Command سطح Request است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
wt.session_id,
r.command,
r.status,
wt.wait_type,
wt.wait_duration_ms,
r.wait_resource
FROM sys.dm_os_waiting_tasks AS wt
JOIN sys.dm_exec_requests AS r
ON r.session_id = wt.session_id
AND r.request_id = wt.request_id
WHERE wt.session_id > 50;
| خروجی نمونه | تفسیر |
|---|
| 64 | UPDATE | suspended | LCK_M_X | 8120 | KEY: 7:... | نتیجه نمایشی مثال 4؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
در Request موازی چند Task به یک Request متصل میشوند؛ برای گزارش Request از تجمیع آگاهانه استفاده کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 5: گروهبندی Waitهای جاری
در این سناریو هدف، دیدن شکل غالب فشار جاری به جای ردیفهای پراکنده است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
wait_type,
COUNT_BIG(*) AS waiting_task_count,
SUM(wait_duration_ms) AS total_current_wait_ms,
MAX(wait_duration_ms) AS max_current_wait_ms
FROM sys.dm_os_waiting_tasks
WHERE session_id IS NOT NULL
GROUP BY wait_type
ORDER BY total_current_wait_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| LCK_M_X | 8 | 34520 | 8120 | نتیجه نمایشی مثال 5؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
جمع Current Wait با Wait Statistics تجمعی فرق دارد و تنها وضعیت همان لحظه را بازتاب میدهد. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 6: تمرکز بر انتظارهای Lock
در این سناریو هدف، فیلتر خانواده LCK_M برای بررسی Blocking قفل است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
session_id,
blocking_session_id,
wait_type,
wait_duration_ms,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE wait_type LIKE N'LCK[_]M[_]%'
ORDER BY wait_duration_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| 64 | 57 | LCK_M_X | 8120 | keylock ... | نتیجه نمایشی مثال 6؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
الگوی [_] باعث میشود Underline بهعنوان کاراکتر واقعی تفسیر شود، نه Wildcard. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 7: بررسی Page و Latch
در این سناریو هدف، جداکردن انتظارهای PageIOLATCH و PAGELATCH برای تشخیص مسیر ذخیرهسازی یا رقابت در حافظه است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
session_id,
wait_type,
wait_duration_ms,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE wait_type LIKE N'PAGE%LATCH%'
ORDER BY wait_duration_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| 72 | PAGEIOLATCH_SH | 240 | 7:1:4852 | نتیجه نمایشی مثال 7؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
نام شبیه است ولی علت متفاوت است؛ PAGEIOLATCH معمولاً I/O و PAGELATCH رقابت ساختار حافظه را نشان میدهد. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 8: تحلیل Workerهای Query موازی
در این سناریو هدف، نمایش Taskهای موازی یک Request بهصورت جداگانه است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SELECT
session_id,
request_id,
exec_context_id,
wait_type,
wait_duration_ms
FROM sys.dm_os_waiting_tasks
WHERE wait_type IN (N'CXPACKET', N'CXCONSUMER')
ORDER BY session_id, request_id, exec_context_id;
| خروجی نمونه | تفسیر |
|---|
| 63 | 0 | 4 | CXCONSUMER | 18 | نتیجه نمایشی مثال 8؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
CXCONSUMER اغلب پیامد طبیعی Parallelism است؛ Plan، Skew و زمان کل را پیش از تغییر MAXDOP بررسی کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 9: اعمال آستانه زمان برای حذف نویز
در این سناریو هدف، محدودکردن هشدار به Waitهای طولانیتر از SLA نمونه است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @MinimumWaitMs bigint = 1000;
SELECT
session_id,
blocking_session_id,
wait_type,
wait_duration_ms,
resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id IS NOT NULL
AND wait_duration_ms >= @MinimumWaitMs
ORDER BY wait_duration_ms DESC;
| خروجی نمونه | تفسیر |
|---|
| 64 | 57 | LCK_M_X | 8120 | keylock ... | نتیجه نمایشی مثال 9؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
آستانه ثابت را برای OLTP، گزارشگیری و ETL جداگانه تنظیم کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 10: زنجیره Blocking با CTE بازگشتی
در این سناریو هدف، تبدیل Edgeهای انتظار به مسیر قابل خواندن تا Head Blocker است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
;WITH wait_edges AS
(
SELECT DISTINCT session_id, blocking_session_id
FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id > 0
), chain AS
(
SELECT session_id, blocking_session_id, 0 AS level_no,
CAST(CONVERT(varchar(11), session_id) AS varchar(max)) AS path
FROM wait_edges
WHERE blocking_session_id NOT IN (SELECT session_id FROM wait_edges)
UNION ALL
SELECT e.session_id, e.blocking_session_id, c.level_no + 1,
c.path + ' <- ' + CONVERT(varchar(11), e.session_id)
FROM wait_edges AS e
JOIN chain AS c ON e.blocking_session_id = c.session_id
)
SELECT session_id, blocking_session_id, level_no, path
FROM chain
OPTION (MAXRECURSION 100);
| خروجی نمونه | تفسیر |
|---|
| 64 | 57 | 1 | 57 <- 64 | نتیجه نمایشی مثال 10؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
Snapshot میتواند حین Query تغییر کند؛ مسیر را مدرک لحظهای بدانید و با گزارش تاریخی تأیید کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
سؤالات متداول
پرسش 1: sys.dm_os_waiting_tasks دقیقاً چه مسئلهای را در SQL Server حل میکند؟
نمای sys.dm_os_waiting_tasks انتظارهای جاری را در سطح Task نمایش میدهد و برای تشخیص زنجیره Blocking، قفل، Latch، I/O و انتظارهای موازیسازی بسیار ارزشمند است. ارزش اصلی آن زمانی آشکار میشود که سؤال عملیاتی مشخص باشد؛ مثلاً شناسایی Head Blocker، تعیین منبع انتظار یا حفظ شواهد Deadlock. خروجی باید کنار زمان رخداد و مشخصات Application نگهداری شود تا از یک Snapshot خام به پاسخ قابل اقدام برسیم.
پرسش 2: برای شروع کار با sys.dm_os_waiting_tasks چه پیشنیازی لازم است؟
ابتدا در محیط آزمایش Syntax و ستونهای نسخه نصبشده را بررسی کنید، سپس مجوز حداقلی مشاهده وضعیت را در نظر بگیرید. برای دید کامل سرور مجوز VIEW SERVER STATE یا معادل جدید آن لازم است. اجرای Query با حساب Production پرقدرت راهحل مناسبی نیست و بهتر است نقش مانیتورینگ مشخص و ممیزیشده ساخته شود.
پرسش 3: استفاده از sys.dm_os_waiting_tasks چه ارزش تجاری برای سامانه پرتراکنش دارد؟
کاهش زمان تشخیص Incident، جلوگیری از تصمیم عجولانه و کوتاهشدن اختلال مستقیمترین ارزشها هستند. وقتی داده این ابزار با SLA و مالک سرویس پیوند بخورد، تیم میتواند بین کندی عادی، Blocking زیانآور و Deadlock تکرارشونده تفاوت بگذارد و هزینه توقف را کم کند.
پرسش 4: چه زمانی برای پیادهسازی مانیتورینگ sys.dm_os_waiting_tasks به مشاوره تخصصی نیاز داریم؟
اگر رخدادها تکراری، چندپایگاهدادهای، حساس به امنیت یا دارای حجم Event بالا هستند، طراحی Baseline، Retention و Runbook تخصصی مفید است. مشاوره SQL Server باید در کنار جمعآوری داده، Query Plan، تراکنش، ایندکس و رفتار کد Application را نیز بررسی کند؛ خرید ابزار بدون فرایند پاسخگویی کافی نیست.
پرسش 5: تفاوت sys.dm_os_waiting_tasks با ابزار نزدیک آن چیست؟
dm_exec_requests یک Wait اصلی در سطح Request میدهد، ولی dm_os_waiting_tasks جزئیات Taskهای موازی و شرح منبع انتظار را آشکار میکند. انتخاب درست به این بستگی دارد که داده لحظهای، تاریخچه XML، مشخصات Session یا امکان اقدام مدیریتی لازم باشد. در عیبیابی حرفهای معمولاً چند منبع مکمل کنار هم استفاده میشوند، نه اینکه یک خروجی به تنهایی حقیقت کامل فرض شود.
پرسش 6: آیا میتوان پیادهسازی داشبورد یا پروژه sys.dm_os_waiting_tasks را به تیم متخصص سپرد؟
بله؛ تحویل حرفهای باید شامل تعریف نیاز، Queryهای کمهزینه، کنترل مجوز، ذخیره UTC، سیاست Retention، هشدار قابل تنظیم، داشبورد و Runbook اعتبارسنجیشده باشد. پیش از پذیرش پروژه، اثر مانیتورینگ روی Production و روش تست خطا نیز باید مستند شود.
پرسش 7: رایجترین خطا هنگام تحلیل sys.dm_os_waiting_tasks چیست؟
جمع مستقیم تعداد ردیفها میتواند مشکل را بزرگتر نشان دهد، زیرا یک Query موازی چند Worker منتظر دارد. خطای دوم تصمیمگیری از روی یک Snapshot بدون Baseline است. زمان رخداد، Login، Host، Database، Transaction و Query متناظر را کنار هم قرار دهید و هر مقدار NULL یا نامشخص را صادقانه حفظ کنید.
پرسش 8: آیا Query گرفتن از sys.dm_os_waiting_tasks روی Performance اثر میگذارد؟
برای کاهش نویز، انتظارهای کوتاه را با wait_duration_ms فیلتر و نتایج را پیش از اتصال به DMVهای متن و Plan محدود کنید. خود مشاهده نیز رایگان نیست، بهویژه وقتی XML، Plan یا Text برای تعداد زیادی Session استخراج شود. Period نمونهبرداری، فیلتر، سقف نگهداری و مانیتور Dropped Event باید بخشی از طراحی باشد.
پرسش 9: بهترین روش استفاده Production از sys.dm_os_waiting_tasks چیست؟
پرسش عملیاتی را از قبل تعریف کنید، کمترین ستون و Scope لازم را جمع کنید، Timestamp UTC و شناسه Incident بسازید و اقدام مخرب را از جمعآوری شواهد جدا نگه دارید. Runbook باید مرحله تأیید هویت Session، اثر Rollback، تماس با مالک سرویس و معیار پایان Incident را روشن کند.
پرسش 10: sys.dm_os_waiting_tasks در کدام نسخههای SQL Server قابل استفاده است؟
جزئیات ستون، مجوز و Eventها با نسخه و Azure SQL تفاوت دارد؛ بنابراین metadata و مستندات همان نسخه باید مرجع نهایی باشد. برای دید کامل سرور مجوز VIEW SERVER STATE یا معادل جدید آن لازم است. در ارتقا، Queryها را روی محیط Stage اجرا کنید و بهویژه قابلیتهای Undocumented یا Deprecated را با جایگزین مستند عوض کنید.