مقایسه توابع SQL Server Rowversion: درک عمیق MIN_ACTIVE_ROWVERSION و @@DBTS برای مدیریت همزمانی
مدیریت صحیح دادهها در SQL Server شامل درک ویژگیهای پیشرفتهای مانند نوع داده rowversion است. این نوع داده که قبلاً timestamp نامیده میشد، یک قابلیت مهم در SQL Server است که به طور خودکار مقادیر باینری منحصر به فردی را برای هر ردیف در یک جدول ایجاد میکند. این مقادیر هر بار که یک ردیف بهروزرسانی یا درج میشود، تغییر میکنند و به عنوان یک مکانیزم عالی برای تشخیص تغییرات یا مدیریت مسائل همزمانی عمل میکنند. در این مقاله، به بررسی دو تابع کلیدی مربوط به rowversion میپردازیم: @@DBTS و MIN_ACTIVE_ROWVERSION و تفاوتها و کاربردهای آنها را روشن میکنیم.
زمانی که یک ستون از نوع rowversion را در جدول خود تعریف میکنید، SQL Server به طور خودکار مقادیری را برای این ستون تولید میکند. این مقادیر منحصر به فرد هستند و هر بار که یک ردیف جدید درج میشود یا یک ردیف موجود بهروزرسانی میشود، مقدار rowversion آن ردیف تغییر میکند. این فرآیند شبیه به عملکرد ستون IDENTITY است، با این تفاوت که rowversion برای ردیفهای بهروزرسانی شده نیز مقدار جدیدی تولید میکند. این ویژگی، rowversion را به ابزاری قدرتمند برای ردیابی تغییرات و کنترل همزمانی تبدیل کرده است.
معرفی @@DBTS
متغیر سراسری @@DBTS یک مقدار عددی را برمیگرداند که نشاندهنده آخرین مقدار rowversion اختصاص یافته در پایگاه داده فعلی است. به عبارت دیگر، این مقدار نشانگر تایماستمپ فعلی پایگاه داده است که به ردیف جدید بعدی یا ردیف بهروزرسانیشده بعدی اختصاص خواهد یافت. این تابع به خصوص زمانی مفید است که بخواهید بالاترین مقدار rowversion در یک پایگاه داده را قبل از یک عملیات خاص بدانید. میتوانید با استفاده از یک دستور SELECT ساده، مقدار @@DBTS را مشاهده کنید:
SELECT @@DBTS;
مقدار بازگشتی توسط @@DBTS یک مقدار باینری است و به طور مداوم افزایش مییابد. اگر مقداری را برای یک ستون rowversion به صورت دستی درج کنید، ممکن است در برخی سناریوها این روند مختل شود، اما معمولاً SQL Server خودش این مقادیر را به ترتیب افزایش میدهد. @@DBTS برای درک وضعیت کلی تغییرات در پایگاه داده مفید است.
معرفی MIN_ACTIVE_ROWVERSION()
در مقابل @@DBTS، تابع MIN_ACTIVE_ROWVERSION() کمترین مقدار rowversion را که در حال حاضر در پایگاه داده فعال است، برمیگرداند. این یعنی کمترین مقدار rowversion که هنوز کامیت نشده (committed) یا برگردانده نشده (rolled back) است. این تابع به طور خاص در سناریوهای مدیریت همزمانی و تراکنشهای بلندمدت اهمیت پیدا میکند. MIN_ACTIVE_ROWVERSION() نشاندهنده شروع “قدیمیترین” تراکنش فعالی است که در حال تغییر دادههای rowversion است. برای مشاهده مقدار این تابع:
SELECT MIN_ACTIVE_ROWVERSION();
کاربرد اصلی MIN_ACTIVE_ROWVERSION() زمانی است که شما نیاز دارید قدیمیترین وضعیت یک پایگاه داده را که هنوز درگیر تراکنشهای فعال است، شناسایی کنید. این امر برای پاکسازی سوابق قدیمی یا مدیریت فضای ذخیرهسازی در پایگاههای دادهای که از ردیابی تغییرات استفاده میکنند، حیاتی است.
تفاوتهای کلیدی و موارد استفاده
تفاوت اصلی بین این دو تابع در “دیدگاه” آنها نسبت به مقادیر rowversion است:
-
@@DBTS: این متغیر تایماستمپ “آینده” یا “بعدی” پایگاه داده را نشان میدهد. به عبارت دیگر، بالاترین مقدارrowversionکه تا کنون در پایگاه داده تخصیص یافته است و مقدار بعدی که برای یک درج یا بهروزرسانی جدید تخصیص خواهد یافت. این یک دیدگاه جهانی و رو به جلو از وضعیت تغییرات در پایگاه داده ارائه میدهد. برای مثال، اگر میخواهید بدانید که بعد از آخرین تغییر، مقدارrowversionبعدی چه خواهد بود،@@DBTSبه کار میآید. -
MIN_ACTIVE_ROWVERSION(): این تابع به “گذشته” نگاه میکند و کمترین مقدارrowversionرا که توسط یک تراکنش فعال در حال استفاده است، نشان میدهد. این به شما کمک میکند تا قدیمیترین نقطهای را که در حال حاضر در یک تراکنش درگیر است، شناسایی کنید. این برای مدیریت تراکنشهای طولانیمدت، عملیات پاکسازی که به تراکنشهای باز وابسته هستند، و سناریوهای بازیابی داده بسیار مهم است.
یک سناریوی رایج برای استفاده از MIN_ACTIVE_ROWVERSION() در پاکسازی دادههای قدیمی (Data Purging) است. اگر یک سیستم آرشیو داده دارید که بر اساس مقادیر rowversion کار میکند، نمیتوانید رکوردهایی را که rowversion آنها کمتر از MIN_ACTIVE_ROWVERSION() است، حذف کنید، زیرا ممکن است هنوز توسط تراکنشهای فعال مورد استفاده قرار گیرند. پاکسازی فقط باید بر روی رکوردهایی انجام شود که rowversion آنها بزرگتر از MIN_ACTIVE_ROWVERSION() است.
به عنوان مثال، فرض کنید یک جدول با ستون rowversion دارید:
CREATE TABLE MyData (
Id INT IDENTITY(1,1) PRIMARY KEY,
Value NVARCHAR(100),
RowVersionCol ROWVERSION
);
اکنون چند ردیف درج میکنیم و مقادیر rowversion را مشاهده میکنیم:
INSERT INTO MyData (Value) VALUES ('Test1');
INSERT INTO MyData (Value) VALUES ('Test2');
SELECT *, CAST(RowVersionCol AS BIGINT) AS RowVersionBigInt FROM MyData;
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
در خروجی، @@DBTS باید بالاتر از بالاترین RowVersionCol باشد، و MIN_ACTIVE_ROWVERSION() احتمالاً صفر یا نزدیک به آن خواهد بود مگر اینکه تراکنشهای فعالی وجود داشته باشد.
حال یک ردیف را بهروزرسانی میکنیم و تأثیر آن را میبینیم:
UPDATE MyData SET Value = 'Updated Test1' WHERE Id = 1;
SELECT *, CAST(RowVersionCol AS BIGINT) AS RowVersionBigInt FROM MyData;
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
با بهروزرسانی، مقدار RowVersionCol برای ردیف با Id = 1 تغییر کرده و @@DBTS نیز افزایش یافته است. MIN_ACTIVE_ROWVERSION() همچنان مقدار پایینترین rowversion در حال استفاده را نشان میدهد.
برای مشاهده تأثیر MIN_ACTIVE_ROWVERSION()، میتوانیم یک تراکنش طولانیمدت را شبیهسازی کنیم:
-- در یک پنجره کوئری جداگانه (Session 1):
BEGIN TRAN;
UPDATE MyData SET Value = 'Still in transaction' WHERE Id = 2;
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
-- اینجا تراکنش باز نگه داشته میشود
-- در یک پنجره کوئری دیگر (Session 2):
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
-- MIN_ACTIVE_ROWVERSION() اکنون باید مقدار RowVersionCol مربوط به Id=2 را نشان دهد.
-- یا مقدار مرتبط با تراکنش باز شده در Session 1
INSERT INTO MyData (Value) VALUES ('New Data After Transaction Starts');
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
-- در Session 1:
ROLLBACK;
-- یا COMMIT;
-- سپس در Session 2:
SELECT @@DBTS, MIN_ACTIVE_ROWVERSION();
-- MIN_ACTIVE_ROWVERSION() باید به حالت اولیه یا مقدار مرتبط با آخرین تراکنش فعال دیگر بازگردد.
این آزمایش نشان میدهد که چگونه MIN_ACTIVE_ROWVERSION() تحت تأثیر تراکنشهای فعال قرار میگیرد و نقش حیاتی آن در نظارت بر وضعیت همزمانی پایگاه داده. درک این دو تابع برای هر توسعهدهنده یا مدیر پایگاه داده SQL Server که با ردیابی تغییرات و مدیریت همزمانی سروکار دارد، ضروری است. انتخاب بین استفاده از @@DBTS و MIN_ACTIVE_ROWVERSION() بستگی به نیاز خاص شما دارد: آیا به بالاترین مقدار تایماستمپ فعلی پایگاه داده نیاز دارید یا به قدیمیترین تایماستمپ فعال در تراکنشها.