sys.dm_exec_query_resource_semaphores؛ تشخیص فشار حافظه با ۱۰ مثال

آموزش sys.dm_exec_query_resource_semaphores در SQL Server

توسط admin | گروه SQL Server | 1405/04/31

نظرات 0

آموزش sys.dm_exec_query_resource_semaphores در SQL Server؛ تشخیص فشار حافظه اجرا

مقدمه

Resource Semaphore سازوکاری است که SQL Server با آن حافظه لازم برای اجرای Queryهای دارای Sort، Hash و دیگر عملگرهای حافظه‌بر را میان درخواست‌های هم‌زمان توزیع می‌کند. DMV با نام sys.dm_exec_query_resource_semaphores نمای کلان وضعیت این سازوکار را نشان می‌دهد: چه مقدار حافظه هدف‌گذاری شده، چه مقدار در اختیار Queryها قرار گرفته، چه مقدار واقعاً استفاده می‌شود و چند Request در صف یا دارای Grant هستند.

برخلاف sys.dm_exec_query_memory_grants که هر Request را جداگانه نمایش می‌دهد، این نما در سطح Semaphore و Resource Pool خلاصه است. در حالت معمول برای هر Pool یک ردیف Semaphore عادی با resource_semaphore_id برابر صفر و یک ردیف Small Query Semaphore با شناسه یک دیده می‌شود. Small Semaphore برای Queryهایی در نظر گرفته می‌شود که هم درخواست حافظه کمتر از پنج مگابایت و هم هزینه تخمینی کمتر از سه Cost Unit دارند.

وجود waiter_count مثبت، available_memory_kb بسیار کم و Grantهای فعال بزرگ می‌تواند فشار Execution Memory را تأیید کند، اما یک Snapshot منفرد کافی نیست. timeout_error_count و forced_grant_count شمارنده‌های تجمعی از زمان راه‌اندازی سرویس‌اند و باید به‌صورت Delta تحلیل شوند. در محیط دارای Resource Governor هر Pool Semaphoreهای مستقل دارد؛ بنابراین pool_id بخش جدایی‌ناپذیر هر Join و گزارش است.

این مطلب بخشی از راهنمای جامع DMVهای حافظه Query در SQL Server است. برای دیدن ارتباط این نما با Semaphoreهای اجرا، Gateهای Compile و Workerهای Parallel می‌توانید ابتدا یا پس از مطالعه این مقاله به راهنمای مادر بازگردید.

تعریف sys.dm_exec_query_resource_semaphores

sys.dm_exec_query_resource_semaphores وضعیت جاری حافظه Query Execution را برای Semaphoreها برمی‌گرداند. target_memory_kb هدف مصرف Grant، max_target_memory_kb سقف بالقوه، total_memory_kb مجموع حافظه آزاد و اعطاشده، available_memory_kb ظرفیت قابل اعطا، granted_memory_kb حافظه رزروشده برای Queryها و used_memory_kb بخش واقعاً مصرف‌شده را بیان می‌کنند.

grantee_count تعداد Queryهایی است که Grant خود را دریافت کرده‌اند و waiter_count تعداد Queryهای در صف را نشان می‌دهد. timeout_error_count تعداد Timeoutهای Memory Grant از زمان Startup و forced_grant_count تعداد دفعات اعطای حداقل اجباری را ثبت می‌کند. برای Small Semaphore این دو ستون می‌توانند NULL باشند؛ در نتیجه Queryهای مانیتورینگ باید رفتار NULL را صریح مدیریت کنند.

این DMV برای عیب‌یابی طراحی شده است و ساختار آن نباید بدون کنترل نسخه به یک Contract دائمی نرم‌افزار تجاری تبدیل شود. برای تصویر کامل، داده آن را با sys.dm_exec_query_memory_grants، Memory Clerk از نوع MEMORYCLERK_SQLQERESERVATIONS، Wait Statistics و Planهای Queryهای بزرگ ترکیب کنید.

Syntax پایه

SELECT
        pool_id,
        resource_semaphore_id,
        target_memory_kb,
        total_memory_kb,
        available_memory_kb,
        granted_memory_kb,
        used_memory_kb,
        grantee_count,
        waiter_count
    FROM sys.dm_exec_query_resource_semaphores;

مجوزها و سازگاری نسخه

