مقایسه توابع 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()
بستگی به نیاز خاص شما دارد: آیا به بالاترین مقدار تایماستمپ فعلی پایگاه داده نیاز دارید یا به قدیمیترین تایماستمپ فعال در تراکنشها.