NOLOCK در SQL Server: چرا Accelerated Database Recovery (ADR) راهحل نیست؟
تصور رایجی وجود دارد که قابلیت Accelerated Database Recovery (ADR) در SQL Server میتواند مشکلات مرتبط با استفاده از اشارهگر (hint) `NOLOCK` را برطرف کند. اما این برداشت اشتباه است. ADR و `NOLOCK` دو مفهوم کاملاً متفاوت هستند که به جنبههای مختلف عملکرد پایگاه داده میپردازند. در این مقاله به بررسی دقیق هر یک و چرایی عدم ارتباط آنها خواهیم پرداخت.
ADR یک ویژگی بازیابی و رولبک (بازگرداندن تغییرات) در SQL Server است که با هدف بهبود زمان ریکاوری پایگاه داده، بهویژه پس از خرابیها یا تراکنشهای طولانیمدت، طراحی شده است. ADR با استفاده از تکنولوژی Persistent Version Store (PVS) و پردازش منطقی بازگرداندن (Logical Revert) به موارد زیر کمک میکند:
* **رولبک فوری تراکنشها (Instant Transaction Rollback):** صرف نظر از زمان فعال بودن یا تعداد عملیات انجام شده، تراکنشها به سرعت به حالت اولیه بازگردانده میشوند.
* **بازیابی فوری پایگاه داده (Instant Database Recovery):** زمان ریکاوری پس از یک crash یا راهاندازی مجدد سرور، بسیار کاهش مییابد.
* **کوچک شدن تهاجمیتر لاگ تراکنش (Aggressive Transaction Log Truncation):** لاگ تراکنشها را میتوان فعالانهتر کوتاه کرد که به مدیریت فضای دیسک و کاهش زمان نگهداری لاگ کمک میکند.
این ویژگیها عمدتاً بر روی پایداری، در دسترس بودن و مدیریت منابع فیزیکی پایگاه داده تمرکز دارند. ADR تغییرات داده را نسخهبرداری میکند تا بتواند بدون نیاز به اسکن کامل لاگ تراکنش، آنها را به سرعت بازگرداند.
در مقابل، `NOLOCK` (که معادل `READ UNCOMMITTED` است) یک اشارهگر تراکنش (transaction hint) است که به SQL Server دستور میدهد تا قفلهای اشتراکی (shared locks) را نادیده بگیرد. این به این معنی است که کوئری شما بدون انتظار برای آزاد شدن قفلها، دادهها را میخواند. مزیت ظاهری این کار، افزایش همزمانی (concurrency) و سرعت خواندن دادهها است، زیرا خواننده منتظر تکمیل شدن تراکنشهای دیگر نمیماند.
اما استفاده از `NOLOCK` با هزینههای سنگینی همراه است و مشکلات جدی در یکپارچگی دادهها ایجاد میکند:
* **Dirty Reads (خواندن دادههای کثیف):** دادههایی را میخوانید که توسط یک تراکنش دیگر تغییر کردهاند اما هنوز commit نشدهاند. اگر آن تراکنش رولبک شود، شما دادههایی را خواندهاید که هرگز در پایگاه داده وجود نداشتهاند.
* **Phantom Reads (خواندن فانتوم):** اگر در طول یک تراکنش، دو بار یک کوئری مشابه را اجرا کنید، ممکن است مجموعه ردیفهای متفاوتی را مشاهده کنید، زیرا تراکنشهای دیگر ردیفهایی را درج یا حذف کردهاند.
* **Non-repeatable Reads (خواندن غیرقابل تکرار):** اگر یک کوئری را دو بار در یک تراکنش اجرا کنید، ممکن است مقادیر متفاوتی برای یک ردیف مشابه مشاهده کنید، زیرا تراکنشهای دیگر آن ردیف را تغییر داده و commit کردهاند.
به عبارت سادهتر، `NOLOCK` به شما اجازه میدهد تا دادههایی را ببینید که ممکن است نادرست، ناقص یا حتی کاملاً ناپایدار باشند. `NOLOCK` اعلام میکند که شما به پایداری و یکپارچگی دادهها در زمان خواندن اهمیتی نمیدهید و ریسک خواندن دادههای غلط را میپذیرید.
حال به سؤال اصلی بازگردیم: چرا ADR مشکلات `NOLOCK` را برطرف نمیکند؟
دلیل این امر ساده است: ADR و `NOLOCK` به مسائل کاملاً متفاوتی میپردازند.
ADR به مکانیسمهای فیزیکی مدیریت لاگ تراکنش و بازیابی پایگاه داده مربوط میشود. این ویژگی نحوه ذخیرهسازی نسخهها و برگشت دادن تغییرات در سطح موتور پایگاه داده را بهبود میبخشد تا فرآیندهای رولبک و ریکاوری سریعتر و کارآمدتر شوند. این تماماً در مورد اطمینان از اینکه پایگاه داده میتواند به سرعت پس از یک رویداد ناخواسته به حالت عملیاتی بازگردد و تراکنشها را به درستی رولبک کند.
**
SELECT
database_name,
log_reuse_wait_desc
FROM sys.databases
WHERE name = 'YourDatabaseName';
**
این کوئری وضعیت انتظار استفاده مجدد از لاگ تراکنش را برای یک پایگاه داده خاص نشان میدهد که میتواند تحت تأثیر ADR قرار گیرد. اما این تغییرات در نحوه مدیریت لاگ یا ریکاوری، هیچ تأثیری بر رفتار `NOLOCK` ندارد.
`NOLOCK` به سطح ایزولیشن (isolation level) تراکنشها مربوط میشود و نحوه تعامل یک تراکنش با قفلهای سایر تراکنشها را دیکته میکند. وقتی از `NOLOCK` استفاده میکنید، به SQL Server میگویید: “من نمیخواهم برای قفلهای هیچ کس منتظر بمانم. هر چیزی که در حال حاضر موجود است را، حتی اگر هنوز commit نشده باشد، به من نشان بده.” ADR این دستورالعمل شما را تغییر نمیدهد. `NOLOCK` همچنان قفلها را نادیده میگیرد و شما همچنان در معرض Dirty Reads، Phantom Reads و Non-repeatable Reads هستید.
ADR قفلهای خواندن (read locks) جدیدی را معرفی نمیکند یا رفتار قفلگذاری را برای `NOLOCK` تغییر نمیدهد. نسخهسازی دادهها که در ADR از آن استفاده میشود (Persistent Version Store – PVS) برای رولبک سریع تراکنشها و بازیابی پایگاه داده است، نه برای ارائه یکپارچگی خواندن (read consistency) به کوئریهایی که صراحتاً از `NOLOCK` استفاده میکنند. کوئریهای `NOLOCK` به PVS مراجعه نمیکنند تا نسخههای پایدار دادهها را بخوانند، بلکه مستقیماً به دادههای فعلی و ناپایدار دسترسی پیدا میکنند.
**
SELECT column1, column2
FROM YourTable WITH (NOLOCK)
WHERE column3 = 'Value';
**
این قطعه کد ساده نشان میدهد که چگونه یک کوئری با استفاده از `NOLOCK` اجرا میشود. ADR تأثیری بر روی نحوه پردازش این کوئری از نظر قفلگذاری یا ایزولیشن ندارد.
**نتیجهگیری**
Accelerated Database Recovery (ADR) یک ویژگی فوقالعاده برای بهبود پایداری و زمان ریکاوری SQL Server است. این قابلیت به طور قابل توجهی سرعت رولبک تراکنشها و بازیابی پایگاه داده را افزایش میدهد. با این حال، ADR به هیچ وجه مشکلات بنیادی ناشی از استفاده از اشارهگر `NOLOCK` را حل نمیکند. `NOLOCK` همچنان منجر به خواندن دادههای ناپایدار و ناسازگار میشود.
اگر به دادههای پایدار و یکپارچه نیاز دارید، باید از سطوح ایزولیشن مناسب مانند `READ COMMITTED` (که پیشفرض است) یا `READ COMMITTED SNAPSHOT` استفاده کنید. هرگز به امید اینکه ADR جادویی مشکلات `NOLOCK` را حل میکند، از آن استفاده نکنید. این دو ابزار برای اهداف کاملاً متفاوتی در معماری SQL Server طراحی شدهاند.