در SQL Server 2022 و نسخه‌های جدیدتر VIEW SERVER PERFORMANCE STATE لازم است. در SQL Server و SQL Managed Instance قدیمی‌تر معمولاً VIEW SERVER STATE نیاز است. در Azure SQL Database سطح سرویس، نقش مدیریتی و VIEW DATABASE STATE تعیین‌کننده است. در Synapse یا APS نام DMV توزیع‌شده متفاوت است و Serverless SQL Pool آن Syntax را پشتیبانی نمی‌کند.

ستون‌های مهم و نحوه تفسیر

این ستون‌ها وضعیت ظرفیت، مصرف و صف را در یک Snapshot نشان می‌دهند. اعداد حافظه بر حسب کیلوبایت‌اند و شمارنده‌های Timeout و Forced Grant تجمعی هستند؛ پس برای نرخ رخداد باید مقدار قبلی و زمان Startup نگهداری شود.

ستوننوع دادهتفسیر و کاربرد
resource_semaphore_idsmallintشناسه صفر برای Semaphore عادی و یک برای Small Query؛ در کل Instance یکتا نیست.
pool_idintشناسه Resource Pool؛ همراه semaphore_id کلید تحلیلی درست را می‌سازد.
target_memory_kbbigintهدف جاری مصرف حافظه Grant در Semaphore.
max_target_memory_kbbigintسقف بالقوه هدف؛ برای Small Semaphore معمولاً NULL است.
total_memory_kbbigintمجموع available_memory_kb و granted_memory_kb؛ ممکن است تحت فشار از Target عبور کند.
available_memory_kbbigintحافظه در دسترس برای Grant تازه.
granted_memory_kbbigintمجموع حافظه اعطاشده به Queryهای فعال.
used_memory_kbbigintبخش فیزیکی مصرف‌شده از حافظه اعطاشده.
grantee_countintتعداد Requestهایی که Grant دریافت کرده‌اند.
waiter_countintتعداد Requestهایی که منتظر Grant هستند.
timeout_error_countbigintشمار تجمعی Timeoutها از Startup؛ برای Small Semaphore می‌تواند NULL باشد.
forced_grant_countbigintشمار Grant حداقلی اجباری از Startup؛ برای Small Semaphore می‌تواند NULL باشد.

Semaphore معمولی، Small Query و Resource Pool

SQL Server Queryهای دارای Memory Grant را بر اساس اندازه و Cost به مسیرهای مناسب هدایت می‌کند. Small Query Semaphore برای درخواست‌هایی است که کمتر از پنج مگابایت حافظه می‌خواهند و Cost تخمینی آن‌ها کمتر از سه است. این مسیر اجازه می‌دهد Queryهای کوچک در زمان اشغال Semaphore اصلی توسط گزارش‌های بزرگ همچنان ظرفیت محدود و مستقلی داشته باشند. اگر یکی از دو شرط برقرار نباشد، Query لزوماً Small محسوب نمی‌شود.

total_memory_kb طبق تعریف مجموع available و granted است. target_memory_kb هدف جاری و max_target_memory_kb سقف بالقوه‌ای است که با وضعیت حافظه سرور تغییر می‌کند. تحت فشار یا Forced Minimum Grant مکرر، total ممکن است از Target یا حتی Max Target گزارش‌شده بزرگ‌تر باشد؛ پس فرض نکنید این ستون‌ها همیشه یک رابطه ساده ثابت دارند.

Resource Governor می‌تواند چند Resource Pool بسازد و هر Pool مانند یک محدوده مستقل برای تخصیص منابع رفتار کند. هر Pool Semaphoreهای خودش را دارد؛ در نتیجه resource_semaphore_id بین Poolها تکرار می‌شود. برای اتصال به sys.dm_exec_query_memory_grants باید هم pool_id و هم resource_semaphore_id برابر باشند. Join فقط بر اساس شناسه Semaphore باعث چندبرابر شدن ردیف و نتیجه نادرست می‌شود.

waiter_count وضعیت لحظه‌ای است، اما timeout_error_count و forced_grant_count تجمعی‌اند. اگر فقط مقدار مطلق را ببینید نمی‌دانید رخداد مربوط به امروز است یا ماه گذشته. Collector باید CaptureTime و مقدار قبلی را ذخیره و Delta را محاسبه کند. Restart سرویس شمارنده‌ها را صفر می‌کند؛ زمان شروع SQL Server را نیز در تحلیل نگه دارید.

