فخ الـ JOIN في Firestore
تواجه مشكلة شائعة في Firestore. تظهر لك وظيفة Firebase خطأً في الحد الأقصى لحجم الدفعة (maximum batch size error). تحتاج إلى ربط الطلبات (orders) والعملاء (customers) من أجل لوحة تحكم. عادةً ما تقوم بتكرار البيانات لإصلاح ذلك، ولكن الآن أصبحت بياناتك قديمة وغير متسقة.
أعلنت Google عن Pipelines API لحل هذه المشكلة. فهي تتيح عمليات JOIN عبر المجموعات (collections) دون تكرار البيانات. أبلغ بعض المطورين عن أوقات استعلام سريعة في الاختبارات الصغيرة.
قضيت أسبوعاً في اختبار هذه الـ API تحت ضغط عالٍ. إليك ما لا تخبرك به الوثائق التقنية.
تكاليف عالية كل عملية تنفيذ لـ pipeline تقرأ من جميع المجموعات المعنية. عملية JOIN بين مجموعتين تفرض عليك رسوماً مقابل عمليات القراءة في كلتيهما. إذا قمت بعمل JOIN بين مجموعتين تحتوي كل منهما على 50,000 مستند، فستتوسع تكاليفك بشكل سيئ. إنها ليست تكلفة خطية بسيطة.
حدود الأداء في اختباراتي، استغرق الـ pipeline مقابل 10,000 مستند 380 مللي ثانية. وعندما اختبرت 100,000 مستند، انتهت مهلة الاستعلام (timed out) عند 30 ثانية. أنت لا تحل المشكلة، بل تقوم فقط بتحويل خطأ الدفعة (batch error) إلى خطأ انتهاء مهلة (timeout error).
مشكلات البداية الباردة (Cold Start) تنشئ الـ Pipelines سياق تنفيذ منفصلاً. في البيئات عديمة الخادم (serverless) مثل Cloud Functions، يضيف هذا تأخيراً يتراوح بين 2 إلى 4 ثوانٍ. سيظن مستخدموك أن تطبيقك بطيء.
تُعد Pipelines API أداة للنماذج الأولية أو للمجموعات الصغيرة التي تقل عن 5,000 مستند. إنها ليست بديلاً لقاعدة بيانات علاقية (relational database). توفرها Google لمساعدتك على البقاء ضمن نظام Firebase البيئي بدلاً من الانتقال إلى PostgreSQL أو Spanner.
إذا كنت تستخدم Pipelines، فاتبع هذه القواعد:
• راجع حجم مجموعتك. إذا تجاوزت المجموعة 20,000 مستند، فاحسب تكلفة الـ JOIN أولاً. • حد من التعقيد. عملية JOIN عبر ثلاث مجموعات أو أكثر هي علامة سيئة. • تتبع تكاليف القراءة أسبوعياً. تظهر قراءات الـ Pipeline بشكل مختلف في فاتورتك. • احتفظ ببياناتك غير الطبيعية (denormalized data). استخدم Pipelines كمكمل، وليس كبديل كامل. • اختبر مع حركة مرور حقيقية. المعايير المرجعية (Benchmarks) على المجموعات الهادئة لا تعكس واقع الإنتاج.
لا تستخدم حلاً مؤقتاً لتجنب اتخاذ قرار معماري حقيقي.
كيف تتعامل مع العلاقات في Firestore؟ هل تستخدم الـ denormalization أم عمليات الربط من جانب العميل (client-side joins)؟ أخبرني في التعليقات.
