WITH w AS NOT MATERIALIZED ( SELECT * FROM very_very_big_table ) SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref WHERE w2.key = 123;
اليوم ، وقع التزام في مستودع PostgreSQL ، والذي يسمح لك بالتحكم في سلوك معالجة استعلامات CTE الفرعية ، وهي: يمكنك الآن الإشارة صراحةً إلى ما إذا كان الاستعلام الفرعي سيتحقق بشكل منفصل أم سيتم تنفيذه كجزء من استعلام كبير واحد.
سيذهب هذا إلى PostgreSQL 12 وهذه مشكلة كبيرة. لنلقِ نظرة على السبب
يحب المبرمجون CTE لأنه يمكن أن يحسن بشكل كبير من قراءة الكود. حسنًا ، في الواقع ، يمكن لبعض الاستعلامات التحليلية أن تعمل مع عشرات الجداول ومجموعات مختلفة ومرشحات. لكتابة كل هذا في استعلام واحد كبير - مضمون للحصول على شيء غير قابل للقراءة. لذلك ، باستخدام عامل التشغيل WITH
، نقوم بالتتابع ، في الاستعلامات الفرعية الصغيرة (التي تُعطى اسمًا قابلاً للقراءة البشرية) لوصف منطق العمل ، ثم ننتج النتيجة. مريح جدا
بتعبير أدق ، سيكون مناسبًا جدًا إذا لم يكن لشيء واحد: ينفّذ PostgreSQL الحالي هذه الاستعلامات الفرعية بشكل منفصل عن الآخر ، ويتجسد فيها (يكتب النتيجة إلى جدول مؤقت). هذا يمكن أن يؤدي إلى تباطؤ كبير بالمقارنة مع وحش كبير غير قابل للقراءة. خاصةً إذا كانت استعلامات CTE الفرعية تُرجع ملايين الصفوف.
ومع ذلك ، هناك مواقف عندما يكون تنفيذ منفصلاً يعمل بشكل جيد: هناك خدعة تحسين عندما يكون من الأفضل تنفيذ جزء من طلب معقد بشكل منفصل ، لكن postgres لا يفهم ذلك من تلقاء نفسه. ثم نخرج هذا الجزء من استعلام CTE الفرعي.
بشكل عام ، تختلف المواقف ، ولهذا السبب ارتكبت Postgres 12 التزامًا بإضافة الكلمات الأساسية MATERIALIZED
و NOT MATERIALIZED
، والتي تشير إلى ما إذا كانت ستجسد الاستعلام أو مضمنة ، على التوالي.
علاوة على ذلك ، لقد تغير السلوك الافتراضي. الآن سيتم تضمين الاستعلام الفرعي CTE افتراضيًا إذا تم استخدام نتائجه مرة واحدة. خلاف ذلك ، وسوف تتحقق كما كان من قبل.