قاعده کلیدی: فشار واقعی را با ترکیب waiter_count مثبت، available_memory_kb پایین، Grantهای فعال و Wait از نوع RESOURCE_SEMAPHORE تأیید کنید. برای Resource Governor همیشه کلید ترکیبی pool_id و resource_semaphore_id را به کار ببرید.

ده مثال عملی و قابل اجرا

مثال ۱: نمایش وضعیت خام همه Semaphoreها

این Query ساده همه ستون‌های کلیدی را برای Snapshot اولیه انتخاب می‌کند و نتیجه را بر اساس Pool و نوع Semaphore مرتب می‌سازد. برای Job دائمی بهتر است دقیقاً همین ستون‌های موردنیاز صریح انتخاب شوند.

SELECT
        pool_id,
        resource_semaphore_id,
        target_memory_kb,
        total_memory_kb,
        available_memory_kb,
        granted_memory_kb,
        used_memory_kb,
        grantee_count,
        waiter_count
    FROM sys.dm_exec_query_resource_semaphores
    ORDER BY pool_id, resource_semaphore_id;
pool_idresource_semaphore_idavailable_memory_kbgrantee_countwaiter_count
10524288183
119830460

نکتهٔ کاربردی: شناسه صفر Semaphore معمولی و یک Small Query است. Snapshot را با زمان ثبت کنید، چون مقدارها با شروع و پایان Queryها تغییر می‌کنند.

مثال ۲: تبدیل ظرفیت حافظه به مگابایت

نمایش مگابایت برای داشبورد و گزارش انسانی خواناتر است. تبدیل با تقسیم اعشاری انجام می‌شود تا بخش کسری حذف نشود و decimal خروجی پایدار ارائه کند.

SELECT
        pool_id,
        resource_semaphore_id,
        TargetMB = CAST(target_memory_kb / 1024.0 AS decimal(18, 2)),
        TotalMB = CAST(total_memory_kb / 1024.0 AS decimal(18, 2)),
        AvailableMB = CAST(available_memory_kb / 1024.0 AS decimal(18, 2)),
        GrantedMB = CAST(granted_memory_kb / 1024.0 AS decimal(18, 2)),
        UsedMB = CAST(used_memory_kb / 1024.0 AS decimal(18, 2))
    FROM sys.dm_exec_query_resource_semaphores;
pool_idresource_semaphore_idTargetMBAvailableMBGrantedMBUsedMB
108192.00512.007680.006240.50
11128.0096.0032.0018.75

نکتهٔ کاربردی: granted حافظه رزروشده و used مصرف فیزیکی است. فاصله این دو در سطح Semaphore سرنخ Over-Grant جمعی است، ولی Queryهای منفرد را در DMV Memory Grants پیدا کنید.

مثال ۳: نام‌گذاری Semaphore معمولی و Small Query

CASE شناسه فنی را به برچسب خوانا تبدیل می‌کند. این Query همچنین شروط Small Query را در توضیح خروجی منعکس می‌کند، اما طبقه‌بندی واقعی را موتور SQL Server انجام می‌دهد.

SELECT
        pool_id,
        resource_semaphore_id,
        SemaphoreType = CASE resource_semaphore_id
            WHEN 0 THEN N'Regular'
            WHEN 1 THEN N'Small Query'
            ELSE N'Other'
        END,
        grantee_count,
        waiter_count
    FROM sys.dm_exec_query_resource_semaphores
    ORDER BY pool_id, resource_semaphore_id;
pool_idresource_semaphore_idSemaphoreTypegrantee_countwaiter_count
10Regular183
11Small Query60

نکتهٔ کاربردی: Small Query باید هم کمتر از پنج مگابایت Grant درخواست کند و هم Cost کمتر از سه داشته باشد. صرف کوچک بودن یکی از این دو معیار کافی نیست.

مثال ۴: فیلتر Semaphoreهای دارای صف

برای Alert اولیه فقط ردیف‌هایی انتخاب می‌شوند که waiter_count آن‌ها مثبت است. حافظه آزاد و اعطاشده نشان می‌دهد صف در چه Pool و چه نوع Semaphore رخ داده است.

