مثالهای عملی
مثال 1: گرفتن Deadlock XML از Ring Buffer
در این سناریو هدف، دریافت سریع Graphهای اخیر بدون ساخت Collector تازه است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
;WITH system_health AS
(
SELECT CAST(t.target_data AS xml) AS target_xml
FROM sys.dm_xe_session_targets AS t
JOIN sys.dm_xe_sessions AS s ON s.address = t.event_session_address
WHERE s.name = N'system_health'
AND t.target_name = N'ring_buffer'
)
SELECT
n.e.value('@timestamp', 'datetime2') AS event_utc,
n.e.query('(data/value/deadlock)[1]') AS deadlock_xml
FROM system_health AS sh
CROSS APPLY sh.target_xml.nodes('/RingBufferTarget/event[@name="xml_deadlock_report"]') AS n(e)
ORDER BY event_utc DESC;
| خروجی نمونه | تفسیر |
|---|
| 2026-07-22 03:31:04 | <deadlock>...</deadlock> | نتیجه نمایشی مثال 1؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
Retention محدود است؛ رخداد مهم را زود به مخزن Incident منتقل کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 2: استخراج قربانی Deadlock
در این سناریو هدف، آموزش مسیر victim-list با یک XML کوچک و قابل اجرا است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @Deadlock xml = N'<deadlock><victim-list><victimProcess id="processA" /></victim-list></deadlock>';
SELECT v.p.value('@id', 'nvarchar(100)') AS victim_process_id
FROM @Deadlock.nodes('/deadlock/victim-list/victimProcess') AS v(p);
| خروجی نمونه | تفسیر |
|---|
| processA | نتیجه نمایشی مثال 2؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
شناسه Process داخل Graph با SPID یکسان نیست؛ آن را به node متناظر در process-list متصل کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 3: خواندن Process List و Input Buffer
در این سناریو هدف، تجزیه مشخصات هر Process از Graph با XQuery است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @Deadlock xml = N'<deadlock><process-list><process id="processA" spid="64" waitresource="KEY: 7:1" lockMode="X"><inputbuf>UPDATE dbo.Orders SET Status=2</inputbuf></process></process-list></deadlock>';
SELECT
p.n.value('@id', 'nvarchar(100)') AS process_id,
p.n.value('@spid', 'int') AS spid,
p.n.value('@waitresource', 'nvarchar(256)') AS wait_resource,
p.n.value('@lockMode', 'nvarchar(30)') AS lock_mode,
p.n.value('(inputbuf/text())[1]', 'nvarchar(4000)') AS input_buffer
FROM @Deadlock.nodes('/deadlock/process-list/process') AS p(n);
| خروجی نمونه | تفسیر |
|---|
| processA | 64 | KEY: 7:1 | X | UPDATE dbo.Orders ... | نتیجه نمایشی مثال 3؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
Input Buffer را برای Parameterها و Plan زمان رخداد با Query Store یا Actionهای XE غنی کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 4: خواندن Resource List
در این سناریو هدف، تبدیل انواع پویا در resource-list به ردیف قابل گزارش است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @Deadlock xml = N'<deadlock><resource-list><keylock hobtid="7205" dbid="7" objectname="Sales.dbo.Orders" indexname="PK_Orders" mode="X"><owner-list><owner id="processA" mode="X" /></owner-list><waiter-list><waiter id="processB" mode="S" requestType="wait" /></waiter-list></keylock></resource-list></deadlock>';
SELECT
r.n.value('local-name(.)', 'nvarchar(60)') AS resource_type,
r.n.value('@objectname', 'nvarchar(512)') AS object_name,
r.n.value('@indexname', 'nvarchar(512)') AS index_name,
r.n.value('@mode', 'nvarchar(30)') AS resource_mode
FROM @Deadlock.nodes('/deadlock/resource-list/*') AS r(n);
| خروجی نمونه | تفسیر |
|---|
| keylock | Sales.dbo.Orders | PK_Orders | X | نتیجه نمایشی مثال 4؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
نام شیء لحظه رخداد را نگه دارید؛ پس از Deploy ممکن است Index یا Object تغییر کرده باشد. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 5: اتصال Owner و Waiter به Process
در این سناریو هدف، بازسازی Edge مالک و منتظر روی هر Resource است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @Deadlock xml = N'<deadlock><resource-list><keylock objectname="Sales.dbo.Orders"><owner-list><owner id="processA" mode="X" /></owner-list><waiter-list><waiter id="processB" mode="S" /></waiter-list></keylock></resource-list></deadlock>';
SELECT
r.n.value('@objectname', 'nvarchar(512)') AS object_name,
r.n.value('(owner-list/owner/@id)[1]', 'nvarchar(100)') AS owner_process,
r.n.value('(owner-list/owner/@mode)[1]', 'nvarchar(30)') AS owner_mode,
r.n.value('(waiter-list/waiter/@id)[1]', 'nvarchar(100)') AS waiter_process,
r.n.value('(waiter-list/waiter/@mode)[1]', 'nvarchar(30)') AS waiter_mode
FROM @Deadlock.nodes('/deadlock/resource-list/*') AS r(n);
| خروجی نمونه | تفسیر |
|---|
| Sales.dbo.Orders | processA | X | processB | S | نتیجه نمایشی مثال 5؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
چرخه را در سطح همه منابع ببینید؛ تمرکز روی یک Edge ممکن است ترتیب متضاد را پنهان کند. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 6: بررسی اثر DEADLOCK_PRIORITY
در این سناریو هدف، نشان دادن تنظیم سطح Session برای Job کماهمیتتر است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
SET DEADLOCK_PRIORITY LOW;
SELECT N'این Session در تساوی هزینه Rollback، اولویت قربانی شدن بیشتری دارد.' AS note;
SET DEADLOCK_PRIORITY NORMAL;
| خروجی نمونه | تفسیر |
|---|
| این Session ... اولویت قربانی شدن بیشتری دارد. | نتیجه نمایشی مثال 6؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
Priority علت Deadlock را رفع نمیکند؛ فقط انتخاب قربانی را تحت تأثیر قرار میدهد. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 7: بازسازی Deadlock دو پنجرهای
در این سناریو هدف، نمایش اصل ترتیب متضاد دسترسی در یک آزمایش کنترلشده است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
-- Window A
BEGIN TRANSACTION;
UPDATE dbo.DeadlockLab SET ValueText = N'A1' WHERE Id = 1;
-- سپس در Window B ردیف 2 و بعد در A ردیف 2 را به ترتیب معکوس Update کنید.
-- پاکسازی Window A پس از آزمایش:
ROLLBACK TRANSACTION;
| خروجی نمونه | تفسیر |
|---|
| یکی از دو Transaction با خطای 1205 قربانی میشود | نتیجه نمایشی مثال 7؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
سناریو نیازمند دو Connection است؛ فقط روی جدول Lab و با برنامه Rollback اجرا شود. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 8: یکسانسازی ترتیب دسترسی برای پیشگیری
در این سناریو هدف، رفع چرخه با قرارداد ثابت ترتیب دسترسی به منابع است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
BEGIN TRANSACTION;
UPDATE dbo.DeadlockLab
SET ValueText = N'first'
WHERE Id = 1;
UPDATE dbo.DeadlockLab
SET ValueText = N'second'
WHERE Id = 2;
COMMIT TRANSACTION;
| خروجی نمونه | تفسیر |
|---|
| هر مسیر برنامه باید ردیفهای 1 و 2 را با همین ترتیب بگیرد | نتیجه نمایشی مثال 8؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
ترتیب یکسان اغلب مؤثرتر از Retry بیحد است و باید در همه Code Pathها رعایت شود. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 9: Retry محدود برای خطای 1205
در این سناریو هدف، افزودن Retry محدود و مخصوص 1205 در کنار اصلاح علت ریشهای است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
DECLARE @Attempt int = 1;
DECLARE @MaxAttempts int = 3;
WHILE @Attempt <= @MaxAttempts
BEGIN
BEGIN TRY
BEGIN TRANSACTION;
UPDATE dbo.DeadlockLab SET ValueText = N'processed' WHERE Id = 1;
COMMIT TRANSACTION;
BREAK;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;
IF ERROR_NUMBER() <> 1205 OR @Attempt = @MaxAttempts THROW;
SET @Attempt += 1;
END CATCH;
END;
| خروجی نمونه | تفسیر |
|---|
| موفقیت یا حداکثر سه تلاش؛ خطاهای دیگر دوباره پرتاب میشوند | نتیجه نمایشی مثال 9؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
در Application از Backoff و Jitter استفاده کنید و عملیات را Idempotent طراحی کنید. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
مثال 10: شاخصگذاری هدفمند بر اساس Graph
در این سناریو هدف، کاهش دامنه و مدت Lock با Index پشتیبان Predicate نمونه است. Query زیر یک نمونه مستقل و قابل اجرا برای محیط مناسب ارائه میکند؛ فرمانهای تغییردهنده باید ابتدا در Lab و با مجوز کنترلشده آزموده شوند.
IF NOT EXISTS
(
SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID(N'dbo.Orders')
AND name = N'IX_Orders_CustomerId'
)
BEGIN
CREATE INDEX IX_Orders_CustomerId
ON dbo.Orders(CustomerId)
INCLUDE (Status, OrderDate);
END;
| خروجی نمونه | تفسیر |
|---|
| Index فقط در صورت نبودن ساخته میشود | نتیجه نمایشی مثال 10؛ مقدار واقعی به بارکاری و نسخه سرور وابسته است. |
Index را از روی Plan و بار نوشتن تأیید کنید؛ افزودن کورکورانه Index هزینه DML و فضا دارد. این نتیجه نمونه کمک میکند پیش از اجرا شکل خروجی را بشناسید، اما جای مشاهده داده واقعی همان Incident را نمیگیرد.
سؤالات متداول
پرسش 1: Deadlock Graph دقیقاً چه مسئلهای را در SQL Server حل میکند؟
Deadlock Graph یک سند XML از چرخه وابستگی منابع است که قربانی انتخابشده، Processها، قفلهای نگهداشته و درخواستی و Batchهای درگیر را نشان میدهد. ارزش اصلی آن زمانی آشکار میشود که سؤال عملیاتی مشخص باشد؛ مثلاً شناسایی Head Blocker، تعیین منبع انتظار یا حفظ شواهد Deadlock. خروجی باید کنار زمان رخداد و مشخصات Application نگهداری شود تا از یک Snapshot خام به پاسخ قابل اقدام برسیم.
پرسش 2: برای شروع کار با Deadlock Graph چه پیشنیازی لازم است؟
ابتدا در محیط آزمایش Syntax و ستونهای نسخه نصبشده را بررسی کنید، سپس مجوز حداقلی مشاهده وضعیت را در نظر بگیرید. خواندن system_health و فایلهای XE به مجوز مشاهده وضعیت و دسترسی سرویس SQL Server به مسیر مربوط وابسته است. اجرای Query با حساب Production پرقدرت راهحل مناسبی نیست و بهتر است نقش مانیتورینگ مشخص و ممیزیشده ساخته شود.
پرسش 3: استفاده از Deadlock Graph چه ارزش تجاری برای سامانه پرتراکنش دارد؟
کاهش زمان تشخیص Incident، جلوگیری از تصمیم عجولانه و کوتاهشدن اختلال مستقیمترین ارزشها هستند. وقتی داده این ابزار با SLA و مالک سرویس پیوند بخورد، تیم میتواند بین کندی عادی، Blocking زیانآور و Deadlock تکرارشونده تفاوت بگذارد و هزینه توقف را کم کند.
پرسش 4: چه زمانی برای پیادهسازی مانیتورینگ Deadlock Graph به مشاوره تخصصی نیاز داریم؟
اگر رخدادها تکراری، چندپایگاهدادهای، حساس به امنیت یا دارای حجم Event بالا هستند، طراحی Baseline، Retention و Runbook تخصصی مفید است. مشاوره SQL Server باید در کنار جمعآوری داده، Query Plan، تراکنش، ایندکس و رفتار کد Application را نیز بررسی کند؛ خرید ابزار بدون فرایند پاسخگویی کافی نیست.
پرسش 5: تفاوت Deadlock Graph با ابزار نزدیک آن چیست؟
Blocked Process یک انتظار یکطرفه و قابل ادامه است؛ Deadlock یک چرخه است که موتور برای شکستن آن یک Transaction را قربانی میکند. انتخاب درست به این بستگی دارد که داده لحظهای، تاریخچه XML، مشخصات Session یا امکان اقدام مدیریتی لازم باشد. در عیبیابی حرفهای معمولاً چند منبع مکمل کنار هم استفاده میشوند، نه اینکه یک خروجی به تنهایی حقیقت کامل فرض شود.
پرسش 6: آیا میتوان پیادهسازی داشبورد یا پروژه Deadlock Graph را به تیم متخصص سپرد؟
بله؛ تحویل حرفهای باید شامل تعریف نیاز، Queryهای کمهزینه، کنترل مجوز، ذخیره UTC، سیاست Retention، هشدار قابل تنظیم، داشبورد و Runbook اعتبارسنجیشده باشد. پیش از پذیرش پروژه، اثر مانیتورینگ روی Production و روش تست خطا نیز باید مستند شود.
پرسش 7: رایجترین خطا هنگام تحلیل Deadlock Graph چیست؟
فرایند Victim الزاماً مقصر اصلی نیست؛ هزینه Rollback و DEADLOCK_PRIORITY در انتخاب قربانی اثر دارند. خطای دوم تصمیمگیری از روی یک Snapshot بدون Baseline است. زمان رخداد، Login، Host، Database، Transaction و Query متناظر را کنار هم قرار دهید و هر مقدار NULL یا نامشخص را صادقانه حفظ کنید.
پرسش 8: آیا Query گرفتن از Deadlock Graph روی Performance اثر میگذارد؟
به جای جمعآوری Plan و متن سنگین برای همه Queryها، Deadlock XML را نگه دارید و تنها رخدادهای مرتبط را غنیسازی کنید. خود مشاهده نیز رایگان نیست، بهویژه وقتی XML، Plan یا Text برای تعداد زیادی Session استخراج شود. Period نمونهبرداری، فیلتر، سقف نگهداری و مانیتور Dropped Event باید بخشی از طراحی باشد.
پرسش 9: بهترین روش استفاده Production از Deadlock Graph چیست؟
پرسش عملیاتی را از قبل تعریف کنید، کمترین ستون و Scope لازم را جمع کنید، Timestamp UTC و شناسه Incident بسازید و اقدام مخرب را از جمعآوری شواهد جدا نگه دارید. Runbook باید مرحله تأیید هویت Session، اثر Rollback، تماس با مالک سرویس و معیار پایان Incident را روشن کند.
پرسش 10: Deadlock Graph در کدام نسخههای SQL Server قابل استفاده است؟
جزئیات ستون، مجوز و Eventها با نسخه و Azure SQL تفاوت دارد؛ بنابراین metadata و مستندات همان نسخه باید مرجع نهایی باشد. خواندن system_health و فایلهای XE به مجوز مشاهده وضعیت و دسترسی سرویس SQL Server به مسیر مربوط وابسته است. در ارتقا، Queryها را روی محیط Stage اجرا کنید و بهویژه قابلیتهای Undocumented یا Deprecated را با جایگزین مستند عوض کنید.