Get a quote

إدارة هجرة قاعدة البيانات في الإنتاج: الأدوات والمشاكل والحلول

هجرة مخطط قاعدة البيانات هي المكان الذي تموت فيه الثقة في الإنتاج. نص هجرة نظيف في بيئة التطوير يمكنه إقفال جدول يحتوي 50 مليون صف لأربع دقائق في الإنتاج.

هجرة مخطط قاعدة البيانات هي المكان الذي تموت فيه الثقة في الإنتاج. نص هجرة نظيف في بيئة التطوير يمكنه إقفال جدول يحتوي 50 مليون صف لأربع دقائق في الإنتاج. عملية تراجع تبدو بسيطة في بيئة الاختبار تصبح غير قابلة للعكس بعد كتابة بيانات الإنتاج في المخطط الجديد.

لماذا تفشل نصوص الهجرة اليدوية عند التوسع؟

أقدم نسخة من إدارة المخطط في معظم المشاريع هي مجلد من ملفات SQL مرقمة: 001_create_users.sql، 002_add_email_index.sql. يقوم المطور بتشغيل الملفات الجديدة يدوياً عند النشر. يعمل هذا حتى:

يقوم مطوران بإنشاء الهجرة 007 بشكل مستقل. يُدمج أحدهما أولاً. يحصل الآخر على تعارض في اسم الملف ويُعاد ترقيمه إلى 008، لكن المحتوى افترض أن 007 ستكون مطبقة بالفعل. قواعد البيانات في بيئات مختلفة لديها الآن مخططات مختلفة.

golang-migrate: المعيار وقيوده

golang-migrate هو أداة الهجرة المعيارية لمشاريع Go. تحتفظ بجدول schema_migrations يتتبع الهجرات المطبقة. تدعم PostgreSQL و MySQL و SQLite وغيرها.

ملفات الهجرة تتبع اصطلاح تسمية:

20260526140000_add_tenant_settings_table.up.sql
20260526140000_add_tenant_settings_table.down.sql

قيود golang-migrate المهمة في الإنتاج:

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

هجرات التراجع (Down) مدعومة نظرياً لكنها غير موثوقة عملياً. في الإنتاج، عكس هجرة قاعدة البيانات إجراء طارئ لا خطوة نشر روتينية.

مشكلة ALTER TABLE على الجداول الكبيرة

ALTER TABLE ... ADD COLUMN على جدول بعشرات الملايين من الصفوف يأخذ قفلاً حصرياً طوال المدة. الحل هو هجرة ثلاث خطوات:

-- الخطوة 1: أضف العمود بدون قيود (فوري)
ALTER TABLE orders ADD COLUMN processing_notes TEXT;

-- الخطوة 2: ملء البيانات بدفعات (بطيء لكن بدون قفل مستمر)
UPDATE orders SET processing_notes = ''
WHERE id IN (SELECT id FROM orders WHERE processing_notes IS NULL LIMIT 10000);

-- الخطوة 3: أضف قيد NOT NULL باستخدام NOT VALID
ALTER TABLE orders ADD CONSTRAINT orders_processing_notes_not_null
    CHECK (processing_notes IS NOT NULL) NOT VALID;
ALTER TABLE orders VALIDATE CONSTRAINT orders_processing_notes_not_null;

خدعة NOT VALID مهمة: تضيف القيد دون التحقق من الصفوف الموجودة (فوري)، ثم VALIDATE CONSTRAINT تتحقق من الصفوف مع الاحتفاظ فقط بقفل SHARE UPDATE EXCLUSIVE الذي لا يمنع عمليات القراءة/الكتابة العادية.

نمط Expand/Contract للتغييرات بدون توقف

لأنظمة SaaS متعددة المستأجرين مع نسخ تطبيق متعددة تعمل في نفس الوقت، تغييرات المخطط يجب أن تكون متوافقة مع الإصدار القديم والجديد في آنٍ واحد.

المرحلة 1 (التوسع): أضف العمود أو الجدول الجديد بجانب القديم. العمود الجديد اختياري. الكود القديم يتجاهله. الكود الجديد يكتب في كليهما.

المرحلة 2 (الهجرة): شغّل مهمة خلفية لملء البيانات من العمود القديم إلى الجديد للصفوف الموجودة.

المرحلة 3 (التقليص): بعد نشر جميع النسخ التي تستخدم العمود الجديد حصرياً، احذف العمود القديم.

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

اعتبارات الأنظمة متعددة المستأجرين

للفرق في لبنان ومنطقة MENA التي تهاجر من أنظمة قديمة (MySQL، MSSQL إلى PostgreSQL) مع نموذج عزل قاعدة بيانات منفصلة لكل مستأجر: تشغيل golang-migrate عبر مئات قواعد البيانات الفردية يتطلب طبقة تنسيق هجرة فوق المكتبة نفسها.

دروس مستخلصة من الإنتاج

لا تعتمد على هجرة التراجع للرجوع للوراء في الإنتاج. عامل هجرة التراجع كتوثيق لما يجب التراجع عنه لا كأداة تراجع آلية.

استخدم CREATE INDEX CONCURRENTLY لجميع إضافات الفهرس على الجداول التي تتلقى حركة إنتاجية.

شغّل الهجرات كخطوة منفصلة عن نشر التطبيق. في بيئة تنسيق الحاويات مثل ECS أو Kubernetes، يؤدي نهج "الهجرة عند بدء التشغيل" إلى سلوك غير قابل للتنبؤ.

هل تحتاج مساعدة؟

Voxire تبني وتحافظ على قواعد بيانات PostgreSQL ومنصات Go في الإنتاج لشركات SaaS في لبنان ومنطقة MENA. إذا كنت تتعامل مع تعقيد الهجرة أو إدارة المخطط على نطاق واسع، يمكننا المساعدة.

https://voxire.com/get-a-quote/

العودة إلى المدونة
Chat on WhatsApp