تغيير مخططات قاعدة البيانات دون تعطيل الإنتاج
لديك قاعدة بيانات تعمل منذ خمس أو عشر أو خمس عشرة سنة. تحتوي على ملايين المعاملات، وآلاف الجداول، ومئات الإجراءات المخزنة التي كتبها أشخاص ربما لم يعودوا يعملون في الشركة. في كل مرة يحتاج فيها أحدهم إلى إضافة عمود، أو تغيير نوع بيانات، أو إصلاح فهرس، يظهر السؤال نفسه: "إذا فشل هذا الترحيل، كم من الوقت سيستغرق الاسترداد؟"
في مؤسسات كهذه، قاعدة البيانات ليست مجرد مكان لتخزين البيانات. إنها القلب التشغيلي للأعمال. إذا توقف التطبيق، يمكن للمستخدمين الانتظار. إذا تلفت قاعدة البيانات، يمكن فقدان البيانات بشكل دائم. لهذا السبب، غالبًا ما تُعامل تغييرات المخطط والبيانات على أنها أنشطة عالية المخاطر، تُجدول ليلة السبت الساعة 2 صباحًا، على أمل ألا يلاحظ أحد شيئًا حتى صباح الاثنين.
هذا النهج لا يتوسع. كلما أراد الفريق تسليم الميزات بشكل أسرع، زادت الحاجة إلى تغييرات قاعدة البيانات. إذا كان على كل تغيير انتظار نافذة صيانة أسبوعية، يشعر فريق المنتج بالإحباط. ولكن إذا تم إجراء التغييرات بإهمال، يصبح خطر تلف البيانات حقيقيًا.
السؤال الحقيقي ليس "ما هي أفضل أداة ترحيل؟" بل: "كيف تغير مخطط قاعدة بيانات دون إيقاف الخدمة، وكيف تعود للخلف إذا حدث خطأ ما؟"
الترحيل الآمن يبدأ بخطوات صغيرة
المبدأ الأساسي بسيط: يجب أن يكون كل تغيير ممكنًا دون قطع الاتصال بالتطبيقات قيد التشغيل، ويجب أن يكون قابلاً للعكس دون فقدان البيانات. هذا يعني أن تغييرات المخطط تحتاج إلى أن تحدث في عدة خطوات صغيرة، وليس قفزة واحدة كبيرة.
خذ مثال إضافة عمود جديد. في قاعدة بيانات قديمة، تضيف العمود بقيمة افتراضية أو تجعله قابلًا للقيم الخالية. لا تقم بإضافة قيود صارمة فورًا. تستمر نسخ التطبيق القديمة في العمل لأنها لا تقرأ العمود الجديد. تبدأ نسخ التطبيق الجديدة في الكتابة إليه. بعد تحديث جميع النسخ وتشغيلها بثبات، تقوم بإضافة قيود مثل NOT NULL أو المفاتيح الخارجية في ترحيل منفصل. إذا حدث خطأ ما في منتصف الطريق، يكون التراجع بسيطًا مثل تجاهل العمود الجديد. لا حاجة لحذف الجداول أو الاستعادة من النسخ الاحتياطية.
يوضح مخطط التسلسل التالي العملية الآمنة خطوة بخطوة الموصوفة أعلاه:
ينطبق نفس النمط على تغيير نوع البيانات. افترض أن عمود price هو حاليًا INTEGER ولكن يجب أن يصبح DECIMAL. النهج الآمن: أضف عمودًا جديدًا باسم price_decimal، واملأه بالقيم المحولة من العمود القديم، ودع التطبيق يقرأ من العمود الجديد مع الاستمرار في الكتابة إلى كليهما، ثم احذف العمود القديم بمجرد أن يصبح كل شيء مستقرًا. التراجع يعني أن التطبيق يقرأ من العمود القديم مرة أخرى، والذي لا يزال موجودًا.
يوضح مثال SQL التالي نصوص الترحيل الأمامي والتراجع لإضافة عمود بأمان:
-- الترحيل الأمامي 1: إضافة عمود كقابل للقيم الخالية
ALTER TABLE products ADD COLUMN discount_rate DECIMAL(5,2) NULL;
-- ملء البيانات بأثر رجعي (تشغيل بعد كتابة التطبيق للعمود الجديد)
UPDATE products SET discount_rate = 0.00 WHERE discount_rate IS NULL;
-- الترحيل الأمامي 2: إضافة قيد NOT NULL
ALTER TABLE products ALTER COLUMN discount_rate SET NOT NULL;
-- نص التراجع (يعكس كلا الخطوتين)
ALTER TABLE products ALTER COLUMN discount_rate DROP NOT NULL;
ALTER TABLE products DROP COLUMN discount_rate;
التغييرات المعقدة تحتاج إلى تشغيل متوازي
للتغييرات الأكثر تعقيدًا مثل تقسيم جدول واحد إلى جدولين أو دمج عدة جداول، تُستخدم تقنية تسمى التشغيل المتوازي. يكتب التطبيق إلى كل من الهياكل القديمة والجديدة في وقت واحد، بينما يتم تحويل استعلامات القراءة تدريجيًا. يمكن للفريق مقارنة النتائج من كلا الهيكلين لضمان عدم وجود اختلافات في البيانات. إذا ظهرت حالة شاذة، يمكن للتطبيق العودة إلى الهيكل القديم دون فقدان البيانات.
يتطلب هذا النهج برمجة دقيقة من جانب التطبيق. يجب أن يكون التطبيق على دراية بكلا الهيكلين وأن يتعامل مع الكتابة إلى كليهما. كما يحتاج إلى منطق لتحديد أي هيكل سيقرأ منه. هذا ليس تافهًا، لكنه أكثر أمانًا بكثير من محاولة ترحيل شامل واحد إما أن يعمل بشكل مثالي أو يتسبب في حادث كبير.
الترحيل يتعلق بالبيانات، وليس فقط المخطط
من الأخطاء الشائعة معاملة ترحيل قاعدة البيانات على أنه مجرد عملية مخطط. البيانات الموجودة بالفعل يجب أن تظل متسقة بعد الترحيل. كل ترحيل يحتاج إلى نصين: نص أمامي ونص تراجع. نص التراجع ليس مجرد عكس النص الأمامي. يجب أن يعيد البيانات إلى نفس الحالة تمامًا كما كانت قبل الترحيل، بما في ذلك أي بيانات قد تكون تم تعديلها بواسطة التطبيق أثناء عملية الترحيل.
على سبيل المثال، إذا قام ترحيل بإعادة تسمية عمود وتحويل قيمه، يجب أن يعكس نص التراجع كلاً من اسم العمود وتحويل القيمة. إذا كتب التطبيق بيانات جديدة إلى العمود المعاد تسميته خلال نافذة الترحيل، يجب أن يتعامل نص التراجع مع تلك البيانات بشكل صحيح، وليس مجرد إسقاطها.
مكان الترحيل في خط الأنابيب
في خط أنابيب CI/CD، يجب أن يكون ترحيل قاعدة البيانات مرحلة منفصلة تعمل بشكل مستقل عن نشر التطبيق. يجب ألا يقوم خط الأنابيب بتشغيل الترحيل في نفس وقت نشر الكود الجديد. بدلاً من ذلك، يتم تشغيل الترحيل أولاً. بعد تأكيد نجاح الترحيل، يتم نشر إصدار التطبيق الجديد. إذا فشل الترحيل، يتوقف خط الأنابيب ويتم إخطار الفريق قبل أن يتأثر التطبيق.
هذا الفصل أمر بالغ الأهمية. إذا حدث الترحيل والنشر معًا وحدث خطأ ما، فمن الصعب معرفة ما إذا كانت المشكلة ناتجة عن تغيير المخطط أو الكود الجديد. تشغيلهما بالتسلسل يعطي ملكية واضحة لكل فشل.
متى تتطلب موافقة يدوية
عادةً ما تتبنى المؤسسات التي تعمل منذ فترة طويلة قاعدة بسيطة: الترحيلات التي تغير البيانات (وليس فقط المخطط) تتطلب موافقة يدوية. الترحيلات التي تخص المخطط فقط والتي تكون إضافية، مثل إضافة عمود قابل للقيم الخالية، يمكن تشغيلها تلقائيًا. هذا ليس لأن الأتمتة غير موثوقة. بل لأن تغييرات البيانات لها عواقب يصعب التنبؤ بها مقارنة بالتغييرات الهيكلية.
العمود الجديد القابل للقيم الخالية لن يكسر أي شيء. لكن الترحيل الذي يقوم بتحديث ملايين الصفوف، أو تحويل القيم، أو دمج الجداول، يمكن أن يقدم أخطاء دقيقة لا تظهر إلا في ظل ظروف بيانات محددة. المراجعة البشرية قبل مثل هذه الترحيلات هي شبكة أمان، وليست عنق زجاجة.
قائمة تحقق عملية لترحيلات قاعدة البيانات الآمنة
- أضف الأعمدة كقابلة للقيم الخالية أو بقيم افتراضية أولاً، ثم أضف القيود لاحقًا.
- غير أنواع البيانات بإضافة عمود جديد، وملئه، وتحويل القراءات تدريجيًا.
- لإعادة الهيكلة المعقدة، قم بتشغيل الهياكل القديمة والجديدة بالتوازي وقارن النتائج.
- اكتب دائمًا نص تراجع يعيد البيانات إلى حالتها الدقيقة قبل الترحيل.
- قم بتشغيل الترحيلات قبل نشر التطبيق، وليس في نفس الوقت.
- اطلب موافقة يدوية للترحيلات التي تغير البيانات، واسمح للترحيلات الإضافية للمخطط بالتشغيل تلقائيًا.
الخلاصة
لا يجب أن تكون ترحيلات قاعدة البيانات مرعبة. المفتاح هو تقسيم كل تغيير إلى خطوات صغيرة قابلة للعكس. أضف قبل أن تزيل. قم بتشغيل القديم والجديد جنبًا إلى جنب قبل التحويل. ودائمًا امتلك طريقًا للعودة لا يعتمد على الاستعادة من نسخة احتياطية. عندما تعامل كل ترحيل كسلسلة من الخطوات الآمنة القابلة للاختبار، تزيل الخوف وتجعل تغييرات قاعدة البيانات جزءًا طبيعيًا من عملية التسليم الخاصة بك.