مشکل رایج در Replication SQL Server: ستون های پیش فرض در Replication
در دنیای پیچیده SQL Server Replication، به ویژه در نوع Transactional Replication، موقعیتهایی پیش میآیند که رفتار سیستم با انتظارات ما متفاوت است. یکی از این موارد چالشبراننگیز، نحوه مدیریت ستونهایی است که با مقادیر پیشفرض (DEFAULT constraints) تعریف شدهاند. این مقاله به بررسی دقیق چگونگی رفتار ستون های پیش فرض در Replication و دامهای رایجی که ممکن است با آنها روبرو شوید، میپردازد.
نحوه عملکرد Replication با مقادیر پیشفرض
بهطور پیشفرض، Transactional Replication مقادیر واقعی ستونها را کپی میکند، نه تعریف محدودیت پیشفرض آنها را. هنگامی که یک دستور `INSERT` در ناشر (Publisher) اجرا میشود و یک ستون با مقدار پیشفرض نادیده گرفته شده است، ناشر ابتدا مقدار پیشفرض را اعمال کرده و سپس همان مقدار نهایی به مشترک (Subscriber) Replication میشود.
برای مثال، اگر شما یک جدول به نام `MyTable` با ستونی به نام `CREATE_DATE` و یک مقدار پیشفرض `GETDATE()` داشته باشید:
CREATE TABLE MyTable (
ID INT PRIMARY KEY,
Value NVARCHAR(100),
CREATE_DATE DATETIME DEFAULT GETDATE()
);
این کد یک جدول با سه ستون `ID`، `Value` و `CREATE_DATE` ایجاد میکند. ستون `CREATE_DATE` یک مقدار پیشفرض `GETDATE()` دارد که به این معنی است که اگر هنگام درج داده، مقداری برای این ستون مشخص نشود، تاریخ و زمان جاری به طور خودکار ثبت خواهد شد.
وقتی شما دادهای را به این صورت درج میکنید:
INSERT INTO MyTable (ID, Value) VALUES (1, 'Test');
در این حالت، ما برای ستون `CREATE_DATE` مقداری را مشخص نکردهایم. ناشر (Publisher) مقدار `GETDATE()` را محاسبه کرده و همان مقدار مشخص `DATETIME` را به مشترک (Subscriber) ارسال میکند. مشترک دقیقا همان مقدار صریح را برای `CREATE_DATE` دریافت خواهد کرد، نه اینکه خودش `GETDATE()` را اجرا کند.
مشکل اصلی: تغییرات شماتیک و مقادیر پیشفرض مشترک
مشکل زمانی بروز میکند که شمای (Schema) جدول را در ناشر تغییر میدهید، بدون اینکه آن را به درستی با مشترک همگامسازی کنید، یا زمانی که قصد دارید مشترک از منطق پیشفرض خود استفاده کند.
سناریویی را در نظر بگیرید که یک ستون جدید با یک محدودیت `DEFAULT` به یک جدول replicated اضافه میکنید:
ALTER TABLE MyTable ADD NewColumn INT DEFAULT 0;
این دستور یک ستون جدید به نام `NewColumn` از نوع `INT` به جدول `MyTable` اضافه میکند و مقدار پیشفرض آن را `0` تعیین میکند.
اگر این تغییر شماتیک Replication نشود (برای مثال، شما آن را به صورت دستی در مشترک اضافه کنید یا تنظیمات Replication از Replication DDL جلوگیری کند)، و سپس شما دادهای را درج کنید که ستون `NewColumn` را در ناشر مشخص نکرده باشد، ناشر از مقدار `0` استفاده خواهد کرد. این `0` سپس به مشترک Replication میشود. اگر مشترک نیز `NewColumn` را با `DEFAULT 0` داشته باشد اما شما انتظار رفتار متفاوتی داشته باشید (مثلاً یک مقدار پیشفرض متفاوت یا مدیریت `NULL`ها)، ممکن است ناهماهنگیهایی مشاهده کنید.
یک مشکل رایجتر این است: اگر ستون جدید در ناشر اضافه شود، اما هنوز در مشترک نباشد، دستورات `INSERT` بعدی در ناشر که این ستون را نادیده میگیرند، در مشترک با خطا مواجه خواهند شد.
راه حلها و بهترین شیوهها برای مدیریت مقادیر پیشفرض در Replication
برای جلوگیری از مشکلات فوق در SQL Server Replication، رعایت بهترین شیوهها و استفاده از راه حلهای مناسب ضروری است:
1. **Replication DDL را فعال کنید:**
سادهترین راه حل، فعالسازی Replication DDL است. این کار تضمین میکند که تغییرات شماتیک (از جمله اضافه کردن ستونها با مقادیر پیشفرض) به طور خودکار در مشترکین اعمال میشوند.
EXEC sp_addarticle @publication = 'MyPublication',
@article = 'MyTable',
@source_owner = 'dbo',
@source_object = 'MyTable',
@destination_table = 'MyTable',
@type = 'logbased',
@schema_option = 0x0000000000000001; -- Example: To include DDL
این فرمان `sp_addarticle` یک Article (مقالهی Replication) را به یک Publication اضافه میکند. پارامتر `@schema_option` نقش حیاتی در تعیین اینکه چه ویژگیهایی از شمای جدول باید Replication شوند، دارد. در اینجا، `0x0000000000000001` مثالی از یک گزینه است که به معنای Replication DDL میتواند باشد. **توجه:** انتخاب `schema_option` باید با دقت برای Replication DDL انجام شود. اغلب، برای محیطهای حیاتی، بهتر است تغییرات DDL به صورت صریح مدیریت شوند یا از ویژگیهایی مانند `ALTER TABLE…ADD WITH VALUES` استفاده شود.
2. **مقادیر را به صورت صریح مشخص کنید:**
همیشه تمام ستونها را در دستورات `INSERT` و `UPDATE` خود لحاظ کنید، حتی آنهایی که دارای مقادیر پیشفرض هستند، اگر میخواهید رفتاری قابل پیشبینی داشته باشید.
INSERT INTO MyTable (ID, Value, CREATE_DATE) VALUES (2, 'Another Test', GETDATE());
این کار تضمین میکند که مقدار دقیق مورد نظر شما منتقل میشود.
3. **از `NOT FOR REPLICATION` استفاده کنید:**
برای ستونهای `IDENTITY` یا محدودیتهای خاصی که فقط باید در سطح ناشر یا مشترک اعمال شوند، از `NOT FOR REPLICATION` استفاده کنید. این گزینه معمولاً بیشتر برای مدیریت محدودههای `IDENTITY` کاربرد دارد، اما مفهوم آن برای درک اینکه برخی ویژگیها را میتوان حذف کرد مفید است. محدودیتهای پیشفرض (`DEFAULT constraints`) را **نمیتوان** `NOT FOR REPLICATION` علامتگذاری کرد.
4. **همگامسازی دقیق شماتیک:**
اگر از Replication DDL استفاده نمیکنید، تغییرات شماتیک را در سراسر ناشر و تمام مشترکین با دقت و وسواس مدیریت کنید. این کار اغلب شامل اسکریپت کردن تغییرات و اعمال دستی یا از طریق ابزارهای استقرار خودکار است.
نتیجهگیری
درک نحوه مدیریت محدودیتهای پیشفرض در Replication SQL Server برای حفظ یکپارچگی دادهها و جلوگیری از رفتارهای غیرمنتظره بسیار مهم است. در حالی که Transactional Replication مقادیر صریح را ارسال میکند، تغییرات شماتیک شامل ستونهای جدید با مقادیر پیشفرض نیازمند مدیریت دقیق هستند، که ایدهآلترین راه آن از طریق Replication DDL یا همگامسازی دستی و وسواسگونه است. با رعایت این نکات، میتوانید از پایداری و صحت سیستمهای Replicated خود اطمینان حاصل کنید.