SELECT
        pool_id,
        resource_semaphore_id,
        waiter_count,
        grantee_count,
        available_memory_kb,
        granted_memory_kb,
        used_memory_kb
    FROM sys.dm_exec_query_resource_semaphores
    WHERE waiter_count > 0
    ORDER BY waiter_count DESC, available_memory_kb;
pool_idresource_semaphore_idwaiter_countavailable_memory_kbgranted_memory_kb
207163848388608
1035242887864320

نکتهٔ کاربردی: waiter_count مثبت را با چند Snapshot و Grantهای منتظر همان Pool تأیید کنید. صفر بودن در یک لحظه می‌تواند صف کوتاه‌مدت بین دو نمونه را پنهان کند.

مثال ۵: محاسبه درصد ظرفیت آزاد

available_memory_kb نسبت به total_memory_kb به درصد تبدیل می‌شود. NULLIF از خطای تقسیم بر صفر جلوگیری می‌کند و درصد کم در کنار Waiter مثبت ردیف‌های پرریسک را مشخص می‌سازد.

SELECT
        pool_id,
        resource_semaphore_id,
        FreePercent = CAST(100.0 * available_memory_kb /
            NULLIF(total_memory_kb, 0) AS decimal(6, 2)),
        waiter_count,
        grantee_count
    FROM sys.dm_exec_query_resource_semaphores
    ORDER BY FreePercent, waiter_count DESC;
pool_idresource_semaphore_idFreePercentwaiter_countgrantee_count
200.19724
106.25318
1175.0006

نکتهٔ کاربردی: درصد پایین بدون Waiter ممکن است گذرا یا قابل‌قبول باشد. تداوم، مدت انتظار Requestها و روند مصرف برای Alert قابل‌اعتمادترند.

مثال ۶: مدیریت NULL و خواندن شمارنده‌های تجمعی

timeout_error_count و forced_grant_count برای Small Semaphore می‌توانند NULL باشند. COALESCE برای نمایش داشبورد مقدار صفر می‌گذارد، اما ستون IsCounterAvailable مشخص می‌کند صفر واقعی با نبود شمارنده اشتباه نشود.

SELECT
        pool_id,
        resource_semaphore_id,
        IsCounterAvailable = CASE
            WHEN timeout_error_count IS NULL THEN 0 ELSE 1
        END,
        TimeoutErrors = COALESCE(timeout_error_count, 0),
        ForcedGrants = COALESCE(forced_grant_count, 0)
    FROM sys.dm_exec_query_resource_semaphores;
pool_idresource_semaphore_idIsCounterAvailableTimeoutErrorsForcedGrants
1011231
11000

نکتهٔ کاربردی: برای Alert از Delta شمارنده‌ها استفاده کنید. صفر نمایشی Small Semaphore به معنی ثبت صفر رخداد نیست؛ ممکن است ستون اساساً قابل‌اعمال نباشد.

مثال ۷: خلاصه فشار به تفکیک Resource Pool

در محیط Resource Governor، مجموع ظرفیت و صف برای هر Pool محاسبه می‌شود. این سطح گزارش به تیم کمک می‌کند Workload آسیب‌دیده را از سایر Poolها جدا کند.

SELECT
        pool_id,
        SemaphoreCount = COUNT_BIG(*),
        TotalMemoryMB = CAST(SUM(total_memory_kb) / 1024.0 AS decimal(18, 2)),
        AvailableMemoryMB = CAST(SUM(available_memory_kb) / 1024.0 AS decimal(18, 2)),
        TotalGrantees = SUM(grantee_count),
        TotalWaiters = SUM(waiter_count)
    FROM sys.dm_exec_query_resource_semaphores
    GROUP BY pool_id
    ORDER BY TotalWaiters DESC, AvailableMemoryMB;
pool_idSemaphoreCountTotalMemoryMBAvailableMemoryMBTotalWaiters
228320.0048.007
128320.00608.003

نکتهٔ کاربردی: Aggregate جزئیات Regular و Small را پنهان می‌کند؛ هنگام Alert دوباره به سطح Semaphore برگردید و سیاست Pool را با Workload Group بررسی کنید.

مثال ۸: اتصال صحیح به Requestهای Memory Grant

این مثال Semaphore را با Grantهای همان Pool و همان شناسه متصل می‌کند. استفاده از هر دو کلید مانع تکثیر اشتباه ردیف‌ها در سرور دارای چند Resource Pool می‌شود.

