هندسة قواعد البيانات
هندسة قواعد البيانات وEloquent
عمل الاستعلامات خلف تطبيق Laravel تجاوز مخططه - إزالة N+1، وفهرسة من خطط استعلام حقيقية، وهجرات لا تقفل جدولًا حيًّا.
كل تطبيق Laravel يصير بطيئًا يصير بطيئًا في قاعدة البيانات تقريبًا، وكل واحد من تلك التطبيقات كان على ما يرام في التطوير تقريبًا. الصفحة التي تنفّذ أحد عشر استعلامًا مقابل أربعين صفًا تنفّذ أحد عشر استعلامًا مقابل أربعة ملايين صف بالطريقة نفسها، وواحدة فقط من الحالتين يمكن النجاة منها.
أين يذهب الوقت فعلًا
عبر التعاقدات التي ننفّذها، تتجمّع الأسباب في قائمة قصيرة.
N+1 لا يظهر إلا في الإنتاج. صفحة القائمة تحمّل علاقتها مسبقًا. وصفحة التفصيل لا تفعل، لأنها لا تحمّل إلا سجلًا واحدًا - ثم يعيد أحدهم استخدام مكوّن التفصيل داخل حلقة. يقفز عدد الاستعلامات من اثنين إلى مئتين ولا شيء في الفرق يبدو خاطئًا.
علاقة تُحمَّل داخل accessor. الدالة getFullAddressAttribute() تلمس
$this->country، ويُستدعى الـ accessor أثناء التسلسل، فيُصدر التطبيق استعلامًا
لكل صف بينما يبدو أنه ينسّق نصًا.
فهرس موجود ولا يُستخدم. عمود ملفوف بدالة، أو تحويل نوع ضمني بين عمود نصي ومعامل عددي، أو محرف بدل في بداية LIKE. الفهرس هناك، وEXPLAIN يقول إنه لا يُقرأ، والجميع يثق بالمخطط بدل خطة الاستعلام.
تجميع يُنفَّذ في PHP. خط معالجة المجموعات معبّر بما يكفي ليقرأ
->get()->groupBy()->map() أفضل مما تقرأ SQL، فتُهيّأ مئة ألف صف في نماذج
لإنتاج ستة أرقام.
هجرة قفلت جدولًا حيًّا. إضافة فهرس، أو إضافة عمود بقيمة افتراضية، أو تغيير نوع عمود، على جدول كبير بما يكفي ليتجاوز القفل مهلة الطلب. نجحت عملية النشر؛ وسقط الموقع.
كيف نعمل
القياس أولًا، من النظام الحقيقي. سجلات الاستعلامات البطيئة، وعدد الاستعلامات لكل نقطة نهاية، وEXPLAIN على الاستعلامات المهمة. لا مُحلِّل على حاسوب محمول مع قاعدة بيانات مزروعة، فذلك يخبرك بثبات عن مشكلة ليست لديك.
إصلاح السبب لا العَرَض. التخزين المؤقت أمام استعلام سيئ وسيلة لدفع ثمن الاستعلام السيئ مرات أقل. أحيانًا يكون ذلك القرار الصحيح وسنقول ذلك؛ وفي الأغلب يريد الاستعلام فهرسًا أو ضمًّا، أو ألا يُصدَر وقت التشغيل أصلًا.
جعل الإصلاح دائمًا. التحميل الكسول معطَّل خارج الإنتاج، حتى لا يعود N+1 الذي أزلته للتو بهدوء. وتأكيد على عدد الاستعلامات في نقاط النهاية المهمة، حتى تُفشل إزالةٌ مستقبلية لتحميل مسبق اختبارًا لا أن تنتج تذكرة دعم. كلاهما بضعة أسطر وهما الفرق بين إصلاح وإصلاح يبقى.
عمل المخطط على نظام لا يستطيع التوقف
أغلب ما يُطلب منا إصلاحه ليس استعلامًا بل هيئة: عمود حالة كان ينبغي أن يكون جدول حالات، وعلاقة متعددة الأشكال جعلت تقييد صفَّين مستحيلًا، وسجل تدقيق ينمو بلا سياسة حفظ، وجدول يؤدي ثلاث وظائف لأن تقسيمه بدا مكلفًا قبل سنتين.
يُنفَّذ ذلك العمل بخطوات كل واحدة منها آمنة:
- أضف البنية الجديدة إلى جانب القديمة، ولا شيء يقرؤها.
- املأ على دفعات، في طابور، بتقدّم ينجو من عملية نشر.
- اكتب في الاثنتين، واقرأ من القديمة، وطابِق حتى يصير الفرق صفرًا.
- حوّل القراءات. انتظر. ثم أوقف الكتابة في القديمة.
- احذفها، في إصدار منفصل، بعد أن يمضي أسبوع دون أن يلمسها شيء.
خطوات أكثر من هجرة واحدة، وهي الفرق بين تغيير مخطط وانقطاع مجدول.
ماذا تتسلّم
وثيقة اكتشافات كل مسألة فيها متتبَّعة إلى الاستعلام أو الهجرة التي تسببها ومقدَّرة بالجهد، والإصلاحات كطلبات دمج قابلة للمراجعة، وتغييرات الفهارس كهجرات آمنة على حجم بياناتك، وتأكيدات التكامل المستمر التي تمنع عودة الانتكاسات.
وحيث يكون الجواب بنيويًا لا إعادة كتابة استعلام، تقول الاكتشافات ذلك وتضع الرقمين جنبًا إلى جنب: كم يكلّف تغييره، وكم يكلّف تركه على مدى السنة القادمة. ينبغي أن تقرأ ذلك في الأسبوع الأول لا أن تسمعه في مكالمة ختامية.
قبل البدء يريد الناس عادةً قراءة أمرين: ما يكلّفه تغيير مخطط يقفل جدولًا في الإنتاج، وأين يختلف MySQL وPostgres فعلًا بالنسبة لتطبيق Laravel. وإن تبيّن أن البطيء هو مسار الطلب لا الاستعلام، فالأداء هو المهمة المجاورة.
