المستوى: متوسط
لو عندك قاعدة PostgreSQL في الإنتاج وبتكتشف الاستعلام البطيء بس لمّا العميل يشتكي، يبقى انت متأخّر أسبوع. التقرير اللي هنبنيه هنا بيوصّلك أبطأ 10 استعلامات كل يوم إثنين الصبح على Slack، من غير ما تفتح السيرفر ولا تدفع لأداة مراقبة.
راقب أبطأ استعلامات PostgreSQL: تقرير أسبوعي تلقائي على Slack
الفكرة بسيطة. امتداد pg_stat_statements بيسجّل إحصائيات كل استعلام، وسكربت واحد مع cron بيلخّص أبطأها ويبعتها. النتيجة: بدل ما تخمّن، بتشوف رقم واضح كل أسبوع.
المشكلة باختصار
الصفحة بتحس بطيئة أحيانًا، والـ CPU مرتاح. مفيش حد يعرف أنهي استعلام هو السبب بالظبط. فبتضيف فهارس عشوائية وتتمنى. ده تخمين، مش هندسة. اللي ناقصك مش سيرفر أقوى، اللي ناقصك رؤية.
إيه هو pg_stat_statements؟ (المثال الأول، التعريف بعده)
تخيّل فاتورة موبايل مفصّلة. الفاتورة مش بتقولك "اتصلت 400 مرة" وخلاص. بتجمّع المكالمات المتشابهة وتقولك: مكالمات الدعم كلّفتك كذا، والمكالمات الدولية كلّفتك كذا. فتعرف في ثانية مين بيسحب فلوسك فعلًا.
الامتداد بيعمل نفس الحاجة بالظبط مع استعلاماتك. بياخد كل استعلام، يشيل القيم المتغيّرة منه (بيحوّل id = 42 إلى id = $1)، ويجمّع كل الاستعلامات المتشابهة في صف واحد. الصف بيحمل عدد المرات calls، وإجمالي وقت التنفيذ total_exec_time، ومتوسط الوقت mean_exec_time. التعريف الدقيق إذًا: جدول إحصائي حيّ لكل نمط استعلام مرّ على قاعدتك منذ آخر تصفير.
الخدعة اللي بتفرق: رتّب بإجمالي الوقت مش بالمتوسط
ركز في النقطة دي. استعلام بياخد 40 مللي ثانية بس بيتنفّذ 900 ألف مرة في الأسبوع يساوي 36 ألف ثانية إجمالي، يعني 10 ساعات معالجة. استعلام تاني بياخد 1.4 ثانية لكنه بيتنفّذ 2000 مرة بس يساوي 2800 ثانية. البطيء "بالإحساس" هو التاني، لكن اللي بياكل سيرفرك فعلًا هو الأول.
الطريقة الشائعة إنك ترتّب بالمتوسط، وهي بتفشل هنا لأنها بتخبّي الاستعلام الصغير كثير التكرار. رتّب بإجمالي وقت التنفيذ عشان تشوف التكلفة الحقيقية.
خطوة 1: فعّل الامتداد
# في ملف postgresql.conf
shared_preload_libraries = 'pg_stat_statements'
-- بعد إعادة تشغيل السيرفر مرة واحدة، ونفّذ داخل قاعدتك:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
الامتداد جزء من حزمة contrib الرسمية، ومدعوم على Amazon RDS و Google Cloud SQL. محتاج إعادة تشغيل واحدة للسيرفر بعد تعديل shared_preload_libraries، فخطّطها في نافذة صيانة.