SELECT
        rs.pool_id,
        rs.resource_semaphore_id,
        rs.waiter_count,
        mg.session_id,
        mg.wait_time_ms,
        mg.requested_memory_kb,
        mg.grant_time
    FROM sys.dm_exec_query_resource_semaphores AS rs
    LEFT JOIN sys.dm_exec_query_memory_grants AS mg
        ON mg.pool_id = rs.pool_id
       AND mg.resource_semaphore_id = rs.resource_semaphore_id
    WHERE rs.waiter_count > 0
    ORDER BY rs.pool_id, rs.resource_semaphore_id, mg.wait_time_ms DESC;
pool_idresource_semaphore_idwaiter_countsession_idwait_time_ms
2078122140
207867900

نکتهٔ کاربردی: اگر Join فقط روی resource_semaphore_id باشد، Sessionهای Poolهای دیگر نیز به ردیف وصل می‌شوند. این خطا در داشبوردها بسیار رایج و گمراه‌کننده است.

مثال ۹: محاسبه Delta شمارنده‌ها با Snapshot نمونه

این نمونه قابل اجرا دو Snapshot فرضی را با VALUES می‌سازد تا روش محاسبه Delta روشن شود. در سامانه واقعی OldValue و NewValue از جدول تاریخچه و با توجه به زمان Startup خوانده می‌شوند.

WITH Samples AS
    (
        SELECT *
        FROM (VALUES
            (1, 0, CAST(10 AS bigint), CAST(28 AS bigint)),
            (1, 0, CAST(12 AS bigint), CAST(31 AS bigint))
        ) AS v(pool_id, resource_semaphore_id, timeout_count, forced_count)
    ), Numbered AS
    (
        SELECT *,
            rn = ROW_NUMBER() OVER
                (PARTITION BY pool_id, resource_semaphore_id ORDER BY timeout_count)
        FROM Samples
    )
    SELECT
        CurrentTimeoutDelta = MAX(timeout_count) - MIN(timeout_count),
        CurrentForcedGrantDelta = MAX(forced_count) - MIN(forced_count)
    FROM Numbered
    WHERE rn IN (1, 2);
CurrentTimeoutDeltaCurrentForcedGrantDelta
23

نکتهٔ کاربردی: در Collector واقعی ترتیب را با CaptureTime تعیین کنید و اگر Startup تغییر کرده است Delta قبلی را ادامه ندهید؛ Restart شمارنده‌ها را بازنشانی می‌کند.

مثال ۱۰: طبقه‌بندی سلامت Semaphore برای Alert

CASE یک وضعیت ساده Operational می‌سازد. بحرانی زمانی است که Waiter وجود دارد و ظرفیت آزاد کمتر از یک درصد کل است؛ حالت هشدار برای هر Waiter دیگر و حالت عادی برای نبود صف استفاده می‌شود.

SELECT
        pool_id,
        resource_semaphore_id,
        waiter_count,
        available_memory_kb,
        total_memory_kb,
        HealthState = CASE
            WHEN waiter_count > 0
             AND 100.0 * available_memory_kb /
                 NULLIF(total_memory_kb, 0) < 1 THEN N'Critical'
            WHEN waiter_count > 0 THEN N'Warning'
            ELSE N'Healthy'
        END
    FROM sys.dm_exec_query_resource_semaphores
    ORDER BY CASE
        WHEN waiter_count > 0 AND 100.0 * available_memory_kb /
             NULLIF(total_memory_kb, 0) < 1 THEN 0
        WHEN waiter_count > 0 THEN 1 ELSE 2 END;
pool_idresource_semaphore_idwaiter_countHealthState
207Critical
103Warning
110Healthy

نکتهٔ کاربردی: آستانه یک درصد فقط نمونه است. مقدار Production باید از Baseline، مدت صف و SLA به دست آید و در چند Snapshot متوالی فعال شود.

خطاهای رایج

