Laravel يشحن SQLite افتراضيًا. متى يكون ذلك مناسبًا فعلًا؟
تغيّر الافتراض وذهبت تطبيقات كثيرة إلى الإنتاج عليه دون أن يقرر ذلك أحد. والحالات التي يكون فيها صحيحًا حقيقية وأضيق مما يوحي به الافتراض.
قاعدة البيانات الافتراضية في Laravel هي SQLite، والافتراضات قوية. وعدد معتبر من التطبيقات يصل اليوم إلى الإنتاج عليها لأن أحدًا لم يغيّر السطر، لا لأن أحدًا قرر أنها مناسبة.
أحيانًا تكون مناسبة. وهنا يقع الخط فعلًا.
ما الذي يختلف حقًا
ليس SQL. ولا Eloquent، الذي يتصرف كما هو. شيء واحد: SQLite ملف يفتحه عمليتك، لا خادم تتصل به عمليتك.
وكل شيء يتبع من ذلك. لا يوجد حد اتصالات لأنه لا توجد اتصالات. ولا يوجد زمن استجابة شبكة لأنه لا توجد شبكة. والكتابات مسلسلة عبر كل عملية تلمس الملف، لأن الملف لا يملك مخطِّطًا يحكم بين العملاء.
فعّل WAL قبل أي شيء آخر. من دونه يحجب القارئ الكاتبَ ويحجب الكاتب القرّاء، وهي الإعداد الذي يقيسه أغلب الناس دون أن يعلموا:
// هجرة، أو مزوّد خدمة
DB::statement('PRAGMA journal_mode = WAL');
DB::statement('PRAGMA busy_timeout = 5000');
DB::statement('PRAGMA foreign_keys = ON');هذه الثلاثة شبه إلزامية. WAL يتيح للقرّاء المضيّ أثناء الكتابة. ومهلة الانشغال
تحوّل خطأ database is locked الفوري إلى انتظار قصير، وهو ما أردته دائمًا
تقريبًا. والمفاتيح الأجنبية مطفأة افتراضيًا في SQLite، وهو ما يفاجئ من كتب
constrained() في هجرة وافترض أنها تُفرض.
أين تكون الجواب الصحيح
أداة داخلية. عشرون شخصًا، أغلبهم يقرأ. والتوفير التشغيلي حقيقي: لا خادم قاعدة بيانات تُرقّعه أو تنسخه احتياطيًا أو تؤمّنه أو تدفع ثمنه، والنسخة الاحتياطية نسخ ملف.
تطبيق على خادم واحد بكتابات معتدلة. موقع محتوى، أو صفحة حجز، أو SaaS صغير في سنته الأولى. وSQLite على قرص محلي أسرع من Postgres عبر شبكة لقارئ واحد، لأنها لا تعبر مقبسًا.
الاختبارات. قاعدة SQLite في الذاكرة تجعل المجموعة سريعة، مع التحفظ أدناه.
أي شيء مدمج أو منشور على الحافة، حيث لا يتوفر خادم قاعدة بيانات أصلًا.
وأين لا تكون
عدة خوادم تطبيق. هذا هو الحد الصارم. لا يستطيع خادما ويب مشاركة ملف SQLite بأمان عبر نظام ملفات شبكي. وإن كنت ستتوسع أفقيًا يومًا، فهذا القرار يجب اتخاذه مرة أخرى، واتخاذه لاحقًا ترحيلٌ تحت ضغط الوقت.
العمل كثيف الكتابة. كل ما يسجّل كل طلب، أو يستقبل أحداثًا، أو يعالج طابورًا في قاعدة البيانات. الكتابات تتسلسل؛ ذلك هو التصميم لا مشكلة ضبط.
أكثر من عامل طوابير أو اثنين. العمّال الذين يستطلعون جدول مهام كتّاب متزامنون. استخدم Redis للطابور وSQLite للتطبيق، أو شغّل عاملًا واحدًا واقبل الإنتاجية.
أي شيء يحتاج استرجاعًا إلى نقطة زمنية، أو نسخًا متماثلًا، أو نسخة قراءة. توجد أدوات تضيف النسخ المتماثل فوق SQLite، وهي اعتمادية وقرار لا افتراض.
فخ الاختبارات
قرار SQLite الأشيع في شيفرة Laravel ليس قرار الإنتاج. بل :memory: في
phpunit.xml، مختارًا للسرعة، مقابل تطبيق يشغّل MySQL أو Postgres.
تلك المجموعة لا تستطيع التقاط:
- مخالفة قيد يفرضها المحرك الحقيقي ولا تفرضها SQLite.
- فرق ترتيب، وهو فخ حساسية الأحرف بقبعة أخرى.
- هجرة تقفل جدولًا كبيرًا، لأنه لا قفل ولا جدول.
- أي شيء يستخدم عامل JSON أو دالة نافذة أو نوعًا يملكه المحرك الحقيقي ولا تملكه SQLite.
إنها مقايضة معقولة لمجموعة تغلب عليها اختبارات الوحدة ورديئة كشيء وحيد يقف بينك وبين خطأ مخطط. شغّل المجموعة السريعة على SQLite إن شئت؛ وشغّل المجموعة التي تبيح النشر مقابل المحرك الذي تنشر عليه.
القرار بصدق
اسأل سؤالًا واحدًا: هل سيعمل هذا التطبيق يومًا على أكثر من خادم؟
إن كانت الإجابة لا وتعرف لماذا هي لا - هو داخلي، وله سقف، وهو صغير فعلًا - فليست SQLite تنازلًا. بل بنية تحتية أقل تملكها، وامتلاك بنية تحتية أقل فائدة حقيقية تُرفض بسهولة أكثر مما تستحق.
وإن كانت الإجابة نعم، أو "غالبًا لا لكن من يدري"، فابدأ على المحرك الذي ستنتهي عليه. ترحيل تطبيق حي عملٌ تتجنبه كليًا بإنفاق عشر دقائق على هذا في الأسبوع الأول - وهي الحجة نفسها التي في المال والتواريخ، وتصمد للسبب نفسه.
