السؤال الكلاسيكي الذي يطرحه أحد المطورين إلى DBA أو مالك أعمال ، مستشار PostgreSQL ، يبدو دائمًا كما هو:
"لماذا تعمل الاستعلامات في قاعدة البيانات لفترة طويلة؟"مجموعة الأسباب التقليدية:
- خوارزمية غير فعالة
عندما قررت إنشاء JOE من عدة CTEs لبضع عشرات الآلاف من السجلات - إحصائيات غير ذات صلة
إذا كان التوزيع الفعلي للبيانات في الجدول مختلفًا تمامًا عن آخر مرة جمعتها ANALYZE - "هفوة" من الموارد
كما أن طاقة الحوسبة المخصصة لوحدة المعالجة المركزية ليست كافية بالفعل ، حيث يتم ضخ غيغابايت من الذاكرة باستمرار أو لا يواكب القرص قاعدة البيانات "مفضلة" - منع من العمليات المتنافسة
وإذا كان من الصعب للغاية التقاط الأقفال وتحليلها ، فبالنسبة إلى أي شيء آخر ، نحتاج
إلى خطة استعلام يمكن الحصول عليها باستخدام
عامل التشغيل EXPLAIN (
أفضل ، بالطبع ، بشكل فوري شرح (تحليل ، BUFFERS) ... ) أو
وحدة نمطية auto_explain .
ولكن ، كما قال في نفس الوثائق ،
"فهم الخطة عبارة عن فن ، ولإتقانها ، أنت بحاجة إلى بعض الخبرة ، ..."
ولكن يمكنك الاستغناء عنها ، إذا كنت تستخدم الأداة الصحيحة!
ما شكل خطة الاستعلام عادة؟ شيء مثل هذا:
Index Scan using pg_class_relname_nsp_index on pg_class (actual time=0.049..0.050 rows=1 loops=1) Index Cond: (relname = $1) Filter: (oid = $0) Buffers: shared hit=4 InitPlan 1 (returns $0,$1) -> Limit (actual time=0.019..0.020 rows=1 loops=1) Buffers: shared hit=1 -> Seq Scan on pg_class pg_class_1 (actual time=0.015..0.015 rows=1 loops=1) Filter: (relkind = 'r'::"char") Rows Removed by Filter: 5 Buffers: shared hit=1
أو مثل هذا:
"Append (cost=868.60..878.95 rows=2 width=233) (actual time=0.024..0.144 rows=2 loops=1)" " Buffers: shared hit=3" " CTE cl" " -> Seq Scan on pg_class (cost=0.00..868.60 rows=9972 width=537) (actual time=0.016..0.042 rows=101 loops=1)" " Buffers: shared hit=3" " -> Limit (cost=0.00..0.10 rows=1 width=233) (actual time=0.023..0.024 rows=1 loops=1)" " Buffers: shared hit=1" " -> CTE Scan on cl (cost=0.00..997.20 rows=9972 width=233) (actual time=0.021..0.021 rows=1 loops=1)" " Buffers: shared hit=1" " -> Limit (cost=10.00..10.10 rows=1 width=233) (actual time=0.117..0.118 rows=1 loops=1)" " Buffers: shared hit=2" " -> CTE Scan on cl cl_1 (cost=0.00..997.20 rows=9972 width=233) (actual time=0.001..0.104 rows=101 loops=1)" " Buffers: shared hit=2" "Planning Time: 0.634 ms" "Execution Time: 0.248 ms"
ولكن قراءة الخطة مع النص "من الورقة" صعب للغاية ومحبوب:
- يعرض العقدة مجموع موارد الشجرة الفرعية
أي لفهم مقدار الوقت المستغرق لتنفيذ عقدة معينة ، أو بالضبط مقدار مقدار هذه القراءة من الجدول الذي أثار البيانات من القرص - تحتاج إلى طرح أحدها بطريقة أخرى بطريقة أو بأخرى - يجب ضرب وقت العقدة بحلقات
نعم ، الطرح ليس العملية الأكثر صعوبة التي يجب القيام بها "في العقل" - بعد كل شيء ، تتم الإشارة إلى متوسط وقت التشغيل لتنفيذ عقدة واحدة ، وقد يكون هناك المئات - حسنًا ، وهذا كله يجعل من الصعب الإجابة على السؤال الرئيسي - إذن من هو "الحلقة الأضعف" ؟
عندما حاولنا شرح كل هذا لعدة مئات من مطورينا ، أدركنا أنه من الخارج يبدو مثل هذا:

وهذا يعني أننا بحاجة ...
أداة
في ذلك ، حاولنا جمع كل الميكانيكا الرئيسية التي تساعد وفقًا للخطة ونطلب أن نفهم "من يقع اللوم وماذا يفعل". حسنًا ، شارك بعضًا من تجربتك مع المجتمع.
يجتمع واستخدام -
illust.tensor.ruخطط واضحة
هل من السهل فهم الخطة عندما تبدو هكذا؟
Seq Scan on pg_class (actual time=0.009..1.304 rows=6609 loops=1) Buffers: shared hit=263 Planning Time: 0.108 ms Execution Time: 1.800 ms
ليس حقا
لكن هكذا ،
في شكل مختصر ، عندما يتم فصل المؤشرات الرئيسية - يكون الأمر أكثر وضوحًا بالفعل:

ولكن إذا كانت الخطة أكثر تعقيدًا ،
فسيكون توزيع وقت توزيع البايت بواسطة العقد
متاحًا للإنقاذ :

حسنًا ، بالنسبة إلى أصعب الخيارات ، يسارع
مخطط التنفيذ للمساعدة في:

على سبيل المثال ، هناك مواقف غير تافهة تمامًا عندما يكون للخطة أكثر من جذر فعلي واحد:


نصائح الهيكلية
حسنًا ، وإذا كانت البنية الكاملة للخطة ومواقعها المؤلمة قد وضعت بالفعل وضوحا - فلماذا لا تسليط الضوء عليها مع المطور واشرحها بـ "اللغة الروسية"؟

لقد جمعنا بالفعل بضع عشرات من نماذج التوصيات هذه.
منشئ الاستعلامات
الآن ، إذا وضعت الاستعلام الأصلي على الخطة التي تم تحليلها ، يمكنك معرفة مقدار الوقت المستغرق لكل مشغل فردي - شيء مثل هذا:

... أو حتى مع ذلك:

استبدال المعلمات في الطلب
إذا لم "ترفق" طلب الخطة فقط ، ولكن أيضًا معلماتها من سطر التفاصيل في السجل ، يمكنك نسخه بالإضافة إلى ذلك في أحد الخيارات:
- مع استبدال القيم في الطلب
للتنفيذ المباشر على قاعدتها والمزيد من التنميط
SELECT 'const', 'param'::text;
- مع استبدال القيمة عبر PREPARE / EXECUTE
لمضاهاة عمل المجدول عندما يمكن تجاهل الجزء حدودي - على سبيل المثال ، عند العمل على الجداول المقسمة
DEALLOCATE ALL; PREPARE q(text) AS SELECT 'const', $1::text; EXECUTE q('param'::text);
خطط الخطط
إدراج وتحليل ومشاركتها مع الزملاء! ستبقى الخطط في الأرشيف ، ويمكنك العودة إليها لاحقًا:
illust.tensor.ru/archiveولكن إذا كنت لا تريد أن يرى الآخرون خطتك ، فلا تنسَ تحديد مربع الاختيار "عدم النشر في الأرشيف".
في المقالات التالية سوف أتحدث عن الصعوبات والحلول التي تنشأ في تحليل الخطة.