تفسیر این DMV به علت ترکیب Snapshotهای لحظه‌ای و شمارنده‌های تجمعی مستعد خطاست. موارد زیر از رایج‌ترین علت‌های گزارش نادرست یا اقدام اصلاحی نامتناسب‌اند.

  • Join کردن فقط با resource_semaphore_id و نادیده گرفتن pool_id در محیط Resource Governor.
  • فرض اینکه Small Query فقط با اندازه کمتر از پنج مگابایت تعریف می‌شود و نادیده گرفتن شرط Cost کمتر از سه.
  • مقایسه مقدار مطلق timeout_error_count بدون Delta و زمان Startup.
  • تعبیر available_memory_kb پایین بدون توجه به waiter_count و Grantهای فعال.
  • فرض اینکه total_memory_kb همیشه کمتر از target یا max_target می‌ماند.
  • تبدیل NULL شمارنده Small Semaphore به صفر بدون ثبت اینکه ستون قابل‌اعمال نیست.
  • استفاده از یک Threshold ثابت برای همه Poolها و همه ساعات کاری.
  • تمرکز بر Semaphore و حذف بررسی Queryهای دارنده Grant، Plan و Wait Statistics.

ملاحظات Performance

خواندن چند ستون از این DMV سبک است، اما Aggregate و ORDER BY مکرر در لحظه فشار حافظه می‌تواند سهمی از منابع مصرف کند. Snapshot پایه را بدون Joinهای حجیم بگیرید و فقط هنگام مشاهده Waiter به Memory Grants و SQL Text متصل شوید.

برای Trend، مقادیر عددی باریک را ذخیره کنید. timeout_error_count و forced_grant_count را به‌صورت Delta با CaptureTime و زمان Startup نگه دارید. ذخیره هر ثانیه برای همیشه معمولاً ارزش ندارد؛ Retention و Rollup ساعتی یا روزانه باید با نیاز Incident هماهنگ باشد.

Microsoft این نما را ابزار Troubleshooting می‌داند، نه Contract ثابت یک Application برای همه نسخه‌های آینده. Collector باید نسخه SQL Server و وجود ستون‌ها را کنترل کند و تغییر Schema را در Deployment آزمایش نماید.

  • ابتدا DMV را مستقل و بدون Plan XML نمونه‌برداری کنید.
  • Join به Memory Grants را فقط برای Pool و Semaphore هدف اجرا کنید.
  • Aggregate و ORDER BY را با نرخ نمونه‌برداری محدود کنید.
  • CaptureTime و SQL Server Start Time را کنار شمارنده‌ها ذخیره کنید.
  • Retention تاریخچه و Rollup را از ابتدا تعریف کنید.
  • Collector را پس از Upgrade نسخه دوباره اعتبارسنجی کنید.

بهترین روش‌ها و کاربرد سازمانی

در Runbook فشار حافظه، Semaphore باید لایه تأیید باشد. ابتدا وجود Grant منتظر را ثبت کنید، سپس ببینید Pool مربوط چه مقدار حافظه آزاد، اعطاشده و مصرف‌شده دارد. پس از آن Queryهای دارنده Grant را بر اساس حجم و مصرف واقعی بررسی کنید. این ترتیب از تمرکز اشتباه روی یک Session منتظر جلوگیری می‌کند.

در محیط Resource Governor، Baseline هر Pool را مستقل بسازید. Pool گزارش‌گیری ممکن است عمداً محدود باشد و Waiter آن نباید با Default Pool یکسان تفسیر شود. سیاست Min و Max Memory Percent، Workload Group، زمان‌بندی Jobها و اولویت کسب‌وکار باید در تصمیم اصلاحی لحاظ شوند.

برای پروژه‌های مانیتورینگ، Alert چندشرطی بسازید: waiter_count پایدار، available percent پایین و رشد wait_time Requestها. سپس Playbook شامل ثبت Text و Plan، مالک سرویس، اقدام اضطراری مجاز و Escalation باشد. این طراحی از هشدار کاذب و واکنش‌های مخرب می‌کاهد.

  1. Baseline جداگانه برای Regular و Small Semaphore هر Pool ثبت کنید.
  2. Alert را با تداوم Waiter و ظرفیت آزاد بسازید.
  3. هنگام رخداد Requestهای منتظر و Granteeهای بزرگ را هم‌زمان ذخیره کنید.
  4. Delta Timeout و Forced Grant را نسبت به Snapshot قبلی محاسبه کنید.
  5. Plan، Statistics، Spill و Concurrency عامل‌های اصلی را اصلاح کنید.
  6. نتیجه تغییر را در همان بازه بار با Baseline مقایسه کنید.

