الانتقال إلى المحتوى الرئيسي
تُعد PREWHERE تحسينًا يجعل تطبيق التصفية أكثر كفاءة. وهي مفعّلة افتراضيًا حتى إذا لم تُحدَّد عبارة PREWHERE صراحةً. وتعمل بنقل جزء من شرط WHERE تلقائيًا إلى مرحلة PREWHERE. ويقتصر دور عبارة PREWHERE على التحكم في هذا التحسين إذا كنت ترى أنك تعرف كيفية تطبيقه بصورة أفضل من السلوك الافتراضي. عند استخدام تحسين PREWHERE، لا تُقرأ في البداية إلا الأعمدة اللازمة لتنفيذ تعبير PREWHERE. ثم تُقرأ الأعمدة الأخرى المطلوبة لتنفيذ بقية الاستعلام، ولكن فقط من الكتل التي تكون فيها قيمة تعبير PREWHERE هي true لبعض الصفوف على الأقل. وإذا كان هناك عدد كبير من الكتل التي تكون فيها قيمة تعبير PREWHERE هي false لجميع الصفوف، وكان PREWHERE يحتاج إلى أعمدة أقل من الأجزاء الأخرى من الاستعلام، فغالبًا ما يتيح ذلك قراءة قدر أقل بكثير من البيانات من القرص عند تنفيذ الاستعلام.

التحكّم في PREWHERE يدويًا

لهذه العبارة المعنى نفسه لعبارة WHERE. ويكمن الاختلاف في البيانات التي تُقرأ من الجدول. عند التحكّم يدويًا في PREWHERE لشروط التصفية التي تستخدمها قلّة من الأعمدة في الاستعلام، لكنها توفّر تصفية قوية للبيانات، فإن ذلك يقلّل حجم البيانات المطلوب قراءتها. يمكن أن يحدّد الاستعلام كلًا من PREWHERE وWHERE في الوقت نفسه. في هذه الحالة، يُنفَّذ PREWHERE قبل WHERE. إذا كان الإعداد optimize_move_to_prewhere مضبوطًا على 0، فسيتم تعطيل الآليات الاستدلالية التي تنقل تلقائيًا أجزاءً من التعبيرات من WHERE إلى PREWHERE. إذا كان الاستعلام يحتوي على المُعدِّل FINAL، فإن تحسين PREWHERE لا يكون صحيحًا دائمًا. ولا يُفعَّل إلا إذا كان كل من الإعدادين optimize_move_to_prewhere وoptimize_move_to_prewhere_if_final مفعّلَين.
يُنفَّذ قسم PREWHERE قبل FINAL، لذا قد تكون نتائج استعلامات FROM ... FINAL غير دقيقة عند استخدام PREWHERE مع حقول غير موجودة في قسم ORDER BY من الجدول.

القيود

لا تكون PREWHERE مدعومة إلا في الجداول التابعة لعائلة *MergeTree.

مثال

CREATE TABLE mydata
(
    `A` Int64,
    `B` Int8,
    `C` String
)
ENGINE = MergeTree
ORDER BY A AS
SELECT
    number,
    0,
    if(number between 1000 and 2000, 'x', toString(number))
FROM numbers(10000000);

SELECT count()
FROM mydata
WHERE (B = 0) AND (C = 'x');

1 row in set. Elapsed: 0.074 sec. Processed 10.00 million rows, 168.89 MB (134.98 million rows/s., 2.28 GB/s.)

-- let's enable tracing to see which predicate are moved to PREWHERE
set send_logs_level='debug';

MergeTreeWhereOptimizer: condition "B = 0" moved to PREWHERE  
-- Clickhouse moves automatically `B = 0` to PREWHERE, but it has no sense because B is always 0.

-- Let's move other predicate `C = 'x'` 

SELECT count()
FROM mydata
PREWHERE C = 'x'
WHERE B = 0;

1 row in set. Elapsed: 0.069 sec. Processed 10.00 million rows, 158.89 MB (144.90 million rows/s., 2.30 GB/s.)

-- This query with manual `PREWHERE` processes slightly less data: 158.89 MB VS 168.89 MB
آخر تعديل في ٢٥ يونيو ٢٠٢٦