آموزش sys.dm_exec_session_wait_stats؛ تحلیل Wait هر Session در SQL Server
نمای sys.dm_exec_session_wait_stats آمار انتظار را به تفکیک Session نگهداری میکند و پلی میان نمای کلان نمونه و فعالیت یک اتصال مشخص است. وقتی یک برنامه، Login یا Host خاص کند گزارش میشود، این تفکیک میتواند دامنه بررسی را بسیار کوچکتر کند.
دادههای هر Session از زمان باز شدن اتصال یا آخرین Reset آن تجمع پیدا میکنند و با پایان اتصال از بین میروند. Connection Pool نیز میتواند آمار Session را هنگام Reset اتصال صفر کند؛ بنابراین مقایسه بدون توجه به Login Time، افت Counter و تعداد درخواستهای اجراشده میتواند گمراهکننده باشد.
این DMV بهتنهایی فقط شناسه Session و Wait Type را دارد. اتصال آن به sys.dm_exec_sessions و sys.dm_exec_requests اطلاعاتی مانند نام برنامه، میزبان، کاربر، وضعیت درخواست و زمان شروع را اضافه میکند.
برای Connection Poolها باید محتاط بود: یک Session فیزیکی ممکن است چند درخواست منطقی را در طول عمر خود اجرا کند. اگر هدف نسبت دادن انتظار به یک عملیات خاص است، Snapshot کوتاه، Query Store یا Extended Events شواهد دقیقتری فراهم میکنند.
این مقاله یکی از بخشهای راهنمای جامع Wait Statistics در SQL Server است و مثالها را از مشاهده پایه تا نمونهبرداری و نکات عملیاتی پیش میبرد.
DMV یک منبع شواهد است، نه نسخه درمان. بازه، Uptime، شدت بار و اثر کاربری را پیش از هر تصمیم ثبت کنید.
تعریف و کاربرد sys.dm_exec_session_wait_stats
sys.dm_exec_session_wait_stats برای آمار انتظار به تفکیک نشست استفاده میشود. خروجی آن باید در کنار هدف تشخیص، نسخه SQL Server و Counterهای مکمل خوانده شود تا میان نشانه و علت ریشهای اشتباه نشود.
در محیط Production بهتر است Query مشاهدهای، محدود و قابل ثبت باشد. هر اقدام تغییردهنده مانند Reset Counter یا خاتمه Session باید جدا از مرحله مشاهده، با مجوز و برنامه بازگشت انجام شود.
نحو پایه
SELECT *
FROM sys.dm_exec_session_wait_stats;
ستونها و معنای آنها
| ستون | توضیح |
|---|
| session_id | شناسه Session که انتظارهای تجمعی به آن تعلق دارد. |
| wait_type | نوع انتظار ثبتشده برای Session. |
| waiting_tasks_count | تعداد دفعات انتظار این Session از نوع مشخص. |
| wait_time_ms | کل زمان انتظار تجمعی Session بر حسب میلیثانیه. |
| max_wait_time_ms | بیشترین انتظار منفرد ثبتشده. |
| signal_wait_time_ms | زمان انتظار برای دریافت CPU پس از آماده شدن منبع. |
نوع خروجی و دامنه Counter
خروجی یک Rowset از Counterهای تجمعی است. مقادیر از زمان آغاز دامنه مربوط رشد میکنند و برای تحلیل بازهای باید دو Snapshot معتبر با زمان ثبتشده مقایسه شوند.
پیشنیاز دسترسی و ملاحظات نسخه
مشاهده DMVهای سطح سرور نیازمند مجوز مناسب است. در نسخههای قدیمی معمولاً VIEW SERVER STATE مطرح است و در SQL Server 2022 بسیاری از اطلاعات کارایی به VIEW SERVER PERFORMANCE STATE منتقل شدهاند. در Azure SQL و سرویسهای مدیریتشده، دامنه دید و نقش لازم ممکن است متفاوت باشد.
برای حفظ اصل کمترین دسترسی، مجوز را به حساب Collector یا نقش مانیتورینگ محدود کنید و دسترسی به متن Query را جداگانه ارزیابی نمایید. خروجی تشخیصی ممکن است نام کاربر، برنامه، Object یا متن حساس داشته باشد.
مثالهای عملی
مثال ۱: نمایش انتظارهای Session جاری
برای یادگیری ساختار DMV میتوان آمار اتصال فعلی را مشاهده کرد.
SELECT
session_id,
wait_type,
waiting_tasks_count,
wait_time_ms
FROM sys.dm_exec_session_wait_stats
WHERE session_id = @@SPID
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | wait_type |
| 57 | ASYNC_NETWORK_IO |
اگر Session تازه باشد ممکن است ردیفهای کمی ببینید؛ چند Query اجرا کرده و دوباره نتیجه را بررسی کنید.
مثال ۲: ده Session با بیشترین زمان انتظار
این Query مجموع زمان انتظار هر Session را محاسبه و اتصالات پرانتظار را اولویتبندی میکند.
SELECT TOP (10)
session_id,
SUM(wait_time_ms) AS total_wait_ms
FROM sys.dm_exec_session_wait_stats
GROUP BY session_id
ORDER BY total_wait_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | total_wait_ms |
| 81 | 93200 |
| 64 | 71500 |
عمر Session را کنار این عدد قرار دهید؛ مجموع بالا برای Connection Pool قدیمی طبیعیتر است.
مثال ۳: اتصال Waitها به نام برنامه و کاربر
Join با sys.dm_exec_sessions مشخص میکند کدام برنامه و Login به Session تعلق دارد.
SELECT TOP (20)
S.session_id,
S.login_name,
S.host_name,
S.program_name,
W.wait_type,
W.wait_time_ms
FROM sys.dm_exec_sessions AS S
INNER JOIN sys.dm_exec_session_wait_stats AS W
ON W.session_id = S.session_id
WHERE S.is_user_process = 1
ORDER BY W.wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| program_name | wait_type |
| OrderService | WRITELOG |
| ReportPortal | ASYNC_NETWORK_IO |
نام برنامه برای جهتدهی مفید است، ولی باید با Query و تیم مالک سرویس تطبیق داده شود.
مثال ۴: نمایش انتظارهای Sessionهای دارای Request فعال
این Query تاریخچه Session را فقط برای اتصالهایی نشان میدهد که اکنون Request فعال دارند.
SELECT
R.session_id,
R.status,
R.command,
W.wait_type,
W.wait_time_ms
FROM sys.dm_exec_requests AS R
INNER JOIN sys.dm_exec_session_wait_stats AS W
ON W.session_id = R.session_id
WHERE R.session_id <> @@SPID
ORDER BY W.wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | status |
| 76 | suspended |
| 91 | running |
wait_type این DMV تجمعی است؛ برای Wait جاری ستون wait_type خود sys.dm_exec_requests را نیز ببینید.
مثال ۵: محاسبه سهم Signal برای هر Session
نسبت Signal Wait به کل زمان انتظار میتواند Sessionهای درگیر صف CPU را برجسته کند.
SELECT TOP (20)
session_id,
SUM(wait_time_ms) AS total_wait_ms,
SUM(signal_wait_time_ms) AS signal_wait_ms,
CAST(100.0 * SUM(signal_wait_time_ms) /
NULLIF(SUM(wait_time_ms), 0) AS decimal(6,2)) AS signal_percent
FROM sys.dm_exec_session_wait_stats
GROUP BY session_id
ORDER BY signal_percent DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | signal_percent |
| 72 | 38.20 |
| 88 | 31.75 |
NULLIF رفتار مجموعه خالی یا مجموع صفر را ایمن میکند؛ درصد را با مقدار مطلق تفسیر کنید.
مثال ۶: فیلتر Sessionهای درگیر Lock
الگوی LCK_M فقط انتظارهای خانواده قفل را برای هر Session نشان میدهد.
SELECT
session_id,
wait_type,
waiting_tasks_count,
wait_time_ms
FROM sys.dm_exec_session_wait_stats
WHERE wait_type LIKE N'LCK_M_%'
ORDER BY wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | wait_type |
| 93 | LCK_M_X |
| 94 | LCK_M_S |
برای پیدا کردن Blocker فعلی از sys.dm_os_waiting_tasks و sys.dm_exec_requests کمک بگیرید.
مثال ۷: ثبت Snapshot اول با Login Time
اضافه کردن login_time خطر اشتباه گرفتن Session بازیافتشده را کاهش میدهد.
DROP TABLE IF EXISTS #SessionWaitStart;
SELECT
S.session_id,
S.login_time,
W.wait_type,
W.waiting_tasks_count,
W.wait_time_ms
INTO #SessionWaitStart
FROM sys.dm_exec_sessions AS S
INNER JOIN sys.dm_exec_session_wait_stats AS W
ON W.session_id = S.session_id
WHERE S.is_user_process = 1;
SELECT COUNT(*) AS captured_rows
FROM #SessionWaitStart;
| ستون یا شاخص | خروجی نمونه |
|---|
| captured_rows | تفسیر |
| 248 | Snapshot نشستها ثبت شد |
برای بازه طولانی، Sessionهای پایانیافته در Snapshot دوم وجود ندارند و باید جداگانه علامتگذاری شوند.
مثال ۸: محاسبه Delta ایمن برای Sessionهای باقیمانده
Join همزمان روی session_id، login_time و wait_type احتمال مقایسه دو اتصال متفاوت را کاهش میدهد.
SELECT TOP (20)
W.session_id,
W.wait_type,
W.wait_time_ms - B.wait_time_ms AS delta_wait_ms
FROM sys.dm_exec_session_wait_stats AS W
INNER JOIN sys.dm_exec_sessions AS S
ON S.session_id = W.session_id
INNER JOIN #SessionWaitStart AS B
ON B.session_id = W.session_id
AND B.login_time = S.login_time
AND B.wait_type = W.wait_type
WHERE W.wait_time_ms >= B.wait_time_ms
ORDER BY delta_wait_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | delta_wait_ms |
| 81 | 12300 |
| 76 | 9400 |
پایان Session یا Reset ناشی از Connection Pool میتواند Counter را حذف یا کاهش دهد؛ چنین بازهای باید نامعتبر علامتگذاری شود.
مثال ۹: گزارش Sessionهای یک برنامه خاص
در رخداد سازمانی میتوان دامنه را به نام برنامهای که تیم پشتیبانی اعلام کرده محدود کرد.
DECLARE @ProgramName nvarchar(128) = N'OrderService';
SELECT
S.session_id,
S.login_name,
W.wait_type,
W.wait_time_ms
FROM sys.dm_exec_sessions AS S
INNER JOIN sys.dm_exec_session_wait_stats AS W
ON W.session_id = S.session_id
WHERE S.program_name = @ProgramName
ORDER BY W.wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| session_id | wait_type |
| 81 | WRITELOG |
| 84 | PAGEIOLATCH_SH |
پارامتر برنامه Unicode تعریف شده است و Query فقط ستونهای لازم را میخواند.
مثال ۱۰: گزارش سبک برای مانیتورینگ دورهای
بهجای خواندن همه ستونها و Sessionها، فقط کاربران فعال و Waitهای مثبت در خروجی قرار میگیرند.
SELECT TOP (50)
W.session_id,
W.wait_type,
W.wait_time_ms,
W.signal_wait_time_ms
FROM sys.dm_exec_session_wait_stats AS W
WHERE W.session_id IN
(
SELECT session_id
FROM sys.dm_exec_sessions
WHERE is_user_process = 1
)
AND W.wait_time_ms > 0
ORDER BY W.wait_time_ms DESC;
| ستون یا شاخص | خروجی نمونه |
|---|
| تعداد ردیف | سربار |
| حداکثر 50 | کنترلشده |
فاصله نمونهبرداری و حجم ذخیرهسازی را بر اساس هدف مانیتورینگ تنظیم کنید، نه بر اساس امکان اجرای سریع DMV.
نکات فنی و تفسیر حرفهای
Session Waitها برای مقایسه اجزای یک برنامه مفیدند، به شرط آنکه Sessionها با ویژگیهای مشترک مانند program_name، login_name و بازه عمر گروهبندی شوند. یک Session قدیمی معمولاً زمان تجمعی بیشتری از اتصال تازه دارد.
درخواست فعال ممکن است یک wait_type جاری در sys.dm_exec_requests داشته باشد، در حالی که این DMV تاریخچه تجمعی انواع انتظار Session از زمان باز شدن یا Reset اتصال را نشان میدهد. این دو مفهوم را نباید یکی دانست.
برای محاسبه Delta لازم است هر دو Snapshot بر اساس session_id و wait_type Join شوند. اگر Session در فاصله دو Snapshot پایان یابد یا شناسه برای اتصال دیگری دوباره استفاده شود، Login Time باید بخشی از کلید منطقی باشد.
Signal Wait بالا در چند Session پرمصرف میتواند فشار CPU را موضعی کند، اما تشخیص نهایی نیازمند مصرف CPU درخواستها، Scheduler Queue و Execution Plan است.
اطلاعات نام برنامه و میزبان قابل جعل یا خالی شدن است؛ آن را برای مسیریابی تشخیص بهکار ببرید، نه بهعنوان مدرک امنیتی قطعی.
برای هر مشاهده، زمان UTC، نام سرور، نسخه، Uptime و شناسه رخداد را همراه خروجی ثبت کنید. این Metadata امکان تشخیص Restart، مقایسه درست Snapshotها و ممیزی تصمیمها را فراهم میکند.
همبستگی زمانی به معنی علت قطعی نیست. اگر Counter با کندی همزمان رشد کرد، فرضیهای بسازید که با Query، Plan، شاخص سیستمعامل یا آزمایش کنترلشده قابل رد یا تأیید باشد.
خطاهای رایج
- مقایسه Session قدیمی با Session تازه بدون نرمالسازی عمر اتصال.
- تفسیر آمار تجمعی Session بهعنوان Wait جاری همان لحظه.
- نادیده گرفتن Connection Pool و استفاده مجدد از اتصال.
- Join کردن Snapshotها فقط با session_id و بدون login_time.
- نسبت دادن قطعی مشکل به program_name بدون شواهد تکمیلی.
خطای مشترک دیگر، ارائه خروجی DMV بدون واحد، زمان Capture و توضیح دامنه Counter است. گزارش حرفهای باید به خواننده بگوید عدد دقیقاً چه چیزی را در چه بازهای اندازه گرفته است.
ملاحظات کارایی
Query مانیتورینگ را با ستونهای موردنیاز، فیلتر مشخص و TOP معقول بنویسید. دریافت همه ردیفها در فاصله بسیار کوتاه، بهویژه همراه متن SQL یا Plan، حجم داده و سربار پردازش مخزن را افزایش میدهد.
محاسبههای تاریخی و نمودارها را روی مخزن مانیتورینگ انجام دهید. سرور Production بهتر است فقط Snapshot خام و سبک را تولید کند. خطا، Timeout، Reset و Failover را بهعنوان وضعیت داده نگه دارید و با صفر ساختگی جایگزین نکنید.
بهترین روشها
- Login Time و زمان Snapshot را همراه آمار نگهداری کنید.
- Sessionهای سیستمی را در گزارش کاربرمحور با is_user_process جدا کنید.
- برای رخداد کوتاه، Delta کوچک و نمونهبرداری هدفمند بگیرید.
- نتیجه را با requests، Query Store و متن Batch پیوند دهید.
- اطلاعات هویتی Session را داده تشخیصی بدانید، نه کنترل امنیتی.
پیش از تغییر، معیار موفقیت قابل اندازهگیری تعریف کنید و پس از تغییر همان بار و همان شاخصها را دوباره بسنجید. کاهش یک Counter داخلی زمانی ارزشمند است که Latency، Throughput یا پایداری سرویس نیز بهتر شود.
کاربرد واقعی در پروژه سازمانی
در سامانهای با چند سرویس، Snapshotهای sys.dm_exec_session_wait_stats باید با شناسه سرور، برنامه، بازه Incident و رخدادهای Deploy در یک Timeline قرار گیرند. این کار امکان میدهد تیم DBA، توسعه و زیرساخت بهجای تبادل Screenshotهای پراکنده روی یک مجموعه داده مشترک گفتگو کنند.
در Runbook تعیین کنید چه کسی Collector را اجرا میکند، چه آستانهای Incident میسازد، چه دادهای حساس است و کدام اقدام نیازمند تأیید مدیر شیفت است. فرایند روشن معمولاً بیش از یک Query پیچیده زمان رفع مشکل را کاهش میدهد.
برای داشبورد، مقدار خام، Delta، نرخ بر ثانیه، Baseline و اثر کاربری را کنار هم نمایش دهید. رنگ هشدار باید از انحراف پایدار و چندشاخصی ساخته شود تا تیم با هشدارهای بیعمل خسته نشود.
سؤالات متداول
پرسش ۱: این DMV چه تفاوتی با آمار کل نمونه دارد؟
آمار را برای هر session_id جدا میکند و بنابراین نسبت دادن الگو به برنامه یا Login آسانتر است، در حالی که sys.dm_os_wait_stats نمای تجمعی کل Instance را میدهد.
پرسش ۲: آیا داده Session پس از قطع اتصال باقی میماند؟
خیر، با پایان Session ردیفهای آن از بین میروند. برای تاریخچه باید Snapshotها را در مخزن مانیتورینگ ذخیره کنید.
پرسش ۳: چطور کندی یک سرویس تجاری را با این DMV بررسی کنیم؟
Sessionهای program_name مربوط را جدا، Delta انتظار آنها را در بازه رخداد محاسبه و سپس Requestها و Planهای همان سرویس را بررسی کنید.
پرسش ۴: آیا این تحلیل برای ظرفیتسنجی Connection Pool مفید است؟
بله، توزیع عمر اتصال، مجموع انتظار و تعداد Sessionهای همزمان میتواند Poolهای نامتوازن را آشکار کند؛ تصمیم نهایی باید با متریکهای برنامه همراه باشد.
پرسش ۵: تفاوت Wait تجمعی Session و Wait جاری Request چیست؟
اولی تاریخچه عمر Session را جمع میکند و دومی وضعیت همان لحظه Request فعال است. برای Incident زنده هر دو لازماند.
پرسش ۶: چه خروجیای برای تیم توسعه قابل تحویل است؟
گزارش program_name، login_name، بازه Delta، Waitهای غالب و نمونه Queryهای مرتبط، زبان مشترک خوبی برای خدمات عیبیابی میان DBA و توسعه میسازد.
پرسش ۷: چرا session_id بهتنهایی کلید مطمئنی برای Snapshot نیست؟
شناسه پس از پایان اتصال میتواند دوباره استفاده شود. افزودن login_time مانع مقایسه دو اتصال متفاوت با یک شماره میشود.
پرسش ۸: جمعآوری Session Wait چه سرباری دارد؟
خواندن هدفمند DMV سبک است، اما Polling بسیار پرتکرار و ذخیره همه ردیفها حجم ایجاد میکند. ستون، فیلتر و دوره نمونهبرداری را محدود کنید.
پرسش ۹: بهترین روش تحلیل Connection Pool چیست؟
Sessionها را با برنامه و Login گروهبندی، عمر اتصال را ثبت و Delta را روی بازه کوتاه محاسبه کنید. داده برنامه و Trace توزیع درخواستها را کامل میکند.
پرسش ۱۰: مجوز و سازگاری نسخه چگونه است؟
DMV در نسخههای جدید SQL Server وجود دارد، اما دسترسی سطح سرور لازم است و در SQL Server 2022 مجوز VIEW SERVER PERFORMANCE STATE مطرح است. نسخه مقصد را بررسی کنید.
سؤالات مصاحبهای
دامنه داده sys.dm_exec_session_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_exec_session_wait_stats وقتی بیشترین ارزش را دارد که در یک فرایند منظم اندازهگیری، تفسیر و آزمون استفاده شود. مثالهای این مقاله الگوی Query ایمن را نشان میدهند، اما آستانه و اقدام باید از Baseline و معماری واقعی شما استخراج شود.
برای دیدن ارتباط این DMV با چهار ابزار دیگر، به مقاله مادر Wait Statistics در SQL Server بازگردید.