آموزش sys.dm_exec_query_parallel_workers؛ تحلیل ظرفیت Workerهای موازی در SQL Server
مقدمه
اجرای موازی فقط به CPU نیاز ندارد؛ هر Branch موازی با Task و Worker اجرا میشود. هنگامی که تعداد زیادی Query با DOP بالا همزمان وارد سیستم میشوند، ظرفیت Worker ممکن است در یک یا چند NUMA Node کاهش یابد. نتیجه میتواند کاهش DOP مؤثر، انتظار برای Worker، افت Throughput و حتی Thread Pool Pressure باشد. sys.dm_exec_query_parallel_workers نمایی فشرده از ظرفیت Worker مخصوص Queryهای موازی در سطح Node ارائه میکند.
این DMV تعداد Scheduler، سقف Worker موازی، Worker رزروشده، آزاد و مصرفشده را برای هر Node برمیگرداند. تحلیل در سطح Node اهمیت دارد، زیرا مجموع مناسب کل سرور ممکن است عدم تعادل موضعی را پنهان کند. طبق تعریف، هر Request ورودی دستکم یک Worker مصرف میکند که از free_worker_count کم میشود و در بار بسیار سنگین این ستون حتی میتواند مقدار منفی داشته باشد.
Worker Pressure را نباید با CPU Utilization یکی دانست. ممکن است CPU در لحظه متوسط باشد اما Workerها به دلیل Requestهای Blocked یا Parallel فراوان رزرو شده باشند. از سوی دیگر مقدار آزاد کم و کوتاهمدت الزاماً بحران نیست. برای تصمیم درست، چند Snapshot، Waitهای THREADPOOL و CXPACKET یا CXCONSUMER، DOP Queryهای فعال، Memory Grants و توزیع NUMA را کنار هم قرار دهید.
این مطلب بخشی از راهنمای جامع DMVهای حافظه Query در SQL Server است. برای دیدن ارتباط این نما با Semaphoreهای اجرا، Gateهای Compile و Workerهای Parallel میتوانید ابتدا یا پس از مطالعه این مقاله به راهنمای مادر بازگردید.
تعریف sys.dm_exec_query_parallel_workers
sys.dm_exec_query_parallel_workers از SQL Server 2016 به بعد برای هر Node یک ردیف Worker Availability بازمیگرداند. node_id شناسه NUMA Node و scheduler_count تعداد Schedulerهای آن Node است. max_worker_count سقف Workerهایی است که برای Queryهای موازی در نظر گرفته شده و free_worker_count ظرفیت باقیمانده برای Taskها را نشان میدهد.
reserved_worker_count شامل Workerهای رزروشده توسط Queryهای موازی بهعلاوه Worker اصلی مورد استفاده تمام Requestهاست. used_worker_count تعداد Workerهایی را گزارش میکند که Queryهای موازی اکنون مصرف میکنند. به دلیل تفاوت تعریف، جمع و تفریق ساده همه ستونها لزوماً معادله حسابداری کاملی نمیسازد؛ از آنها به عنوان شاخص ظرفیت و روند استفاده کنید.
برای ارتباط با Memory Grant، ستونهای reserved_worker_count و used_worker_count در sys.dm_exec_query_memory_grants را نیز میتوان جمعبندی کرد. این دو نما Scope متفاوت دارند: Parallel Workers در سطح Node ظرفیت را نشان میدهد و Memory Grants در سطح Request مصرف و رزرو Queryهای دارای Grant را گزارش میکند. مقایسه همزمان سرنخ مفید است، ولی Join مستقیم ساده بر اساس Node همیشه ممکن نیست، زیرا reserved_node_bitmap یک Bitmap است.
Syntax پایه
SELECT
node_id,
scheduler_count,
max_worker_count,
reserved_worker_count,
free_worker_count,
used_worker_count
FROM sys.dm_exec_query_parallel_workers;
مجوزها و سازگاری نسخه
این DMV از SQL Server 2016 و نسخههای بعدی، Azure SQL Database، Azure SQL Managed Instance و SQL Database در Fabric پشتیبانی میشود. SQL Server 2022 و بعد VIEW SERVER PERFORMANCE STATE و نسخههای قدیمیتر VIEW SERVER STATE میخواهند. در Azure SQL Database مجوز بسته به سطح سرویس VIEW DATABASE STATE یا نقش مدیریتی متناظر است.
ستونهای مهم و نحوه تفسیر
همه ستونها عددی و در سطح Node هستند. free_worker_count میتواند در فشار شدید منفی شود و reserved_worker_count دامنهای گستردهتر از used_worker_count دارد؛ بنابراین نسبتها باید به عنوان شاخص عملیاتی تفسیر شوند، نه برابری حسابداری دقیق.
| ستون | نوع داده | تفسیر و کاربرد |
|---|
node_id | int | شناسه NUMA Node که ظرفیت Worker برای آن گزارش شده است. |
scheduler_count | int | تعداد Schedulerهای موجود روی Node. |
max_worker_count | int | حداکثر Worker قابل استفاده برای Queryهای موازی روی Node. |
reserved_worker_count | int | Worker رزروشده Parallel بهعلاوه Worker اصلی همه Requestها. |
free_worker_count | int | Workerهای در دسترس برای Taskها؛ در بار بسیار سنگین ممکن است منفی شود. |
used_worker_count | int | Workerهایی که اکنون توسط Queryهای موازی استفاده میشوند. |
Worker، Task، DOP و NUMA
یک Request موازی به چند Task تقسیم میشود و Taskها روی Schedulerها Worker میگیرند. DOP تعداد مسیرهای موازی Plan را محدود میکند، اما تعداد Worker رزروشده میتواند با شکل Plan و تعداد Branchها بیشتر از تصور ساده DOP باشد. چند Query موازی همزمان به سرعت ظرفیت Node را مصرف میکنند، بهویژه اگر Requestها Blocked بمانند و Worker خود را نگه دارند.
max_worker_count این DMV ظرفیت Worker برای Parallel Query را در Node نشان میدهد. free_worker_count پس از در نظر گرفتن مصرف Requestها محاسبه میشود و طبق مستندات میتواند منفی شود. مقدار منفی نشانه بار شدید است، اما باید مدت آن و Waitهای Thread Pool بررسی شود. یک Spike بسیار کوتاه با فشار پایدار چند دقیقهای اثر یکسانی ندارد.
عدم تعادل NUMA زمانی دیده میشود که درصد Worker آزاد Nodeها اختلاف زیادی داشته باشد. مجموع کل سرور ممکن است مثلاً سی درصد ظرفیت آزاد نشان دهد، اما یک Node نزدیک صفر و Node دیگر آزاد باشد. Queryها، Connectionها، Affinity و تخصیص Scheduler باید در سطح Node تحلیل شوند. تغییر Affinity یا تنظیمات NUMA اقدام سادهای نیست و بدون تست تخصصی توصیه نمیشود.
MAXDOP و Cost Threshold for Parallelism روی تعداد Queryهای موازی و Worker مصرفی اثر دارند، اما تغییر سراسری آنها درمان خودکار نیست. MAXDOP پایینتر میتواند Worker هر Query را کم کند و در عوض مدت اجرای آن را بالا ببرد. هدف یافتن تعادل Throughput و Latency با Workload واقعی است؛ Queryهای بد، Blocking و Grantهای بزرگ نیز باید اصلاح شوند.
قاعده کلیدی: ظرفیت را در سطح هر Node و در چند Snapshot بسنجید. free_worker_count پایین یا منفی را با THREADPOOL، DOP Queryهای فعال، Blocking و Memory Grants تطبیق دهید؛ مجموع کل سرور بهتنهایی کافی نیست.
ده مثال عملی و قابل اجرا
مثال ۱: نمایش ظرفیت Worker هر Node
این Snapshot پایه همه ستونها را صریح انتخاب و بر node_id مرتب میکند. خروجی برای شناخت تعداد Nodeها و ظرفیت توزیعشده نقطه شروع است.
SELECT
node_id,
scheduler_count,
max_worker_count,
reserved_worker_count,
free_worker_count,
used_worker_count
FROM sys.dm_exec_query_parallel_workers
ORDER BY node_id;
| node_id | scheduler_count | max_worker_count | reserved_worker_count | free_worker_count | used_worker_count |
|---|
| 0 | 8 | 256 | 238 | 18 | 196 |
| 1 | 8 | 256 | 92 | 164 | 71 |
نکتهٔ کاربردی: اختلاف Node صفر و یک مهمتر از میانگین کل است. Snapshot را در زمان عادی نیز ذخیره کنید تا عدم تعادل Incident با Baseline مقایسه شود.
مثال ۲: محاسبه درصد Worker آزاد
free_worker_count نسبت به max_worker_count به درصد تبدیل میشود. NULLIF تقسیم بر صفر را ایمن میکند و Nodeهای کمظرفیت در ابتدای خروجی قرار میگیرند.
SELECT
node_id,
max_worker_count,
free_worker_count,
FreeWorkerPercent = CAST(100.0 * free_worker_count /
NULLIF(max_worker_count, 0) AS decimal(7, 2))
FROM sys.dm_exec_query_parallel_workers
ORDER BY FreeWorkerPercent, node_id;
| node_id | max_worker_count | free_worker_count | FreeWorkerPercent |
|---|
| 0 | 256 | 18 | 7.03 |
| 1 | 256 | 164 | 64.06 |
نکتهٔ کاربردی: درصد منفی ممکن است رخ دهد و با decimal نمایش داده میشود. آستانه هشدار را از Baseline و تداوم فشار استخراج کنید.
مثال ۳: شناسایی Node با free_worker_count منفی
این Query حالت مرزی مستندشده را فیلتر میکند. مقدار منفی در بار بسیار سنگین ممکن است دیده شود و باید فوراً با Waitهای THREADPOOL و تعداد Requestهای همزمان تطبیق داده شود.
SELECT
node_id,
scheduler_count,
max_worker_count,
reserved_worker_count,
free_worker_count,
used_worker_count
FROM sys.dm_exec_query_parallel_workers
WHERE free_worker_count < 0
ORDER BY free_worker_count;
| node_id | max_worker_count | reserved_worker_count | free_worker_count | used_worker_count |
|---|
| 0 | 256 | 271 | -15 | 224 |
نکتهٔ کاربردی: خروجی بدون ردیف طبیعی است. اگر مقدار منفی پایدار است، Blocking، Queryهای موازی و تنظیمات Worker را بررسی و شواهد زماندار ثبت کنید.
مثال ۴: محاسبه درصد Worker موازی مصرفشده
used_worker_count نسبت به سقف Worker موازی سنجیده میشود. این نسبت مصرف جاری Parallel را نشان میدهد و با نسبت Free متفاوت است، زیرا تعریف reserved و مصرف Worker اصلی گستردهتر است.
SELECT
node_id,
used_worker_count,
max_worker_count,
ParallelWorkerUsedPercent = CAST(100.0 * used_worker_count /
NULLIF(max_worker_count, 0) AS decimal(6, 2)),
reserved_worker_count
FROM sys.dm_exec_query_parallel_workers
ORDER BY ParallelWorkerUsedPercent DESC;
| node_id | used_worker_count | max_worker_count | ParallelWorkerUsedPercent | reserved_worker_count |
|---|
| 0 | 196 | 256 | 76.56 | 238 |
| 1 | 71 | 256 | 27.73 | 92 |
نکتهٔ کاربردی: used فقط Worker موازی را گزارش میکند، درحالیکه reserved شامل Worker اصلی Requestها نیز هست. معادله ساده used + free = max را فرض نکنید.
مثال ۵: ساخت خلاصه کل سرور
مجموع Scheduler، ظرفیت، رزرو، Worker آزاد و مصرف موازی برای داشبورد سطح Instance محاسبه میشود. درصد آزاد کل دید سریع میدهد، اما Drill-down Node برای کشف عدم تعادل همچنان ضروری است.
SELECT
NodeCount = COUNT_BIG(*),
TotalSchedulers = SUM(scheduler_count),
TotalMaxWorkers = SUM(max_worker_count),
TotalReservedWorkers = SUM(reserved_worker_count),
TotalFreeWorkers = SUM(free_worker_count),
TotalUsedParallelWorkers = SUM(used_worker_count),
TotalFreePercent = CAST(100.0 * SUM(free_worker_count) /
NULLIF(SUM(max_worker_count), 0) AS decimal(7, 2))
FROM sys.dm_exec_query_parallel_workers;
| NodeCount | TotalSchedulers | TotalMaxWorkers | TotalFreeWorkers | TotalUsedParallelWorkers | TotalFreePercent |
|---|
| 2 | 16 | 512 | 182 | 267 | 35.55 |
نکتهٔ کاربردی: ۳۵ درصد آزاد کل میتواند فشار Node صفر با ۷ درصد ظرفیت را پنهان کند. Aggregate برای Overview است و جای گزارش Node را نمیگیرد.
مثال ۶: فیلتر Nodeهای زیر آستانه ده درصد
برای Alert نمونه، Nodeهایی انتخاب میشوند که ظرفیت آزادشان کمتر از ده درصد سقف است. شرط با ضرب عددی نوشته شده تا نیاز به Alias یا تکرار تقسیم اعشاری کمتر شود.
SELECT
node_id,
max_worker_count,
free_worker_count,
reserved_worker_count,
used_worker_count
FROM sys.dm_exec_query_parallel_workers
WHERE free_worker_count * 10 < max_worker_count
ORDER BY free_worker_count;
| node_id | max_worker_count | free_worker_count | reserved_worker_count | used_worker_count |
|---|
| 0 | 256 | 18 | 238 | 196 |
نکتهٔ کاربردی: این شرط مقادیر منفی را نیز شامل میشود. آستانه ده درصد نمونه آموزشی است و باید با مدت فشار، SLA و Baseline سرور تنظیم شود.
مثال ۷: اندازهگیری عدم تعادل میان NUMA Nodeها
حداقل و حداکثر درصد Worker آزاد محاسبه و فاصله آنها به عنوان Imbalance نمایش داده میشود. این شاخص ساده مشخص میکند آیا مجموع کل سرور توزیع نامتوازن را پنهان کرده است.
WITH NodeCapacity AS
(
SELECT
node_id,
FreePercent = 100.0 * free_worker_count /
NULLIF(max_worker_count, 0)
FROM sys.dm_exec_query_parallel_workers
)
SELECT
MinimumFreePercent = CAST(MIN(FreePercent) AS decimal(7, 2)),
MaximumFreePercent = CAST(MAX(FreePercent) AS decimal(7, 2)),
ImbalancePercent = CAST(MAX(FreePercent) - MIN(FreePercent) AS decimal(7, 2))
FROM NodeCapacity;
| MinimumFreePercent | MaximumFreePercent | ImbalancePercent |
|---|
| 7.03 | 64.06 | 57.03 |
نکتهٔ کاربردی: فاصله بزرگ سرنخ است، نه تشخیص نهایی. Affinity، محل Connectionها، Queryهای فعال و وضعیت Schedulerهای هر Node را بررسی کنید.
مثال ۸: مقایسه ظرفیت Worker با Queryهای دارای Memory Grant
دو Aggregate مستقل ساخته و در یک ردیف کنار هم قرار میگیرند. هدف مشاهده همزمان ظرفیت کلی Parallel Worker و Workerهای رزروشده یا مصرفشده توسط Requestهای دارای Memory Grant است.
WITH WorkerCapacity AS
(
SELECT
TotalFreeWorkers = SUM(free_worker_count),
TotalUsedParallelWorkers = SUM(used_worker_count)
FROM sys.dm_exec_query_parallel_workers
), GrantWorkers AS
(
SELECT
GrantReservedWorkers = SUM(COALESCE(reserved_worker_count, 0)),
GrantUsedWorkers = SUM(COALESCE(used_worker_count, 0)),
ActiveGrantCount = COUNT_BIG(*)
FROM sys.dm_exec_query_memory_grants
)
SELECT *
FROM WorkerCapacity
CROSS JOIN GrantWorkers;
| TotalFreeWorkers | TotalUsedParallelWorkers | GrantReservedWorkers | GrantUsedWorkers | ActiveGrantCount |
|---|
| 182 | 267 | 241 | 203 | 21 |
نکتهٔ کاربردی: Scope دو DMV متفاوت است و اعداد الزاماً برابر نیستند. این مقایسه همبستگی Incident را نشان میدهد؛ برای Node دقیق، reserved_node_bitmap نیازمند Decode جداگانه است.
مثال ۹: ذخیره Snapshot Worker در Temp Table
برای تحلیل ثابت، Snapshot در Temp Table ذخیره و روی درصد فشار تقریبی ایندکس میشود. ستون CaptureTime برای مستندسازی لحظه داده ضروری است.
DROP TABLE IF EXISTS #ParallelWorkerSnapshot;
SELECT
CaptureTime = SYSDATETIME(),
node_id,
scheduler_count,
max_worker_count,
reserved_worker_count,
free_worker_count,
used_worker_count
INTO #ParallelWorkerSnapshot
FROM sys.dm_exec_query_parallel_workers;
CREATE UNIQUE CLUSTERED INDEX CX_ParallelWorkerSnapshot_Node
ON #ParallelWorkerSnapshot(node_id);
SELECT *
FROM #ParallelWorkerSnapshot
ORDER BY free_worker_count, node_id;
| CaptureTime | node_id | max_worker_count | free_worker_count | used_worker_count |
|---|
| 2026-07-22 04:40:00.100 | 0 | 256 | 18 | 196 |
| 2026-07-22 04:40:00.100 | 1 | 256 | 164 | 71 |
نکتهٔ کاربردی: Temp Table برای چند Query تحلیلی در یک Session مناسب است. Trend دائمی به جدول تاریخچه، Retention و ایندکس بر CaptureTime و node_id نیاز دارد.
مثال ۱۰: طبقهبندی وضعیت Worker هر Node
CASE سه سطح سلامت میسازد: مقدار منفی یا کمتر از پنج درصد بحرانی، کمتر از پانزده درصد هشدار و بقیه عادی. تقسیم با NULLIF ایمن شده و ترتیب خروجی Nodeهای پرخطر را جلو میآورد.
SELECT
node_id,
max_worker_count,
free_worker_count,
HealthState = CASE
WHEN free_worker_count < 0 THEN N'Critical'
WHEN 100.0 * free_worker_count /
NULLIF(max_worker_count, 0) < 5 THEN N'Critical'
WHEN 100.0 * free_worker_count /
NULLIF(max_worker_count, 0) < 15 THEN N'Warning'
ELSE N'Healthy'
END
FROM sys.dm_exec_query_parallel_workers
ORDER BY CASE
WHEN free_worker_count < 0 THEN 0
WHEN 100.0 * free_worker_count / NULLIF(max_worker_count, 0) < 5 THEN 0
WHEN 100.0 * free_worker_count / NULLIF(max_worker_count, 0) < 15 THEN 1
ELSE 2 END,
node_id;
| node_id | max_worker_count | free_worker_count | HealthState |
|---|
| 0 | 256 | 18 | Warning |
| 1 | 256 | 164 | Healthy |
نکتهٔ کاربردی: در Production شرط تداوم، THREADPOOL و Blocking را اضافه کنید. Threshold درصدی باید با Baseline سختافزار و Workload تنظیم شود.
خطاهای رایج
Worker یک منبع اجرایی است و برداشت نادرست از Scope ستونها میتواند به تغییر بیاثر MAXDOP یا تنظیمات سطح سرور منجر شود. موارد زیر را در تحلیل کنترل کنید.
- یکسان دانستن Worker Pressure با CPU صددرصد؛ Worker میتواند در Blocking نگه داشته شود.
- اتکا به مجموع کل سرور و نادیده گرفتن فشار یک NUMA Node.
- فرض برابری ساده max، free، used و reserved با وجود تفاوت تعریف ستونها.
- نادیده گرفتن امکان مقدار منفی free_worker_count در بار بسیار سنگین.
- کاهش فوری MAXDOP بدون بررسی مدت Query، Throughput و Plan.
- تمرکز فقط بر Parallel Query و نادیده گرفتن Blocking و Requestهای سریال دارای Worker اصلی.
- Join مستقیم reserved_node_bitmap به node_id بدون Decode صحیح Bitmap.
- تنظیم Threshold ثابت بدون Baseline هر Node و دوره بار.
ملاحظات Performance
این DMV تعداد ردیف اندکی دارد و Snapshot عددی آن سبک است. بااینحال اتصال مداوم به Session، Request، Plan و Waitهای متعدد میتواند Collector را پرهزینه کند. روش مناسب ثبت ظرفیت Node در فاصله معقول و Drill-down هنگام آستانه یا THREADPOOL است.
Sampling باید Spikeهای کوتاه را از فشار پایدار جدا کند. برای Incident فعال میتوان نرخ را موقتاً افزایش داد، اما تاریخچه دائمی با Granularity مناسب و Rollup نگهداری شود. CaptureTime، node_id و زمان Startup برای مقایسه معتبر لازماند.
تغییر MAXDOP، Cost Threshold for Parallelism یا Max Worker Threads اثر گسترده دارد. مقدار Max Worker Threads معمولاً بهتر است روی تنظیم پیشفرض خودکار بماند مگر تحلیل عمیق خلاف آن را ثابت کند. هر تغییر باید با Workload نماینده، Throughput، Latency، Wait و ظرفیت Worker قبل و بعد آزمایش شود.
- Snapshot سطح Node بدون Join سنگین ثبت میشود.
- مجموع Instance فقط برای Overview و Node برای Alert استفاده میشود.
- THREADPOOL و Waitهای Parallel در همان بازه ثبت میشوند.
- Blocking و Sessionهای نگهدارنده Worker بررسی میشوند.
- نرخ نمونهبرداری در حالت عادی و Incident جداست.
- تغییر تنظیمات با تست بار و برنامه بازگشت انجام میشود.
بهترین روشها و کاربرد سازمانی
Baseline هر Node را در ساعت عادی، اوج ترافیک و Jobهای Batch بسازید. درصد آزاد، Worker مصرفی موازی و Imbalance را ثبت کنید. وقتی Alert فعال شد، Queryهای با DOP بالا، Blocking Chain، Memory Grant و Waitهای Thread Pool را در همان Timestamp جمعآوری نمایید.
اصلاح را از Query و Workload آغاز کنید. Index مناسب، کاهش Scan و Sort، رفع Cardinality Estimate نادرست و کوتاه کردن Transaction میتواند مدت نگه داشتن Worker را کم کند. تنظیم MAXDOP باید در سطح مناسب Server، Database، Resource Governor یا Query و با توجه به نسخه انتخاب شود.
در پروژههای حساس، Capacity Planning را با تست Concurrency انجام دهید. اجرای یک Query سریع در تنهایی ثابت نمیکند صد نمونه همزمان آن پایدار است. بازپخش Workload و اندازهگیری Throughput، P95 Latency، Worker Free، CPU و Memory Grant به انتخاب تنظیمات متعادل کمک میکند.
- Worker آزاد و مصرفی را برای هر Node Baseline کنید.
- Alert را بر تداوم فشار و Imbalance بنا کنید.
- هنگام رخداد THREADPOOL، Blocking و DOP Queryها را ثبت کنید.
- Queryهای طولانی و موازی غالب را بهینه کنید.
- MAXDOP و Cost Threshold را فقط با تست Workload تغییر دهید.
- نتیجه را با Throughput، Latency و Worker هر Node مقایسه کنید.
سؤالات متداول
پرسش ۱: sys.dm_exec_query_parallel_workers چه چیزی نشان میدهد؟
ظرفیت Workerهای مرتبط با Queryهای موازی را برای هر Node نمایش میدهد. تعداد Scheduler، سقف Worker، رزرو، ظرفیت آزاد و مصرف موازی قابل مشاهده است. این نما برای تشخیص فشار موضعی NUMA و ارتباط آن با Parallelism کاربرد دارد.
پرسش ۲: چرا free_worker_count میتواند منفی شود؟
هر Request دستکم یک Worker مصرف میکند و این مصرف از Free کم میشود. در سرور بسیار شلوغ، محاسبه میتواند عدد منفی گزارش کند. مقدار منفی باید با تداوم زمانی، THREADPOOL، Blocking و Queryهای موازی همزمان تحلیل شود؛ یک Snapshot گذرا به تنهایی کافی نیست.
پرسش ۳: Worker Pressure چه اثری بر سامانه تجاری دارد؟
درخواستها ممکن است برای Worker منتظر بمانند و Latency افزایش یابد، حتی اگر Storage مشکل نداشته باشد. فشار روی یک Node میتواند سرویسهای خاص را نامتوازن آسیب بزند. مانیتورینگ Node و SLA به تیم عملیات اجازه میدهد پیش از گسترش صف، Query یا Workload غالب را شناسایی کند.
پرسش ۴: آیا کاهش MAXDOP همیشه مشکل Worker را حل میکند؟
خیر. Worker هر Query ممکن است کمتر شود، اما مدت اجرا و تعداد Queryهای همزمان افزایش یابد. Blocking یا Query بد نیز با MAXDOP درمان نمیشود. برای تغییر Production، تحلیل تخصصی Plan و تست Concurrency لازم است تا Throughput و Latency هر دو سنجیده شوند.
پرسش ۵: تفاوت reserved_worker_count و used_worker_count چیست؟
reserved شامل Workerهای رزروشده Parallel بهعلاوه Worker اصلی همه Requestهاست، درحالیکه used تعداد Workerهای واقعاً مورد استفاده Queryهای موازی را نشان میدهد. Scope متفاوت است و نباید انتظار داشت جمع used و free همیشه دقیقاً برابر max باشد.
پرسش ۶: چگونه داشبورد Parallel Worker بسازیم؟
CaptureTime و شش ستون DMV را در سطح node_id ذخیره کنید و درصد Free و Imbalance را محاسبه نمایید. Alert را با تداوم فشار و THREADPOOL ترکیب و Drill-down به Queryهای DOP بالا فراهم کنید. Retention و نرخ Sampling باید با بار Production آزمایش شود.
پرسش ۷: چرا مجموع کل سالم است اما یک Node مشکل دارد؟
Workerها در سطح Node و Scheduler توزیع شدهاند. یک Node میتواند نزدیک اشباع و Node دیگر آزاد باشد؛ Aggregate کل این اختلاف را میانگین میکند. گزارش باید Minimum Free Percent و اختلاف Nodeها را نشان دهد و سپس Affinity و Workload همان Node بررسی شود.
پرسش ۸: خواندن این DMV چه سرباری دارد؟
خود DMV کوچک و معمولاً سبک است. سربار از Joinهای مکرر به Plan XML، Requestها و Polling سریع ایجاد میشود. Snapshot عددی را ذخیره و جزئیات را فقط هنگام آستانه یا Incident واکشی کنید. زمان اجرای Collector نیز بخشی از مانیتورینگ باشد.
پرسش ۹: بهترین روش رفع کمبود Worker چیست؟
ابتدا Blocking، Queryهای طولانی، Parallelism افراطی و Concurrency را پیدا کنید. Query و Index را اصلاح و سپس MAXDOP یا Cost Threshold را با تست بار بسنجید. تغییر Max Worker Threads معمولاً گزینه اول نیست و بدون دلیل قوی میتواند پایداری را بدتر کند.
پرسش ۱۰: این DMV در چه نسخههایی و با چه مجوزی موجود است؟
از SQL Server 2016 به بعد در دسترس است. SQL Server 2022 و بعد VIEW SERVER PERFORMANCE STATE و نسخههای قدیمیتر VIEW SERVER STATE میخواهند. Azure SQL Database بسته به سطح سرویس VIEW DATABASE STATE یا نقش مدیریتی متناظر را نیاز دارد.
سؤالات مصاحبه
سؤال مصاحبه ۱: free_worker_count منفی چه معنایی دارد؟
در بار بسیار سنگین و با احتساب Worker اصلی Requestها ممکن است ظرفیت محاسبهشده منفی شود. باید با THREADPOOL، Blocking و تداوم فشار تأیید شود.
سؤال مصاحبه ۲: چرا تحلیل سطح Node مهم است؟
Aggregate کل میتواند فشار یک NUMA Node را با ظرفیت آزاد Node دیگر پنهان کند. Scheduler و Worker عملاً در Node توزیع شدهاند.
سؤال مصاحبه ۳: آیا used + free باید max شود؟
الزاماً نه؛ reserved_worker_count و used_worker_count Scope یکسانی ندارند و Worker اصلی Requestها در تعریف Reserved اثر دارد. ستونها شاخص عملیاتیاند.
سؤال مصاحبه ۴: چه Waitی را کنار این DMV میبینید؟
THREADPOOL برای کمبود Worker اهمیت اصلی دارد. CXPACKET و CXCONSUMER نیز برای رفتار Parallelism مفیدند، اما به تنهایی نشانه بد بودن Plan نیستند.
سؤال مصاحبه ۵: اولین اقدام هنگام Worker Pressure چیست؟
شواهد زماندار، Node آسیبدیده، Blocking و Queryهای با DOP بالا را ثبت میکنم؛ سپس Query و Workload را پیش از تغییر سراسری تنظیمات بررسی میکنم.
چکلیست نهایی
- ظرفیت هر Node جداگانه ثبت شده است.
- free_worker_count منفی یا پایین در چند Snapshot تأیید شده است.
- THREADPOOL، CXPACKET، CXCONSUMER و Blocking بررسی شدهاند.
- DOP و Worker Queryهای دارای Grant ثبت شدهاند.
- Aggregate کل با Minimum Node مقایسه شده است.
- تعریف متفاوت reserved و used در محاسبات رعایت شده است.
- MAXDOP و Cost Threshold فقط با تست بار تغییر میکنند.
- برنامه بازگشت و معیار Throughput و Latency وجود دارد.
جمعبندی
sys.dm_exec_query_parallel_workers ظرفیت Worker موازی را در جایی نشان میدهد که Aggregateهای سطح سرور ممکن است مشکل را پنهان کنند: هر NUMA Node. درصد آزاد، مقدار منفی، رزرو و مصرف موازی سرنخهایی برای تشخیص فشار Worker و عدم تعادل هستند.
تفسیر درست به چند Snapshot و ترکیب با THREADPOOL، Blocking، DOP و Memory Grant نیاز دارد. اصلاح Query و Workload معمولاً پیش از تغییر سراسری MAXDOP یا Max Worker Threads قرار میگیرد و نتیجه باید با Throughput و Latency واقعی سنجیده شود.
برای تکمیل تصویر عیبیابی، به مقاله مادر DMVهای Query Memory و نقشه تشخیص یکپارچه بازگردید.