إضافة هياكل قاعدة بيانات جديدة دون تعطيل التطبيقات العاملة

لديك جدول users يحتوي على عمود full_name. يريد فريق المنتج تقسيم الأسماء إلى first_name و last_name لتحسين التخصيص. تحتاج إلى إجراء هذا التغيير دون إيقاف التطبيق أو كسر الميزات الحالية.

النهج الواضح هو حذف full_name، وإضافة العمودين الجديدين، وتحديث كل الكود دفعة واحدة. لكن هذا يتطلب نشرًا منسقًا، وتوقفًا عن العمل، وخطة تراجع مثالية إذا حدث خطأ ما. في الممارسة العملية، غالبًا ما يؤدي هذا النوع من التغييرات إلى تراجعات في وقت متأخر من الليل ومستخدمين غاضبين.

هناك طريقة أكثر أمانًا: أضف الهيكل الجديد أولاً، دون لمس القديم. دع القديم والجديد يتعايشان حتى تصبح مستعدًا للتحويل الكامل.

مرحلة التوسيع: أضف دون إزالة

يبدأ نمط التوسيع والتقلص (expand-contract) بأكثر خطوة ممكنة أمانًا. تقوم بإضافة أعمدة أو جداول أو قيود جديدة إلى قاعدة البيانات مع ترك كل ما هو موجود بالفعل دون أي تغيير. التطبيقات القديمة التي لا تزال تعمل ضد المخطط القديم لن تلاحظ أي فرق. يمكن للكود الجديد البدء في استخدام الهياكل الجديدة فورًا.

هذه هي الفكرة الأساسية لمرحلة التوسيع: تقوم بإدخال كائنات قاعدة بيانات جديدة دون تعديل أو إزالة الكائنات الموجودة. يظل المخطط القديم يعمل بكامل طاقته. المخطط الجديد هو إضافة، وليس استبدالًا.

يوضح الرسم البياني أدناه حالة جدول المستخدمين قبل وبعد مرحلة التوسيع، وكيف تتفاعل التطبيقات القديمة والجديدة مع المخطط.

flowchart TD subgraph Before[قبل مرحلة التوسيع] T1[جدول users] C1[full_name VARCHAR] end subgraph After[بعد مرحلة التوسيع] T2[جدول users] C2[full_name VARCHAR] C3[first_name VARCHAR NULL] C4[last_name VARCHAR NULL] end OldApp[تطبيق قديم] -->|يقرأ فقط| C2 NewApp[تطبيق جديد] -->|يقرأ/يكتب| C2 NewApp -->|يقرأ/يكتب| C3 NewApp -->|يقرأ/يكتب| C4 Before -->|ALTER TABLE ADD COLUMN| After

مثال عملي

خذ جدول users مع عمود full_name. في مرحلة التوسيع، تقوم بإضافة عمودين جديدين:

إليك كود SQL لإضافة الأعمدة الجديدة:

ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN first_name VARCHAR(100) NULL;
ALTER TABLE users ADD COLUMN last_name VARCHAR(100) NULL;

يبقى عمود full_name كما هو تمامًا. التطبيقات القديمة التي تقرأ full_name تستمر في العمل دون أي تغييرات في الكود. يمكن للتطبيقات الجديدة البدء في الكتابة إلى first_name و last_name مع الاستمرار في قراءة full_name للتوافق مع الإصدارات السابقة.

لا توقف عن العمل. لا نشر منسق. لا خطر من كسر الاستعلامات الحالية.

القاعدة الحاسمة: الأعمدة الجديدة يجب أن تكون اختيارية

الخطأ الأكثر شيوعًا في مرحلة التوسيع هو إضافة عمود جديد مع NOT NULL وبدون قيمة افتراضية. هذا يكسر فورًا أي تطبيق يقوم بإدراج صفوف دون تحديد العمود الجديد. التطبيقات القديمة التي لا تعلم بوجود العمود ستفشل في كل عملية إدراج.

القاعدة بسيطة: كل عمود جديد يجب أن يكون قابلاً للقيم الخالية (nullable) أو أن يكون له قيمة افتراضية مناسبة. إذا كنت بحاجة إلى قيد NOT NULL، أضف العمود كقابل للقيم الخالية أولاً، وقم بملء البيانات بأثر رجعي، ثم أضف القيد في مرحلة لاحقة. لا تجبر جميع التطبيقات الحالية على تغيير عبارات الإدراج الخاصة بها في نفس الوقت.

