راهنمای جامع Wait Typeهای رایج SQL Server و عیبیابی Performance
مقدمه
وقتی یک سامانه SQL Server کند میشود، نمودار CPU، حافظه و Disk فقط بخشی از داستان را نشان میدهد. موتور پایگاه داده دقیقتر میگوید workerها کجا متوقف شدهاند: منتظر خواندن صفحه، Flush لاگ، دریافت Lock، مصرف نتیجه توسط Client، گرفتن Memory Grant، Worker Thread یا هماهنگی Plan موازی. این توقفها با Wait Type نامگذاری و در Wait Stats جمع میشوند. آنها زبان مشترک میان رفتار Query، Scheduler، Storage، شبکه و همزمانی هستند.
Wait بهخودیخود خطا نیست. هر Request در چرخه Running، Runnable و Suspended جابهجا میشود و انتظار طبیعی بخشی از طراحی Cooperative Scheduling است. هدف عیبیابی صفر کردن Waitها نیست؛ هدف یافتن انتظارهایی است که در پنجره کندی رشد غیرعادی دارند، به Query یا عملیات مشخص متصل میشوند و شاخص تخصصی همان زیرسیستم آنها را تأیید میکند.
این راهنما هجده Wait Type رایج را پوشش میدهد: انتظارهای I/O صفحه داده، لاگ تراکنش، شبکه و Client، Parallelism، CPU، Memory Grant، Lock، Worker Pool، Latch حافظه، I/O عمومی، OLE DB، Backup و Always On. برای هر مورد یک مقاله مستقل با ده مثال اجرایی، خروجی نمونه، خطاهای رایج و Best Practice در دسترس است.
روش مطالعه پیشنهادی این است که ابتدا مدل اندازهگیری و جدول مقایسه را بخوانید، سپس بر اساس Wait غالب و علائم سامانه وارد مقاله تخصصی شوید. رتبه اول جدول از زمان Startup الزاماً Root Cause رخداد امروز نیست. همواره زمان، نرخ، workload، Session فعال، Plan و اثر کسبوکاری را در یک Timeline قرار دهید.
اصل عملی این مجموعه: از Wait تجمعی به Delta، از Delta به Session، از Session به Query و Plan، و از Plan به شاخص زیرسیستم بروید؛ سپس فقط یک تغییر قابل بازگشت را با معیار قبل و بعد بیازمایید.
دسترسی سریع به مقالههای تخصصی
مدل Wait در SQL Server
Scheduler در SQL Server بهصورت Cooperative کار میکند. Worker هنگام اجرای کد روی CPU در حالت Running است؛ اگر منبعی آماده نباشد، با ثبت Wait در حالت Suspended قرار میگیرد؛ و وقتی منبع آماده شد، وارد Runnable Queue میشود تا دوباره CPU بگیرد. مدت انتظار منبع و مدت انتظار Signal دو بخش متفاوتاند و جمع نادرست آنها میتواند تشخیص CPU را منحرف کند.
sys.dm_os_wait_stats شمارندهها را در سطح Instance و از شروع سرویس یا آخرین پاکسازی نگه میدارد. waiting_tasks_count تعداد آغاز انتظار، wait_time_ms زمان کل و signal_wait_time_ms بخش آمادهبهاجرا را ارائه میکند. این DMV نمیگوید کدام Database یا Query تاریخچه را ساخته است؛ برای این اتصال باید Snapshot زنده و ابزار تاریخچه Query به کار رود.
دو نوع نگاه مکمل لازم است. نگاه Historical روند و Baseline را میسازد: در ساعت مشابه هفته گذشته چه Waitهایی و با چه نرخ بر تراکنش دیده شدند؟ نگاه Live Request و Task را میگیرد: اکنون چه Sessionی، روی چه منبعی، با چه متن و Planی منتظر است؟ تنها با پیوند این دو میتوان از یک جدول آماری به اقدام مهندسی رسید.
Resource Wait و Signal Wait
Resource Wait زمانی است که Task برای آماده شدن منبعی مانند صفحه دیسک، Lock یا Memory Grant توقف دارد. Signal Wait پس از آماده شدن منبع آغاز میشود و Task در Runnable Queue منتظر CPU است. افزایش Signal Ratio همراه با Runnable Queue و CPU بالا میتواند فشار پردازنده را نشان دهد، اما نسبت تجمعی باید به Delta بازه حادثه تبدیل شود.
چرا درصد بهتنهایی کافی نیست؟
درصد یک Wait از مجموع، شاخص نسبی است. اگر یک Wait اصلاح شود، درصد Wait دیگری حتی بدون بدتر شدن عدد مطلق بالا میرود. همچنین روز پرترافیک Wait بیشتری از روز تعطیل میسازد. نرخ بر ثانیه، تراکنش یا Request و معیارهای p95 و Throughput، مقایسه را منصفانهتر میکنند.
دستهبندی منطقی Wait Typeهای این مجموعه
- I/O صفحه داده: PAGEIOLATCH_SH و PAGEIOLATCH_EX؛ شامل بافر درگیر درخواست I/O.
- لاگ تراکنش: WRITELOG؛ انتظار تکمیل Log Flush در Commit یا عملیات مرتبط.
- Client و منبع خارجی: ASYNC_NETWORK_IO و OLEDB؛ مصرف نتیجه یا پاسخ Provider خارجی.
- Parallelism: CXPACKET و CXCONSUMER؛ هماهنگی workerهای Plan موازی و سمت مصرفکننده Exchange.
- CPU و Worker: SOS_SCHEDULER_YIELD و THREADPOOL؛ رقابت CPU یا نبود Worker آزاد.
- حافظه اجرای Query: RESOURCE_SEMAPHORE؛ صف Memory Grant برای Sort و Hash.
- Lock: LCK_M_S، LCK_M_X و LCK_M_U؛ انتظار قفل اشتراکی، انحصاری یا Update.
- Latch حافظه: PAGELATCH_UP و PAGELATCH_EX؛ Contention صفحه بدون I/O فعال.
- I/O عمومی و Backup: IO_COMPLETION و BACKUPIO؛ عملیات غیرصفحهای یا Pipeline پشتیبانگیری.
- دسترسپذیری بالا: HADR_SYNC_COMMIT؛ انتظار تأیید Harden شدن Log در Replica همگام.
مرزبندی دستهها برای انتخاب ابزار بعدی مهم است. PAGEIOLATCH شامل IO است و با Latency فایل و Physical Read تحلیل میشود؛ PAGELATCH روی صفحه حافظه بدون I/O فعال است و بیشتر به Hot Page یا تخصیص tempdb مربوط میشود. همین تفاوت یک حرف میتواند مسیر درمان را از Storage به طراحی همزمانی تغییر دهد.
Waitها همچنین میتوانند زنجیره بسازند. تراکنش طولانی LCK تولید میکند، Sessionهای مسدود workerها را نگه میدارند و در نهایت THREADPOOL ظاهر میشود. Plan پرخوانش PAGEIOLATCH و CPU ایجاد میکند و Parallel Plan ممکن است CXPACKET را نیز بالا ببرد. Root Cause معمولاً با ترتیب زمانی و Head Event پیدا میشود، نه با بالاترین درصد نهایی.
جدول مقایسه Wait Typeها
| Wait Type | کاربرد اصلی | نوع خروجی یا نکته مهم | لینک آموزش کامل |
|---|
| PAGEIOLATCH_SH | انتظار خواندن صفحه داده با لچ اشتراکی | ابتدا Delta انتظار و Latency هر فایل را در یک بازه پرترافیک اندازه بگیرید؛ سپس Plan و Logical/Physical Read کوئریهای همان بازه را بررسی کنید. | آموزش کامل PAGEIOLATCH_SH |
| PAGEIOLATCH_EX | انتظار I/O صفحه داده با لچ انحصاری | فایل و دیتابیس مسئول، صفحه یا Query فعال و نسبت Read/Write آن فایل را همزمان ثبت کنید. | آموزش کامل PAGEIOLATCH_EX |
| WRITELOG | انتظار Flush شدن لاگ تراکنش | Delta WRITELOG را کنار متوسط write latency فایل Log، نرخ تراکنش و الگوی Batch/Commit اندازهگیری کنید. | آموزش کامل WRITELOG |
| ASYNC_NETWORK_IO | انتظار مصرف نتیجه توسط Client | Session، تعداد ردیف ارسالی، متن Query، مشخصات Client و زمان مصرف Result Set را با هم بررسی کنید. | آموزش کامل ASYNC_NETWORK_IO |
| CXPACKET | هماهنگی workerهای اجرای موازی | Plan واقعی، DOP، تعداد ردیف هر شاخه و CXCONSUMER را پیش از تغییر تنظیمات Instance بررسی کنید. | آموزش کامل CXPACKET |
| CXCONSUMER | انتظار سمت مصرفکننده در Plan موازی | بهجای رتبه خام انتظار، Query کند و Plan موازی آن را در بازه مسئله پیدا و نسبت CXPACKET را مقایسه کنید. | آموزش کامل CXCONSUMER |
| SOS_SCHEDULER_YIELD | واگذاری داوطلبانه Scheduler پس از مصرف CPU | Top Queryها بر اساس worker time، وضعیت Schedulerها و Plan واقعی را در همان بازه بررسی کنید. | آموزش کامل SOS_SCHEDULER_YIELD |
| RESOURCE_SEMAPHORE | انتظار دریافت حافظه اجرای Query | درخواستهای منتظر و دریافتکننده Grant، اندازه requested/required و Plan شامل Sort یا Hash را بررسی کنید. | آموزش کامل RESOURCE_SEMAPHORE |
| LCK_M_S | انتظار دریافت Shared Lock | Head Blocker، متن و Transaction باز آن را پیدا کنید و سپس Plan خواننده و نویسنده را تحلیل کنید. | آموزش کامل LCK_M_S |
| LCK_M_X | انتظار دریافت Exclusive Lock | منبع Lock، Head Blocker، زمان Transaction و ترتیب دسترسی به جدولها را ثبت کنید. | آموزش کامل LCK_M_X |
| LCK_M_U | انتظار دریافت Update Lock | Session دارنده و منتظر، حالت Lock و Queryهایی را که یک کلید مشترک را تغییر میدهند مقایسه کنید. | آموزش کامل LCK_M_U |
| THREADPOOL | انتظار دریافت Worker Thread | از Dedicated Admin Connection در رخداد شدید استفاده و Head Blocker، Scheduler و تعداد workerها را فوراً ثبت کنید. | آموزش کامل THREADPOOL |
| PAGELATCH_UP | رقابت Update Latch روی صفحه حافظه | wait_resource را به فایل و صفحه نگاشت و توزیع فایلهای tempdb و الگوی اشیای موقت را بررسی کنید. | آموزش کامل PAGELATCH_UP |
| PAGELATCH_EX | رقابت Exclusive Latch روی صفحه حافظه | wait_resource و index_operational_stats را برای یافتن فایل، صفحه و ایندکس داغ همبسته کنید. | آموزش کامل PAGELATCH_EX |
| IO_COMPLETION | انتظار تکمیل عملیات عمومی I/O | درخواستهای فعال، pending I/O و Latency تفکیکشده فایلها را در بازه رخداد ثبت کنید. | آموزش کامل IO_COMPLETION |
| OLEDB | انتظار پاسخ OLE DB Provider | متن Remote Query، Linked Server هدف، حجم داده و زمان پاسخ همان منبع را مستقل اندازه بگیرید. | آموزش کامل OLEDB |
| BACKUPIO | انتظار I/O در مسیر Backup | تاریخچه مدت و Throughput Backup را کنار Latency فایلها، مقصد و تنظیمات Compression/Stripe مقایسه کنید. | آموزش کامل BACKUPIO |
| HADR_SYNC_COMMIT | انتظار تأیید Commit از Replica همگام | زمان Commit را با log_send_queue_size، send_rate، وضعیت Synchronization و Latency Log هر دو Replica همبسته کنید. | آموزش کامل HADR_SYNC_COMMIT |
Workflow استاندارد عیبیابی
- رخداد را با Timestamp، p95، Throughput، خطا و عملیات کسبوکاری تعریف کنید.
- زمان Startup و Snapshot پایه sys.dm_os_wait_stats را ذخیره کنید.
- پس از بازه ثابت، Delta شمارندهها و نرخ بر ثانیه یا تراکنش را بسازید.
- Session و Task فعال، wait_resource، Blocker، متن Query و Plan را ثبت کنید.
- بر اساس دسته Wait، شاخص تخصصی Storage، Log، CPU، Memory، Lock، Client یا AG را جمع کنید.
- فرضیهها را بر اساس چند شاهد مستقل رتبهبندی کنید.
- یک تغییر محدود با معیار موفقیت و Script بازگشت اجرا کنید.
- تست همسطح را تکرار و Regression در Wait و SLAهای دیگر را کنترل کنید.
در Production از اجرای تغییرات همزمان پرهیز کنید. اگر ایندکس، MAXDOP و حافظه با هم عوض شوند، معلوم نیست کدام عامل نتیجه را ساخته است. Change Log باید نسخه Query، تنظیم قبلی و جدید، زمان اجرا، مالک تغییر و نتیجه قابل سنجش را نگه دارد.
Permission مانیتورینگ را حداقلی طراحی کنید. DMVهای سطح Server ممکن است مجوز مشاهده وضعیت مناسب نسخه بخواهند و متن Query داده حساس داشته باشد. حساب Read-only، Masking خروجی، Retention محدود و کنترل دسترسی بخشی از مهندسی Performance هستند.
مثالهای کاربردی جامع
مثال 1: رتبهبندی Wait Typeهای مهم پس از فیلتر انتظارهای پسزمینه
این Query یک نمای اولیه از Waitهای تجمعی میسازد و چند انتظار معمولاً idle را کنار میگذارد. فهرست حذف باید با نسخه و workload بازبینی شود و خروجی هنوز جای Delta بازهای را نمیگیرد.
WITH WaitTotals AS
(
SELECT
wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type NOT LIKE N'SLEEP%'
AND wait_type NOT IN
(N'BROKER_EVENTHANDLER', N'BROKER_RECEIVE_WAITFOR',
N'CLR_AUTO_EVENT', N'DIRTY_PAGE_POLL', N'LAZYWRITER_SLEEP',
N'XE_DISPATCHER_WAIT', N'XE_TIMER_EVENT')
)
SELECT TOP (15)
wait_type,
waiting_tasks_count,
wait_time_ms,
signal_wait_time_ms,
CAST(100.0 * wait_time_ms /
NULLIF(SUM(wait_time_ms) OVER (), 0) AS decimal(10,2)) AS wait_percent
FROM WaitTotals
ORDER BY wait_time_ms DESC;
| Wait Type | تعداد | زمان کل | سهم |
|---|
| PAGEIOLATCH_SH | 12840 | 3842000 ms | 21.40% |
| WRITELOG | 24500 | 2810000 ms | 15.66% |
رتبه بالا فقط نامزد بررسی است. زمان Startup، Jobهای دورهای، تعداد تراکنش و شکایت کاربران را کنار خروجی قرار دهید تا اولویت واقعی مشخص شود.
مثال 2: ساخت Snapshot و محاسبه Delta کل Waitها
برای مشاهده رفتار جاری، دو Snapshot با فاصله ثابت ذخیره و اختلاف آنها محاسبه میشود. در Production بهتر است این منطق توسط Job مانیتورینگ و بدون DROP داده تاریخی اجرا شود.
IF OBJECT_ID(N'tempdb..#WaitBefore') IS NOT NULL
DROP TABLE #WaitBefore;
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
INTO #WaitBefore
FROM sys.dm_os_wait_stats;
WAITFOR DELAY '00:00:05';
SELECT TOP (15)
w.wait_type,
w.waiting_tasks_count - b.waiting_tasks_count AS delta_tasks,
w.wait_time_ms - b.wait_time_ms AS delta_wait_ms,
w.signal_wait_time_ms - b.signal_wait_time_ms AS delta_signal_ms
FROM sys.dm_os_wait_stats AS w
JOIN #WaitBefore AS b ON b.wait_type = w.wait_type
WHERE w.wait_time_ms > b.wait_time_ms
ORDER BY delta_wait_ms DESC;
| Wait Type | Delta Task | Delta Wait | Delta Signal |
|---|
| SOS_SCHEDULER_YIELD | 820 | 14600 ms | 9100 ms |
| CXPACKET | 310 | 9800 ms | 420 ms |
بازه پنجثانیهای آموزشی است. برای رخدادهای Burst چند بازه کوتاه و برای Capacity Trend بازههای یک تا پنج دقیقهای با Timestamp ثبت کنید.
مثال 3: اتصال Request جاری به Waiting Task
این Query Wait، Blocker، Context و منبع انتظار را برای درخواستهای کاربر کنار هم قرار میدهد. یک Request موازی ممکن است چند ردیف Task تولید کند.
SELECT
r.session_id,
DB_NAME(r.database_id) AS database_name,
r.status,
r.wait_type AS request_wait_type,
wt.wait_type AS task_wait_type,
wt.exec_context_id,
wt.wait_duration_ms,
r.blocking_session_id,
wt.resource_description
FROM sys.dm_exec_requests AS r
LEFT JOIN sys.dm_os_waiting_tasks AS wt
ON wt.session_id = r.session_id
WHERE r.session_id > 50
AND (r.wait_type IS NOT NULL OR wt.wait_type IS NOT NULL)
ORDER BY wt.wait_duration_ms DESC;
| Session | Wait | Context | منبع |
|---|
| 74 | LCK_M_S | 0 | KEY: 7:... |
| 81 | CXPACKET | 3 | exchangeEvent |
از این خروجی برای انتخاب شاخه مقاله مرتبط استفاده کنید: Lock، Parallelism، I/O، Memory یا Worker. سپس متن Query و Plan همان Session را بگیرید.
مثال 4: محاسبه Latency فایلهای Data و Log
Waitهای I/O باید با آمار واقعی فایل اعتبارسنجی شوند. تفکیک type_desc نشان میدهد کندی خواندن Data با PAGEIOLATCH یا کندی نوشتن Log با WRITELOG همخوان است یا خیر.
SELECT
DB_NAME(vfs.database_id) AS database_name,
mf.type_desc,
mf.name,
vfs.num_of_reads,
vfs.num_of_writes,
CAST(vfs.io_stall_read_ms * 1.0 /
NULLIF(vfs.num_of_reads, 0) AS decimal(18,2)) AS avg_read_ms,
CAST(vfs.io_stall_write_ms * 1.0 /
NULLIF(vfs.num_of_writes, 0) AS decimal(18,2)) AS avg_write_ms
FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS vfs
JOIN sys.master_files AS mf
ON mf.database_id = vfs.database_id
AND mf.file_id = vfs.file_id
ORDER BY avg_read_ms DESC, avg_write_ms DESC;
| پایگاه داده | نوع فایل | Read ms | Write ms |
|---|
| a00b | ROWS | 18.40 | 4.10 |
| a00b | LOG | 0.80 | 12.70 |
این آمار نیز تجمعی است. دو Snapshot vfs و اختلاف io_stall و عملیات، Latency بازه حادثه را دقیقتر میکند.
مثال 5: پیدا کردن زنجیره Blocking و Head Blocker
Waitهای LCK و THREADPOOL ممکن است از یک Head Blocker مشترک شروع شوند. گزارش زیر Session منتظر، Blocker، Transaction باز و متن هر دو طرف را نمایش میدهد.
SELECT
r.session_id AS waiting_session_id,
r.blocking_session_id,
r.wait_type,
r.wait_time,
s.open_transaction_count,
LEFT(wt.text, 250) AS waiting_sql,
LEFT(bt.text, 250) AS blocker_sql
FROM sys.dm_exec_requests AS r
JOIN sys.dm_exec_sessions AS s ON s.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS wt
LEFT JOIN sys.dm_exec_requests AS br
ON br.session_id = r.blocking_session_id
OUTER APPLY sys.dm_exec_sql_text(br.sql_handle) AS bt
WHERE r.blocking_session_id <> 0
ORDER BY r.wait_time DESC;
| منتظر | Blocker | Wait | زمان |
|---|
| 67 | 54 | LCK_M_X | 18200 ms |
| 68 | 67 | LCK_M_S | 14600 ms |
Session 54 در نمونه Head Blocker است. پیش از KILL، مالک Transaction، اثر Rollback و علت باز ماندن آن را بررسی کنید.
مثال 6: یافتن Queryهای غالب CPU برای تحلیل Scheduler و Parallelism
Waitهای SOS_SCHEDULER_YIELD، CXPACKET و THREADPOOL بدون دیدن Query و CPU کامل تفسیر نمیشوند. این Query Plan Cache را بر اساس worker time مرتب میکند.
SELECT TOP (15)
qs.execution_count,
qs.total_worker_time / 1000 AS total_cpu_ms,
(qs.total_worker_time / NULLIF(qs.execution_count, 0)) / 1000 AS avg_cpu_ms,
qs.total_elapsed_time / 1000 AS total_elapsed_ms,
qs.total_logical_reads,
LEFT(st.text, 350) AS sql_text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY qs.total_worker_time DESC;
| اجرا | CPU کل | CPU متوسط | Logical Read |
|---|
| 180 | 920000 ms | 5111 ms | 18200000 |
Plan Cache تاریخچه کامل نیست و با Recompile یا Restart تغییر میکند. برای روند پایدار از Query Store یا سامانه مانیتورینگ دارای Retention مناسب استفاده کنید.
معرفی تکتک Wait Typeها
PAGEIOLATCH_SH: انتظار خواندن صفحه داده با لچ اشتراکی
این انتظار زمانی ثبت میشود که یک worker برای خواندن صفحهای از فایل داده به Buffer Pool منتظر تکمیل I/O و گرفتن لچ اشتراکی است. طولانی شدن آن معمولاً به تأخیر خواندن Storage، Physical Read زیاد یا فشار حافظه اشاره میکند. علتهای رایج آن شامل Latency زیاد فایلهای داده، اسکنهای بزرگ ناشی از ایندکس نامناسب، کمبود حافظه و خروج مکرر صفحات از Buffer Pool، همزمانی عملیات تحلیلی سنگین است. اثر محتمل بر سامانه چنین توصیف میشود: افزایش زمان پاسخ کوئریهای خواندنی، کاهش Throughput و انباشته شدن درخواستهای وابسته به صفحههای دیسکی.
نقطه شروع عملی: ابتدا Delta انتظار و Latency هر فایل را در یک بازه پرترافیک اندازه بگیرید؛ سپس Plan و Logical/Physical Read کوئریهای همان بازه را بررسی کنید. هشدار مهم: خرید Storage سریعتر بدون یافتن Query پرخوانش ممکن است فقط علامت را پنهان کند و هزینه را بالا ببرد. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی PAGEIOLATCH_SH در SQL Server را بخوانید.
PAGEIOLATCH_EX: انتظار I/O صفحه داده با لچ انحصاری
این انتظار هنگامی دیده میشود که SQL Server برای بافری در حال I/O به لچ انحصاری نیاز دارد؛ این حالت اغلب در مسیر آمادهسازی صفحه برای تغییر یا عملیات نوشتنی رخ میدهد. زمان زیاد میتواند ترکیبی از Storage کند و الگوی تغییرات سنگین باشد. علتهای رایج آن شامل تأخیر فایل داده در workload نوشتنی، Read-before-write روی صفحههای خارج از حافظه، Checkpoint یا عملیات حجیم همزمان، طراحی ایندکس نامتناسب با مسیر بهروزرسانی است. اثر محتمل بر سامانه چنین توصیف میشود: کند شدن UPDATE و INSERT، طولانی شدن تراکنش و افزایش احتمال زنجیرههای Blocking.
نقطه شروع عملی: فایل و دیتابیس مسئول، صفحه یا Query فعال و نسبت Read/Write آن فایل را همزمان ثبت کنید. هشدار مهم: این انتظار را با PAGELATCH_EX اشتباه نگیرید؛ وجود IO در نام یعنی بافر درگیر درخواست ورودی/خروجی است. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی PAGEIOLATCH_EX در SQL Server را بخوانید.
WRITELOG: انتظار Flush شدن لاگ تراکنش
WRITELOG وقتی رخ میدهد که Session منتظر تکمیل Log Flush روی فایل تراکنش است؛ Commit و Checkpoint از محرکهای رایج آن هستند. Latency فایل لاگ، تعداد زیاد تراکنشهای بسیار کوچک و حجم شدید تولید لاگ سه محور اصلی تحلیلاند. علتهای رایج آن شامل Latency نوشتن فایل Log، Commitهای بسیار ریز و پرتعداد، رشد خودکار مکرر یا اندازه نامناسب Log، فشار همزمان Backup، Replication یا Availability Group است. اثر محتمل بر سامانه چنین توصیف میشود: کند شدن Commit، کاهش نرخ تراکنش و افزایش مدت نگهداری Lockها در سامانههای OLTP.
نقطه شروع عملی: Delta WRITELOG را کنار متوسط write latency فایل Log، نرخ تراکنش و الگوی Batch/Commit اندازهگیری کنید. هشدار مهم: بزرگ کردن فایل Log بهتنهایی Latency دیسک یا طراحی نامناسب تراکنشها را درمان نمیکند. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی WRITELOG در SQL Server را بخوانید.
ASYNC_NETWORK_IO: انتظار مصرف نتیجه توسط Client
این انتظار زمانی شکل میگیرد که SQL Server نتیجه را روی شبکه نوشته اما برنامه Client هنوز داده را با سرعت کافی مصرف یا تأیید نکرده است. علت میتواند پردازش ردیفبهردیف در برنامه، نتیجه بسیار بزرگ، فشار منابع Client یا تأخیر واقعی شبکه باشد. علتهای رایج آن شامل مصرف آهسته Result Set در برنامه، SELECT بدون محدودسازی ستون و ردیف، فیلتر کردن داده در Client به جای Server، CPU، حافظه یا شبکه ضعیف سمت Client است. اثر محتمل بر سامانه چنین توصیف میشود: باز ماندن Request و Transaction، اشغال Connection و حافظه و گاهی طولانیتر شدن Lockها.
نقطه شروع عملی: Session، تعداد ردیف ارسالی، متن Query، مشخصات Client و زمان مصرف Result Set را با هم بررسی کنید. هشدار مهم: نام این انتظار به معنای قطعی بودن مشکل شبکه نیست؛ طراحی برنامه Client در بسیاری از رخدادها عامل اصلی است. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی ASYNC_NETWORK_IO در SQL Server را بخوانید.
CXPACKET: هماهنگی workerهای اجرای موازی
CXPACKET به هماهنگی و تبادل بین workerهای یک Plan موازی مربوط است. بالا بودن آن باید همراه با CXCONSUMER، توزیع کار بین Threadها، Skew، CPU و تنظیمات MAXDOP و Cost Threshold تحلیل شود؛ خود انتظار بهتنهایی اثبات مشکل نیست. علتهای رایج آن شامل Plan موازی با توزیع نامتوازن ردیفها، برآورد Cardinality نادرست، Cost Threshold بسیار پایین، اسکن یا Join سنگین و Parallelism بیش از ظرفیت است. اثر محتمل بر سامانه چنین توصیف میشود: مصرف CPU، افزایش زمان هماهنگی workerها و افت همزمانی در workloadهای پرتراکنش.
نقطه شروع عملی: Plan واقعی، DOP، تعداد ردیف هر شاخه و CXCONSUMER را پیش از تغییر تنظیمات Instance بررسی کنید. هشدار مهم: قرار دادن MAXDOP روی 1 بهصورت سراسری میتواند Queryهای تحلیلی سالم را کند و علت اصلی را پنهان کند. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی CXPACKET در SQL Server را بخوانید.
CXCONSUMER: انتظار سمت مصرفکننده در Plan موازی
CXCONSUMER بخش مصرفکننده تبادل داده در یک Query موازی را نشان میدهد و در بسیاری از workloadها انتظار طبیعی یا کماهمیت است. تحلیل آن زمانی ارزش دارد که با کندی واقعی، CXPACKET، Skew یا مصرف CPU غیرعادی همبستگی داشته باشد. علتهای رایج آن شامل هماهنگی طبیعی Exchange Operator، تفاوت سرعت producer و consumer، Skew در توزیع ردیفها، Plan موازی پرهزینه یا برآورد نادرست است. اثر محتمل بر سامانه چنین توصیف میشود: اغلب کمخطر است، اما در کنار عدم توازن workerها میتواند نشانه اتلاف Parallelism باشد.
نقطه شروع عملی: بهجای رتبه خام انتظار، Query کند و Plan موازی آن را در بازه مسئله پیدا و نسبت CXPACKET را مقایسه کنید. هشدار مهم: حذف یا کاهش اجباری CXCONSUMER بدون نشانه عملکردی، هدف مناسبی برای Tuning نیست. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی CXCONSUMER در SQL Server را بخوانید.
SOS_SCHEDULER_YIELD: واگذاری داوطلبانه Scheduler پس از مصرف CPU
این انتظار زمانی ثبت میشود که worker پس از مصرف Quantum پردازنده، Scheduler را داوطلبانه واگذار میکند و برای ادامه کار دوباره در صف Runnable قرار میگیرد. نرخ بالای آن همراه با Runnable Queue و CPU زیاد معمولاً به Queryهای CPU-bound اشاره دارد. علتهای رایج آن شامل اسکن و Join پرهزینه، محاسبات Scalar یا Sort سنگین، Plan نامناسب و Cardinality غلط، فشار CPU یا Parallelism بیش از ظرفیت است. اثر محتمل بر سامانه چنین توصیف میشود: افزایش Response Time، رشد Runnable Queue و رقابت شدید workerها برای پردازنده.
نقطه شروع عملی: Top Queryها بر اساس worker time، وضعیت Schedulerها و Plan واقعی را در همان بازه بررسی کنید. هشدار مهم: این انتظار معمولاً به معنی مشکل Disk نیست و افزایش CPU بدون اصلاح Query همیشه راهحل پایدار نیست. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی SOS_SCHEDULER_YIELD در SQL Server را بخوانید.
RESOURCE_SEMAPHORE: انتظار دریافت حافظه اجرای Query
RESOURCE_SEMAPHORE زمانی رخ میدهد که Query برای Sort، Hash یا عملیات مشابه Memory Grant درخواست کرده اما حافظه اجرایی کافی در دسترس نیست. برآورد نادرست ردیف، Grant بیشازحد و همزمانی Queryهای تحلیلی از عوامل کلیدیاند. علتهای رایج آن شامل Memory Grant بزرگ ناشی از برآورد غلط، همزمانی زیاد Sort و Hash، فشار حافظه کلی Instance، Plan پارامتری نامناسب یا Parameter Sniffing است. اثر محتمل بر سامانه چنین توصیف میشود: شروع نشدن Queryهای منتظر، تشکیل صف و افت شدید Throughput حتی پیش از مصرف CPU.
نقطه شروع عملی: درخواستهای منتظر و دریافتکننده Grant، اندازه requested/required و Plan شامل Sort یا Hash را بررسی کنید. هشدار مهم: افزایش max server memory بدون توجه به حافظه سیستمعامل و Grantهای اشتباه میتواند فشار کلی را بدتر کند. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی RESOURCE_SEMAPHORE در SQL Server را بخوانید.
LCK_M_S: انتظار دریافت Shared Lock
LCK_M_S یعنی یک Task برای گرفتن Shared Lock و خواندن منبع، پشت Lock ناسازگار دیگری متوقف شده است. معمولاً تراکنش نوشتنی طولانی، ترتیب دسترسی نامناسب یا ایندکس ناکافی دامنه Lock را بزرگ میکند. علتهای رایج آن شامل تراکنش نوشتنی باز و طولانی، اسکن گسترده در مسیر خواندن، Isolation Level و طراحی همزمانی نامناسب، عدم Commit یا Rollback بهموقع در برنامه است. اثر محتمل بر سامانه چنین توصیف میشود: کندی خواندن، تشکیل زنجیره Blocking و مصرف worker و Connection.
نقطه شروع عملی: Head Blocker، متن و Transaction باز آن را پیدا کنید و سپس Plan خواننده و نویسنده را تحلیل کنید. هشدار مهم: استفاده سراسری از NOLOCK میتواند Dirty Read و پاسخ نادرست ایجاد کند و درمان اصولی Blocking نیست. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی LCK_M_S در SQL Server را بخوانید.
LCK_M_X: انتظار دریافت Exclusive Lock
LCK_M_X نشان میدهد یک Task برای تغییر داده به Exclusive Lock نیاز دارد ولی Lock ناسازگار دیگری منبع را نگه داشته است. این انتظار در برخورد نویسنده با خواننده یا نویسنده دیگر و در تراکنشهای طولانی برجسته میشود. علتهای رایج آن شامل چند نویسنده روی ردیف یا صفحه داغ، تراکنش طولانی و Batch بزرگ، نبود ایندکس و قفلگذاری دامنه وسیع، ترتیب متفاوت دسترسی به اشیا است. اثر محتمل بر سامانه چنین توصیف میشود: توقف INSERT/UPDATE/DELETE، افزایش زمان تراکنش و خطر Deadlock یا Timeout برنامه.
نقطه شروع عملی: منبع Lock، Head Blocker، زمان Transaction و ترتیب دسترسی به جدولها را ثبت کنید. هشدار مهم: کشتن Session بدون اصلاح تراکنش یا Query فقط رخداد را موقتاً متوقف میکند و ممکن است Rollback طولانی بسازد. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی LCK_M_X در SQL Server را بخوانید.
LCK_M_U: انتظار دریافت Update Lock
LCK_M_U هنگامی رخ میدهد که SQL Server برای مرحله بررسی پیش از تغییر، Update Lock میخواهد اما منبع با Lock ناسازگار اشغال شده است. این Lock به کاهش برخی Deadlockهای تبدیل Shared به Exclusive کمک میکند، ولی خود میتواند محل رقابت شود. علتهای رایج آن شامل الگوی خواندن سپس بهروزرسانی همزمان، تراکنشهای طولانی روی کلید مشترک، ایندکس نامناسب برای یافتن ردیف هدف، ترتیب دسترسی ناسازگار بین Procedureها است. اثر محتمل بر سامانه چنین توصیف میشود: صف شدن عملیات Update، تبدیل Lock دشوار و افزایش احتمال Deadlock در مسیرهای رقابتی.
نقطه شروع عملی: Session دارنده و منتظر، حالت Lock و Queryهایی را که یک کلید مشترک را تغییر میدهند مقایسه کنید. هشدار مهم: افزودن Hintهایی مانند UPDLOCK بدون طراحی و تست میتواند دامنه و مدت Lock را بیشتر کند. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی LCK_M_U در SQL Server را بخوانید.
THREADPOOL: انتظار دریافت Worker Thread
THREADPOOL زمانی رخ میدهد که Task آماده اجراست اما Worker آزاد در Pool وجود ندارد. Blocking وسیع، Connectionهای فعال بسیار زیاد، Queryهای موازی و تنظیم نامناسب Workerها میتوانند این وضعیت بحرانی را ایجاد کنند. علتهای رایج آن شامل زنجیره Blocking با Sessionهای فراوان، ورود همزمان درخواست بیش از ظرفیت، Parallelism و مصرف چند worker برای هر Query، Threadهای اشغالشده توسط عملیات کند خارجی است. اثر محتمل بر سامانه چنین توصیف میشود: درخواستهای جدید حتی برای تشخیص مشکل هم ممکن است وصل یا اجرا نشوند و کل Instance ظاهراً فریز شود.
نقطه شروع عملی: از Dedicated Admin Connection در رخداد شدید استفاده و Head Blocker، Scheduler و تعداد workerها را فوراً ثبت کنید. هشدار مهم: افزایش max worker threads بدون یافتن Blocking یا فشار ورودی میتواند Context Switching و بیثباتی را بیشتر کند. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی THREADPOOL در SQL Server را بخوانید.
PAGELATCH_UP: رقابت Update Latch روی صفحه حافظه
PAGELATCH_UP انتظار گرفتن Update Latch روی بافری است که درخواست I/O فعال ندارد. این انتظار اغلب در صفحههای تخصیص PFS، GAM و SGAM بهویژه در tempdb یا در صفحههای داغ دیده میشود. علتهای رایج آن شامل رقابت تخصیص در tempdb، تعداد یا اندازه نامتوازن فایلهای tempdb، ایجاد و حذف بسیار زیاد اشیای موقت، صفحه حافظه داغ با تغییرات همزمان است. اثر محتمل بر سامانه چنین توصیف میشود: کندی workloadهای موقت، افت مقیاسپذیری و صف شدن workerها روی یک صفحه داخلی.
نقطه شروع عملی: wait_resource را به فایل و صفحه نگاشت و توزیع فایلهای tempdb و الگوی اشیای موقت را بررسی کنید. هشدار مهم: این انتظار مشکل کندی دیسک نیست؛ افزودن Storage سریعتر بدون رفع Contention حافظه معمولاً مؤثر نیست. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی PAGELATCH_UP در SQL Server را بخوانید.
PAGELATCH_EX: رقابت Exclusive Latch روی صفحه حافظه
PAGELATCH_EX یعنی worker برای Exclusive Latch روی صفحهای در حافظه و بدون I/O منتظر است. Last-page insert در ایندکس ترتیبی، صفحه تخصیص tempdb یا Queue Table کوچک از سناریوهای شناختهشده هستند. علتهای رایج آن شامل درج همزمان روی آخرین صفحه ایندکس، کلید افزایشی و صفحه داغ، رقابت تخصیص tempdb، Queue Table کوچک با تغییرات پرتعداد است. اثر محتمل بر سامانه چنین توصیف میشود: افت مقیاسپذیری INSERT و افزایش زمان پاسخ با زیاد شدن هستهها و Sessionها.
نقطه شروع عملی: wait_resource و index_operational_stats را برای یافتن فایل، صفحه و ایندکس داغ همبسته کنید. هشدار مهم: با PAGEIOLATCH_EX متفاوت است؛ حذف ایندکس یا تغییر کلید بدون اثبات Last-page contention ریسک بالایی دارد. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی PAGELATCH_EX در SQL Server را بخوانید.
IO_COMPLETION: انتظار تکمیل عملیات عمومی I/O
IO_COMPLETION هنگام انتظار برای تکمیل عملیات ورودی/خروجی ثبت میشود و معمولاً نماینده I/O غیرصفحه داده است؛ انتظار تکمیل خواندن صفحه داده بیشتر با PAGEIOLATCH دیده میشود. Backup، File Operation و مسیرهای جانبی میتوانند در تحلیل مطرح باشند. علتهای رایج آن شامل Latency Storage برای عملیات غیرصفحهای، فشار همزمان Backup یا File Growth، صف طولانی I/O در سیستمعامل، اشتراک مسیر ذخیرهسازی با workload دیگر است. اثر محتمل بر سامانه چنین توصیف میشود: کند شدن عملیات نگهداری، Backup/Restore یا مراحل خاص Query و افزایش زمان کلی کار.
نقطه شروع عملی: درخواستهای فعال، pending I/O و Latency تفکیکشده فایلها را در بازه رخداد ثبت کنید. هشدار مهم: جمع کل از زمان Startup مشخص نمیکند کدام فایل یا عملیات اکنون مشکل دارد؛ Delta و همبستگی زمانی لازم است. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی IO_COMPLETION در SQL Server را بخوانید.
OLEDB: انتظار پاسخ OLE DB Provider
OLEDB نشان میدهد SQL Server در فراخوانی Provider خارجی، Linked Server یا مسیر مبتنی بر OLE DB منتظر مانده است. زمان پردازش Remote، انتقال داده، Pushdown نشدن فیلتر و رفتار Provider باید جداگانه سنجیده شوند. علتهای رایج آن شامل Remote Query کند، انتقال حجم زیاد از Linked Server، فیلتر یا Join توزیعشده نامناسب، Provider، شبکه یا منبع خارجی تحت فشار است. اثر محتمل بر سامانه چنین توصیف میشود: طولانی شدن Session محلی، اشغال worker و گسترش Transaction توزیعشده یا Blocking.
نقطه شروع عملی: متن Remote Query، Linked Server هدف، حجم داده و زمان پاسخ همان منبع را مستقل اندازه بگیرید. هشدار مهم: Tuning فقط روی Instance محلی کافی نیست؛ اجرای مستقیم Query روی منبع خارجی ممکن است گلوگاه واقعی را نشان دهد. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی OLEDB در SQL Server را بخوانید.
BACKUPIO: انتظار I/O در مسیر Backup
BACKUPIO به انتظارهای ورودی/خروجی میان workerهای Backup و دستگاه مقصد مربوط است. Throughput فایلهای داده، فشردهسازی، مقصد محلی یا شبکهای، تعداد Stripe و رقابت با workload اصلی در نتیجه اثر دارند. علتهای رایج آن شامل مقصد Backup کند، رقابت خواندن با فایلهای داده، تعداد نامناسب Backup Stripe، CPU فشردهسازی یا شبکه محدود است. اثر محتمل بر سامانه چنین توصیف میشود: طولانی شدن Backup، همپوشانی Jobها و فشار I/O یا CPU بر workload تولیدی.
نقطه شروع عملی: تاریخچه مدت و Throughput Backup را کنار Latency فایلها، مقصد و تنظیمات Compression/Stripe مقایسه کنید. هشدار مهم: افزایش BUFFERCOUNT یا MAXTRANSFERSIZE بدون تست میتواند حافظه مصرفی و فشار مسیر را بالا ببرد. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی BACKUPIO در SQL Server را بخوانید.
HADR_SYNC_COMMIT: انتظار تأیید Commit از Replica همگام
در حالت Synchronous Commit، این انتظار وقتی دیده میشود که Primary پس از Harden کردن Log محلی منتظر تأیید Replica ثانویه است. Latency شبکه، Log Flush در Secondary، فشار CPU و جریان ارسال Log بر مدت آن اثر دارند. علتهای رایج آن شامل Round-trip شبکه بین Replicaها، Latency فایل Log در Secondary، Log send queue یا فشار انتقال، CPU یا worker محدود در Replica ثانویه است. اثر محتمل بر سامانه چنین توصیف میشود: افزایش مستقیم زمان Commit برنامه و کاهش نرخ تراکنش در Primary.
نقطه شروع عملی: زمان Commit را با log_send_queue_size، send_rate، وضعیت Synchronization و Latency Log هر دو Replica همبسته کنید. هشدار مهم: تغییر فوری به Asynchronous Commit هدف RPO را عوض میکند و باید تصمیم معماری و کسبوکاری باشد، نه واکنش عجولانه. برای جزئیات Syntax تشخیصی، ده سناریوی قابل اجرا، خروجی نمونه، FAQ و سؤالات مصاحبه، مقاله تخصصی HADR_SYNC_COMMIT در SQL Server را بخوانید.
خطاهای رایج در پروژههای Performance
نخستین خطا، انتخاب درمان از روی نام Wait است. PAGEIOLATCH همیشه خرید Disk، CXPACKET همیشه MAXDOP یک، ASYNC_NETWORK_IO همیشه تعویض شبکه و LCK همیشه NOLOCK نیست. هر یک چند علت دارد و درمان عمومی میتواند هزینه، خطای داده یا Regression بسازد.
دومین خطا، نبود Baseline است. بدون بار مرجع نمیدانیم عدد جدید واقعاً بدتر شده یا فقط تعداد کاربران افزایش یافته است. Baseline باید الگوی ساعت، روز هفته، Jobهای دورهای، Release برنامه و تغییر حجم داده را نگه دارد و معیارها را نرمال کند.
سومین خطا، تمرکز بر متوسط است. میانگین میتواند چند Timeout شدید را پنهان کند. p95 و p99، تعداد Request متاثر، طول صف و مدت Incident دید کاملتری میدهند. Wait Delta باید به Endpoint، Report یا Job کسبوکاری متصل شود.
چهارمین خطا، اعلام موفقیت با پایین آمدن یک Wait است. منابع محدودند و Bottleneck ممکن است جابهجا شود. پس از اصلاح، CPU، I/O، Memory Grant، Blocking، نرخ خطا و صحت خروجی را دوباره کنترل کنید و نتیجه را با workload همسطح بسنجید.
بهترین روشهای مانیتورینگ بلندمدت
- Snapshot زماندار Waitها را بدون پاک کردن تاریخچه جمعآوری کنید.
- sqlserver_start_time را نگه دارید تا Restart و Reset از Regression جدا شود.
- Delta منفی یا Reset را در Pipeline مانیتورینگ تشخیص دهید.
- Waitها را بر ثانیه، تراکنش و Request نرمال کنید.
- Query Store یا تاریخچه Plan را برای اتصال Wait به تغییر Plan نگه دارید.
- شاخصهای سیستمعامل و Storage را با Clock همگام در همان Dashboard ثبت کنید.
- برای Alert از Baseline پویا و چند شرط همزمان استفاده کنید.
- Runbook هر Wait را با مالک، Query تشخیصی، سطح دسترسی و Rollback مستند کنید.
سؤالات متداول
سؤال 1: Wait Type در SQL Server چیست؟
Wait Type نام منبع یا مرحلهای است که Task برای ادامه اجرا منتظر آن میماند؛ مانند I/O، Lock، CPU، حافظه، Worker یا هماهنگی موازی. انتظار طبیعی است و تحلیل روی الگو، Delta و اثر SLA تمرکز میکند.
سؤال 2: تفاوت Resource Wait و Signal Wait چیست؟
Resource Wait تا آماده شدن منبع ادامه دارد؛ Signal Wait پس از آماده شدن Task تا دریافت CPU است. wait_time_ms شامل signal_wait_time_ms است، بنابراین تفکیک آن برای تشخیص فشار CPU اهمیت دارد.
سؤال 3: آیا میتوان Wait Stats را در Production پاک کرد؟
دستور پاکسازی وجود دارد، اما تاریخچه مشترک Instance را حذف میکند. روش کمریسکتر ذخیره Snapshot و محاسبه Delta است؛ پاکسازی فقط در آزمایش کنترلشده و پس از ثبت Baseline انجام شود.
سؤال 4: کدام Wait Type همیشه بحرانی است؟
هیچ نامی بدون زمینه همیشه بحرانی نیست. حتی THREADPOOL که نشانه شدیدی است باید با Request، Worker و Blocking تأیید شود؛ اولویت از نرخ، مدت، تعداد کاربر متاثر و SLA میآید.
سؤال 5: برای خرید Storage چگونه از Wait Stats استفاده کنیم؟
PAGEIOLATCH یا WRITELOG فقط فرضیه میسازند. برای تصمیم تجاری باید Delta، Latency فایل، IOPS، Throughput، صف سیستمعامل و امکان اصلاح Query اندازهگیری و هزینه گزینهها مقایسه شود.
سؤال 6: یک پروژه Performance Tuning حرفهای چه تحویلی باید داشته باشد؟
Baseline، Timeline رخداد، Query و Plan مسئول، فرضیههای آزمودهشده، تغییرات نسخهپذیر، نتیجه قبل و بعد و برنامه Rollback باید تحویل شود. صرف ارائه فهرست Waitها یا تغییر تنظیمات، خروجی کامل مشاوره نیست.
سؤال 7: رایجترین اشتباه در خواندن sys.dm_os_wait_stats چیست؟
برداشت علت از مقدار تجمعی بدون دانستن زمان Startup و workload رایجترین اشتباه است. حذف کورکورانه Waitهای پسزمینه یا تمرکز بر درصد بدون نرخ و SLA نیز نتیجه را منحرف میکند.
سؤال 8: بهترین فاصله نمونهبرداری Wait Stats چقدر است؟
عدد عمومی وجود ندارد. رخداد چندثانیهای به Capture کوتاه نیاز دارد، اما روند ظرفیت با بازه یک تا پنج دقیقه و Retention بلندمدت بهتر دیده میشود؛ هزینه مانیتورینگ نیز باید کنترل شود.
سؤال 9: Wait Stats چگونه به Query مشخص متصل میشود؟
آمار تجمعی با دو Snapshot محدود میشود؛ سپس sys.dm_exec_requests و sys.dm_os_waiting_tasks، متن SQL، Plan و شناسه Session در همان Timeline ثبت میشوند. Query Store برای تاریخچه Plan و Runtime مفید است.
سؤال 10: این Queryها با کدام نسخه SQL Server سازگارند؟
هسته DMVها در نسخههای رایج SQL Server موجود است، اما ستون، Permission و رفتار Azure میتواند متفاوت باشد. Query باید با مستندات نسخه مقصد و حساب Read-only دارای حداقل دسترسی آزموده شود.
سؤالات مصاحبه
پرسش مصاحبه 1: چرا Wait رتبه اول الزاماً Root Cause نیست؟
پاسخ پیشنهادی: زیرا آمار تجمعی، نسبی و حاصل چند workload است. باید Delta بازه حادثه، Session، Query، Plan و شاخص زیرسیستم علت را تأیید کنند.
پرسش مصاحبه 2: wait_time_ms و signal_wait_time_ms چه رابطهای دارند؟
پاسخ پیشنهادی: wait_time_ms کل زمان و شامل signal است؛ اختلاف آنها تقریب Resource Wait را میدهد. Signal بالا میتواند رقابت CPU را مطرح کند.
پرسش مصاحبه 3: تفاوت PAGEIOLATCH و PAGELATCH چیست؟
پاسخ پیشنهادی: اولی بافر درگیر درخواست I/O و دومی لچ صفحه حافظه بدون I/O فعال است؛ مسیر تشخیص Storage در برابر Hot Page یا تخصیص متفاوت میشود.
پرسش مصاحبه 4: CXCONSUMER را چگونه تفسیر میکنید؟
پاسخ پیشنهادی: اغلب بخش طبیعی سمت مصرفکننده Parallel Exchange است. فقط همراه کندی واقعی، CXPACKET، Skew و CPU غیرعادی اولویت میگیرد.
پرسش مصاحبه 5: روش کمریسک محاسبه Wait Delta چیست؟
پاسخ پیشنهادی: دو Snapshot با Timestamp میگیرم، اختلاف را محاسبه، Restart را تشخیص و نتیجه را بر مدت و workload نرمال میکنم؛ لازم نیست Wait Stats پاک شود.
جمعبندی و مسیر مطالعه
Wait Stats نقشه توقفهای موتور SQL Server است، نه فهرست خطاها. تحلیل معتبر از تعریف Incident آغاز میشود، آمار تجمعی را به Delta تبدیل میکند، Session و Plan را پیدا میکند و شاخص زیرسیستم را برای تأیید میآورد. سپس یک تغییر محدود با معیار موفقیت و Rollback آزموده میشود.
برای ادامه، مقاله مرتبط با Wait غالب سامانه را انتخاب کنید. همه مقالهها شامل Queryهای Read-only، خروجی نمونه، دامهای تشخیصی و روش اندازهگیری قبل و بعد هستند:
اگر چند Wait همزمان بالا هستند، ابتدا Timeline را بسازید و اولین رخداد زنجیره را پیدا کنید. اصلاح Root Cause میتواند چند علامت پاییندستی را همزمان کاهش دهد؛ در مقابل، درمان علامت ممکن است Bottleneck را فقط به جای دیگری منتقل کند.