سؤالات متداول

پرسش ۱: sys.dm_exec_query_resource_semaphores چه چیزی نشان می‌دهد؟

وضعیت جاری حافظه اجرای Query را در سطح Resource Semaphore و Pool نمایش می‌دهد. ظرفیت هدف، حافظه آزاد، Grant و مصرف، تعداد Queryهای دارای Grant و تعداد منتظرها در دسترس است. برای یافتن Sessionهای دقیق باید آن را با sys.dm_exec_query_memory_grants ترکیب کنید.

پرسش ۲: تفاوت Semaphore عادی و Small Query چیست؟

Semaphore عادی بیشتر Grantهای اجرا را مدیریت می‌کند. Small Query Semaphore برای Queryهایی است که هم کمتر از پنج مگابایت حافظه می‌خواهند و هم Cost تخمینی کمتر از سه دارند. این مسیر ظرفیت محدودی برای جلوگیری از متوقف شدن Queryهای کوچک در پشت مصرف‌کنندگان بزرگ فراهم می‌کند.

پرسش ۳: این DMV چگونه از SLA یک سامانه تجاری محافظت می‌کند؟

رشد waiter_count می‌تواند تأخیر گزارش‌ها و APIهای وابسته به SQL Server را پیش از اشباع CPU نشان دهد. با Baseline و Alert چندشرطی، تیم عملیات زودتر Pool و Workload آسیب‌دیده را تشخیص می‌دهد. Threshold باید بر اساس ساعت اوج و اهمیت فرایند کسب‌وکار تنظیم شود.

پرسش ۴: آیا افزایش حافظه سرور بهترین راه رفع Semaphore Wait است؟

نه همیشه. Query با Estimate اشتباه، Grant بیش‌ازحد، Concurrency گزارش‌ها یا محدودیت Resource Governor می‌تواند علت اصلی باشد. تحلیل تخصصی Plan، Statistics و Pool معمولاً مشخص می‌کند اصلاح نرم‌افزاری یا زمان‌بندی از خرید سخت‌افزار مؤثرتر است. افزایش RAM باید پس از سنجش کمبود ظرفیت واقعی انجام شود.

پرسش ۵: تفاوت waiter_count و timeout_error_count چیست؟

waiter_count تعداد Requestهای منتظر در همین لحظه است. timeout_error_count شمار تجمعی Timeoutها از زمان Startup است و برای Small Semaphore می‌تواند NULL باشد. برای روندسنجی Timeout باید Delta دو Snapshot با Startup یکسان محاسبه شود؛ مقدار مطلق شدت فعلی را نشان نمی‌دهد.

پرسش ۶: چگونه داشبورد Resource Semaphore بسازیم؟

CaptureTime، pool_id، semaphore_id، ظرفیت، Grant، مصرف، Grantee، Waiter و شمارنده‌ها را در جدول باریک ذخیره کنید. Alert را روی تداوم صف و درصد آزاد بسازید و Drill-down به Memory Grants فراهم کنید. طراحی Retention، نسخه‌پذیری و امنیت باید در پروژه مانیتورینگ آزمایش شود.

پرسش ۷: چرا Join بر اساس semaphore_id نتیجه تکراری می‌دهد؟

resource_semaphore_id در کل Instance یکتا نیست و در Resource Poolهای مختلف تکرار می‌شود. شرط اتصال درست شامل pool_id و resource_semaphore_id است. حذف pool_id باعث اتصال Grantهای یک Pool به Semaphoreهای Pool دیگر و چندبرابر شدن شمار Sessionها می‌شود.

پرسش ۸: اجرای Aggregate روی این DMV چه ریسکی دارد؟

ORDER BY و Aggregate خود می‌توانند حافظه و CPU مصرف کنند، به‌ویژه اگر با DMVهای دیگر و Plan XML ترکیب شوند. در بحران، Snapshot سبک بگیرید و جزئیات را برای Pool هدف واکشی کنید. نرخ Polling و زمان اجرای Collector نیز باید مانیتور شود.

پرسش ۹: بهترین روش Alert برای waiter_count چیست؟

یک Waiter لحظه‌ای را بحران تلقی نکنید. چند نمونه متوالی، رشد مدت انتظار در Memory Grants، available percent پایین و Wait Type را ترکیب کنید. آستانه و بازه باید از Baseline همان Pool و SLA استخراج شود و پس از تغییر Workload بازتنظیم گردد.

