تتمثل المشكلة في أدوات ORM ليس في وجودها.
تبدأ المشكلة عندما يعامل الفريق ORM كطبقة تجريد قاعدة بيانات بدلاً من أن تكون مولد استعلامات لا يزال يحتاج إلى الفهم والقياس وأحيانًا التجاوز.
تلك التفرقة مهمة.
## ما الذي تتمتع به أدوات ORM في الواقع
تتميز أدوات ORM بـ:
- مسارات CRUD القياسية
- نمذجة المخطط
- الترقيات
- تقليل الأكواد المتكررة للتعيين
وعادة ما تكون سيئة في إخفاء نموذج التكلفة لقواعد البيانات العلائقية.
إذا لم ينظر الفريق أبدًا إلى SQL، تصبح ORM مولدًا للتاخر مع إكمال تلقائي جيد.
## وضع الفشل الذي يراه الجميع في النهاية
المثال الكلاسيكي هو مشكلة الاستعلام N+1:
```ts
const users = await db.user.findMany({ take: 50 });
for (const user of users) {
console.log(user.invoices[0]?.status);
}
على مستوى التطبيق، يبدو هذا غير ضار.
على مستوى قاعدة البيانات، يعني ذلك غالبًا:
- استعلام واحد لجلب المستخدمين
- خمسون استعلامًا إضافيًا لجلب السجلات ذات الصلة
هذا ليس خطأ في ORM. إنه نتيجة الوصول إلى العلاقات التي تخفي حدود الاستعلام.
التحميل المتعجل ليس حلاً عالمياً
رد الفعل المعتاد هو تحميل كل شيء مقدماً:
const users = await db.user.findMany({
include: {
invoices: true,
},
take: 50,
});
يقلل ذلك من جولات الشبكة، ولكنه يمكن أن يخلق مشكلة مختلفة:
- مجموعات نتائج أكبر بكثير
- بيانات مكررة عبر الانضمامات
- تكلفة باهظة لإعادة البناء في الذاكرة
لذا الدرس الحقيقي ليس "تحميل كل شيء دائمًا". إنه "فهم خطة الاستعلام التي طلبتها للتو".
عندما تفوز SQL الخام أو مولد الاستعلامات
بمجرد أن يصبح الاستعلام:
- كثيف التجميع
- كثيف الانضمامات
- حساس للمتأخرات
- شبيه بالتقارير
ترغب عادة في تشكيله بشكل صريح.
يعد مولد الاستعلامات المطبوع عادةً خيارًا جيدًا:
const rows = await db
.selectFrom("users as u")
.leftJoin("orders as o", "o.user_id", "u.id")
.select(({ fn }) => [
"u.id",
"u.email",
fn.coalesce(fn.sum("o.total"), 0).as("lifetime_value"),
])
.groupBy(["u.id", "u.email"])
.execute();
القيمة هنا ليست أن SQL متفوق أخلاقياً. بل أنك مجبر على التفكير في شكل الاستعلام.
القاعدة العملية
استخدم ORM حيثما يساعد.
تراجع عندما تستحق الاستعلامات اهتماماً من الدرجة الأولى.
تقوم الفرق الجيدة بفعل كلا الأمرين:
- ORM للوصول الروتيني إلى البيانات
- SQL صريح للمسارات الحرجة
- تسجيل الاستعلامات وفحص الخطط لأي شيء يواجه المستخدم ويتمتع بالبطء
فشل الهندسة ليس في استخدام ORM. بل هو التخلي عن المسؤولية عن SQL الذي ينتجه.
القراءة الإضافية