ينطبق نفس المنطق على الجداول الجديدة. الجدول الجديد لا يغير أي هيكل موجود. التطبيقات القديمة لا تحتاج أبدًا إلى معرفة بوجوده. يمكن للتطبيقات الجديدة البدء في الكتابة إليه فورًا. لا يوجد تعارض لأنه لم يتغير شيء في الجداول التي يستخدمونها بالفعل.

التعامل مع القيود بأمان

تحتاج القيود إلى عناية إضافية أثناء مرحلة التوسيع. إذا قمت بإضافة قيد UNIQUE على عمود جديد، تأكد من أن البيانات الحالية لا تنتهكه. إذا قمت بإضافة FOREIGN KEY، تأكد من أن جميع الصفوف الحالية تشير إلى صفوف أصل صالحة.

بالنسبة لقيود CHECK، تحقق من أن الشرط لا يتعارض مع البيانات الحالية. بعض قواعد البيانات تدعم خيار NOT VALID الذي يطبق القيد فقط على الصفوف الجديدة، مما يتيح لك التحقق من صحة البيانات الحالية بشكل منفصل لاحقًا. هذا مفيد عندما تكون غير متأكد من جودة البيانات في الصفوف القديمة.

المبدأ هو نفسه: لا تقدم قيدًا سيفشل مقابل البيانات الحالية. إذا لم تتمكن من ضمان ذلك، قم بتأجيل القيد أو أضفه بطريقة لا تمنع عمليات الكتابة.

أهمية التسمية

تحتاج الأعمدة والجداول الجديدة إلى أسماء واضحة تميزها عن الهيكل القديم. تجنب أسماء مثل name_new أو temp_name أو name_v2. هذه تخلق ارتباكًا أثناء مرحلة التقلص عندما تحتاج إلى معرفة أي هيكل هو الأساسي.

استخدم أسماء تصف البيانات الفعلية. first_name و last_name أفضل من name_split_1 و name_split_2. الأسماء الجيدة تجعل عملية الانتقال أسهل لكل من يعمل مع المخطط لاحقًا.

ما لا تتطلبه مرحلة التوسيع

لا تتطلب مرحلة التوسيع أي تغييرات في الكود في التطبيقات القديمة. تستمر في استخدام نفس المخطط، ونفس الاستعلامات، ونفس المنطق. هذا ما يجعل مرحلة التوسيع آمنة للتنفيذ في أي وقت، حتى خلال ساعات الذروة الإنتاجية.

لا توقف عن العمل. لا إعادة تشغيل للتطبيقات. لا استعلامات تفشل فجأة لأن عمودًا اختفى. التغيير الوحيد هو في مخطط قاعدة البيانات، وهذا التغيير هو إضافة بحتة.

متى تكتمل مرحلة التوسيع

تنتهي مرحلة التوسيع عندما تكون الهياكل الجديدة موجودة في قاعدة البيانات وجاهزة للاستخدام. التطبيقات القديمة لا تزال تستخدم الهياكل القديمة. يمكن للتطبيقات الجديدة البدء في استخدام الهياكل الجديدة. كلا المسارين يعملان في وقت واحد.

في هذه المرحلة، لديك قاعدة بيانات تدعم نسختين من المخطط. هذا هو الأساس للخطوة التالية: ترحيل التطبيقات تدريجيًا لاستخدام الهياكل الجديدة دون كسر أي شيء.

قائمة التحقق العملية لمرحلة التوسيع

  • الأعمدة الجديدة قابلة للقيم الخالية أو لها قيمة افتراضية
  • الجداول الجديدة لا تعدل هياكل الجداول الموجودة
  • القيود الجديدة لا تتعارض مع البيانات الحالية
  • الأسماء تميز بوضوح الهياكل الجديدة عن القديمة
  • التطبيقات القديمة تستمر في العمل دون تغييرات في الكود
  • يمكن للتطبيقات الجديدة البدء في استخدام الهياكل الجديدة فورًا

الخلاصة

مرحلة التوسيع هي أكثر تغيير آمن في قاعدة البيانات يمكنك القيام به لأنه يضيف فقط. لا إزالة، لا تعديل، لا خطر من كسر التطبيقات العاملة. أضف الأعمدة الجديدة كقابلة للقيم الخالية، واترك الأعمدة القديمة كما هي، ودع كلا المخططين يتعايشان. هذا يمنحك الحرية في ترحيل التطبيقات بالسرعة التي تناسبك، دون الحاجة إلى تنسيق إصدار شامل أو جدولة توقف عن العمل.