پرسش ۱۰: مجوز و سازگاری نسخه این DMV چیست؟

در SQL Server 2022 و بعد VIEW SERVER PERFORMANCE STATE و در نسخه‌های قدیمی‌تر معمولاً VIEW SERVER STATE لازم است. Azure SQL Database قواعد مجوز متفاوتی دارد. ساختار DMV ابزار عیب‌یابی است؛ Collector باید نسخه و ستون‌ها را پس از Upgrade کنترل کند.

سؤالات مصاحبه

سؤال مصاحبه ۱: total_memory_kb از چه اجزایی ساخته می‌شود؟

طبق تعریف مجموع available_memory_kb و granted_memory_kb است. used_memory_kb بخشی از Grant است که در لحظه واقعاً مصرف شده و نباید دوباره به Total افزوده شود.

سؤال مصاحبه ۲: شناسه صفر و یک Semaphore چه معنایی دارند؟

صفر Semaphore عادی و یک Small Query Semaphore است. این شناسه‌ها میان Resource Poolها تکرار می‌شوند، پس pool_id نیز باید در کلید تحلیل باشد.

سؤال مصاحبه ۳: Forced Grant چیست؟

وقتی فشار حافظه اجازه Grant کامل را نمی‌دهد، موتور ممکن است حداقل لازم را به‌صورت اجباری بدهد تا Query اجرا شود. افزایش Delta forced_grant_count می‌تواند با Spill و افت Performance همراه باشد.

سؤال مصاحبه ۴: چگونه فشار لحظه‌ای و تاریخی را جدا می‌کنید؟

waiter_count و available_memory وضعیت لحظه‌ای‌اند؛ timeout_error_count و forced_grant_count تجمعی‌اند. برای تاریخی از Snapshot و Delta با توجه به Startup استفاده می‌کنم.

سؤال مصاحبه ۵: Small Query چه دو شرطی دارد؟

Memory Grant درخواستی کمتر از پنج مگابایت و Query Cost کمتر از سه Cost Unit. هر دو شرط باید برقرار باشند.

چک‌لیست نهایی

  • Regular و Small Semaphore جداگانه بررسی شده‌اند.
  • pool_id در تمام Joinها و Groupها لحاظ شده است.
  • waiter_count در چند Snapshot ثبت شده است.
  • available، granted و used با واحد یکسان مقایسه شده‌اند.
  • شمارنده‌های تجمعی به‌صورت Delta و با Startup تحلیل شده‌اند.
  • Grantهای منتظر و دارندگان بزرگ همان Pool استخراج شده‌اند.
  • سیاست Resource Governor و SLA Workload بررسی شده است.
  • Alert با Baseline و تداوم چند نشانه تنظیم شده است.

جمع‌بندی

sys.dm_exec_query_resource_semaphores نمای کلان و ضروری برای اثبات فشار Execution Memory است. با آن می‌توان ظرفیت آزاد، Grant، مصرف، تعداد دریافت‌کنندگان و صف را در هر Pool مشاهده کرد. تفکیک Semaphore عادی و Small Query و استفاده از کلید ترکیبی Pool از شروط تحلیل صحیح است.

این نما به تنهایی Query مقصر را نام نمی‌برد؛ باید آن را با Memory Grants، Wait Statistics و Plan ترکیب کرد. Snapshotهای زمان‌دار، Delta شمارنده‌ها و Alert چندشرطی به تیم عملیات اجازه می‌دهد میان رخداد گذرا، محدودیت عمدی Pool و کمبود واقعی ظرفیت تفاوت بگذارد.

برای تکمیل تصویر عیب‌یابی، به مقاله مادر DMVهای Query Memory و نقشه تشخیص یکپارچه بازگردید.

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

حرف 500 حداکثر

اطلاعات تماس

  • آدرس:اصفهان-خیابان ام کلثوم غربی - بعد خیابان تخم چی - بیست متر بعد از پیتزا ننه شب - کوچه تعمیر گاه سمار زغالی - پلاک 354 - درب مشکی - طبقه هفتم
  • آدرس ایمیل:najafzade@gmail.com
  • وب سایت:http://www.a00b.com/
  • تلفن ثابت:(+98)9131253620
  • تلفن همراه:09131253620