إذا كتبت
استعلامات SQL دون تحليل الخوارزمية التي يجب أن تنفذها ، فإن هذا لا يؤدي عادة إلى أي شيء جيد من حيث الأداء.
مثل هذه الطلبات
مثل "أكل" وقت المعالج وقراءة البيانات بنشاط من اللون الأزرق. علاوة على ذلك ، ليس هذا بالضرورة نوعًا من الاستعلامات المعقدة ، بل على العكس - كلما تمت كتابتها بشكل أبسط ، زادت فرصة حدوث المشكلات. وإذا كان مشغل JOIN يلعب دوره ...
إن ربط الجداول في حد ذاته ليس ضارًا أو مفيدًا - إنه مجرد أداة ، لكن يجب أن تكون قادرًا على استخدامها.
تجمع الرقابة
أولا ، خذ مثالا بسيطا جدا.
يوجد "قاموس" يضم 100 إدخال (على سبيل المثال ، هذه مناطق في الاتحاد الروسي):
CREATE TABLE tbl_dict AS SELECT generate_series(0, 100) k; ALTER TABLE tbl_dict ADD PRIMARY KEY(k);
... ومرفقة به جدول "الحقائق" ذات الصلة لكل مائة ألف إدخال:
CREATE TABLE tbl_fact AS SELECT (random() * 100)::integer k , (random() * 1000)::integer v FROM generate_series(1, 100000); CREATE INDEX ON tbl_fact(k);
الآن دعونا نحاول حساب مجموع القيم لكل "منطقة".
كما سمع ، هو مكتوب
SELECT dk , sum(fv) FROM tbl_fact f NATURAL JOIN tbl_dict d GROUP BY 1;
استغرق قراءة البيانات نفسها 18٪ فقط من الوقت ، وكان الباقي قيد المعالجة:
[انظروا شرح.tensor.ru]وكل ذلك لأن Hash Join and Hash Aggregate كان عليهما معالجة سجلات 100K لكل منهما بسبب رغبتنا في التجميع
حسب مجال الجدول المرتبط .
نحن نستخدم البراعة
لكن قيمة هذا الحقل تساوي قيمة الحقل في الجدول المجمع! أي أنه لا أحد يزعجنا أن نجمع
أولاً "الحقائق" ، وعندها فقط نربط :
SELECT dk , f.sum FROM ( SELECT k , sum(v) FROM tbl_fact GROUP BY 1 ) f NATURAL JOIN tbl_dict d;
[انظروا شرح.tensor.ru]بالطبع ، هذه الطريقة ليست عالمية ، ولكن بالنسبة لحالتنا الخاصة بـ "JOIN المعتادة"
، فإن كسب الوقت هو مرتين مع الحد الأدنى من تعديل الطلب - ببساطة بسبب "Hash Join" الذي تم إلغاؤه ، والذي تلقى 100 إدخال فقط بدلاً من مداخل 100K.
ظروف غير متكافئة
الآن دعنا نعقد المهمة: لدينا 3 جداول متصلة بمعرف واحد - الجدولان الرئيسيان والجدولان المساعدان مع بعض بيانات التطبيق ، والتي سنقوم بالتصفية بها.
ملاحظة صغيرة ولكنها مهمة جدًا: على الرغم من المعرفة "التطبيقية" للمهمة المستهدفة ، فإننا نعلم بالفعل أن الشروط سيتم تلبيتها
في الجدول الأول - دائمًا تقريبًا (على وجه اليقين - 3: 4) ،
والثاني - نادرًا جدًا (1: 8) ).
نريد أن نختار من أول
100 جدول من الجداول المساعدة
والسجلات الإضافية
الأولى بمعرف مع قيم معرف حتى يتم
استيفاء الشروط في جميع الجداول . جميع السجلات في الجداول ، دعونا مرة أخرى في 100K.
مولد النصي CREATE TABLE base( id integer PRIMARY KEY , val integer ); INSERT INTO base SELECT id , (random() * 1000)::integer FROM generate_series(1, 100000) id; CREATE TABLE ext1( id integer PRIMARY KEY , conda boolean ); INSERT INTO ext1 SELECT id , (random() * 4)::integer <> 0
كما سمع ، هو مكتوب
SELECT base.* , ext1.* FROM base NATURAL JOIN ext1 NATURAL JOIN ext2 WHERE id % 2 = 0 AND conda AND condb ORDER BY base.id LIMIT 100;
[انظروا شرح.tensor.ru]الأوقات السلبية من حيثلقد مرت العديد من الدورات عبر بعض العقد حتى أن أخطاء التقريب للبعض قد تم دفعها إلى السلبيات. فقط حول القطع الأثرية المماثلة في الخطط سأتحدث عن
PGConf.Russia .
200 مللي ثانية وأكثر من 2 جيجا بايت من البيانات التي تم ضخها - ليست جيدة جدًا لـ 100 سجل!
نحن نستخدم البراعة
نستخدم الطرق التالية لتحقيق التسارع:
- بادئ ذي بدء ، نحن نفهم أنه من المنطقي بالنسبة لنا التحقق من كل الشروط للجداول المرتبطة فقط عندما يتم استيفاء شروط الجدول الرئيسي (حتى المعرف).
- يجب فرز الإخراج حسب base.id ، ولهذا ، فإن المفتاح الأساسي لهذا الجدول مثالي بالنسبة لنا!
- لا نحتاج إلى بيانات من الملفات ext2 ، ويتم استخدامها فقط للتحقق من الحالة. هذا يعني أنه يمكن إزالة كل العمل مع هذا الجدول بأمان من JOIN إلى الجزء WHERE . واستخدم EXISTS للتحقق ، وإلا ماذا لو لم يكن هناك مثل هذا السجل على الإطلاق؟
- نحتاج إلى استرداد بعض البيانات على الأقل من نظام ext1 فقط إذا تم اجتياز عمليات التحقق المتبقية على القاعدة و ext2 بنجاح . بمعنى أن الاتصال بـ ext1 يجب أن يتبع كل الإجراءات مع base / ext2 ، والتي يمكن تحقيقها باستخدام LATERAL.
- بحيث لا يحاول مخطط الاستعلام تحويل التحقق المتداخل على ext2 إلى JOIN ، استعلام فرعي "إخفاء تحت CASE" .
SELECT base.* , ext1.* FROM base , LATERAL(
[انظروا شرح.tensor.ru]بالطبع ، أصبح الطلب أكثر تعقيدًا ، لكن
الفوز بـ 13 مرة في الوقت و 350 في "الشراهة" يستحق كل هذا العناء!
اسمحوا لي أن أذكرك مرة أخرى أنه لا يتم استخدام جميع الأساليب وليس دائمًا ، ولكن المعرفة لن تكون ضرورية.سيكون أيضًا مثيرًا للاهتمام: