0Pricing
SQL Interview Prep · درس

التصفية حسب القيم المحسوبة

سبب تعطيل الدوال المطبقة على الأعمدة لاستخدام الفهارس، وكيف يستكشف مسؤولو المقابلات ذلك

التصفية حسب القيم المحسوبة درس مجاني في SQL Interview Prep على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في SQL Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

لماذا يميّز هذا السؤال بين مستويات الخبرة

يبدو السؤال بريئًا: هذا الاستعلام صحيح لكنه بطيء، لماذا؟ غالبًا تكون الإجابة أن جملة WHERE تضع عمودًا مفهرسًا داخل دالة. وهذا يجعل الشرط غير قابل للاستفادة من الفهرس (non-sargable)، إذ لا يعود المُحسِّن قادرًا على استخدام الفهرس، ويضطر إلى فحص كل صف.

يشرح هذا الدرس مفهوم Sargability، ويعرض إعادة الصياغة التي يتوقعها المحاورون، ويوضح الموضع الصحيح للمرشح المحسوب.

Sargable في تعريف واحد

تعني Sargable (Search ARGument ABLE) أن الشرط يمكنه استخدام فهرس للانتقال مباشرةً إلى الصفوف المطابقة. والقاعدة العامة هي أن يظهر العمود المفهرس من دون تعديل في أحد طرفي المقارنة، لا أن يكون مدفونًا داخل دالة أو تعبير.

  • قابل للاستفادة من الفهرس: col = 5، col > 100، col LIKE 'abc%'
  • غير قابل للاستفادة من الفهرس: FUNC(col) = 5، col + 1 > 100

النمط المضاد لاستخدام دالة على العمود

الهدف هنا هو الحصول على الطلبات التي وُضعت في عام 2024. إن وضع العمود داخل YEAR() يجبر المحرك على حساب السنة لكل صف على حدة قبل إجراء المقارنة، ولذلك يصبح الفهرس الموجود على order_date بلا فائدة.

يعيد الاستعلام النتيجة الصحيحة، لكنه يفحص الجدول بأكمله. وفي جدول كبير، قد يعني ذلك الفرق بين أجزاء من الثانية ودقائق كاملة.

-- non-sargable: function on the indexed column
SELECT *
FROM orders
WHERE YEAR(order_date) = 2024;

إعادة الصياغة كنطاق

يكمن الحل في إبقاء order_date من دون تعديل، والتعبير عن الشرط باستخدام نطاق نصف مفتوح. عندها يستطيع الفهرس الموجود على order_date الانتقال مباشرةً إلى بداية عام 2024 والتوقف عند عام 2025.

النتيجة نفسها، لكن مع فحص لنطاق الفهرس بدلًا من فحص كامل. وتُعد إعادة صياغة النطاق هذه أكثر حلول Sargability شيوعًا في المقابلات.

-- sargable: column stays bare
SELECT *
FROM orders
WHERE order_date >= '2024-01-01'
  AND order_date <  '2025-01-01';

الحساب على العمود

تظهر المشكلة نفسها في العمليات الحسابية. فكل من WHERE salary + bonus > 100000 وWHERE price * 0.9 < 50 يجري عملية على العمود، مما يمنع استخدام الفهرس.

انقل العملية الحسابية إلى جانب الثابت كلما أمكن: أعد كتابة price * 0.9 < 50 بالشكل price < 50 / 0.9. عندها تُحسب القيمة الحرفية مرة واحدة، ويبقى price من دون تعديل وقابلًا للفهرسة.

-- before: math on the column (non-sargable)
WHERE price * 0.9 < 50
-- after: math on the constant (sargable)
WHERE price < 50 / 0.9

صيغة البحث غير الحساسة لحالة الأحرف

يكون WHERE LOWER(email) = 'a@b.com' غير قابل للاستفادة من فهرس عادي على email، لأن البريد الإلكتروني لكل صف يُحوَّل إلى أحرف صغيرة أولًا.

هناك حلّان عمليان في بيئات الإنتاج: تخزين نسخة موحّدة بأحرف صغيرة وفهرستها، أو إنشاء فهرس وظيفي على LOWER(email) بحيث تتم فهرسة التعبير نفسه. وذكر خيار الفهرس الوظيفي يدل على خبرة عملية حقيقية.

-- functional index makes the expression sargable
CREATE INDEX idx_email_lower ON users (LOWER(email));
SELECT * FROM users WHERE LOWER(email) = 'a@b.com';

متى تحتاج فعلًا إلى حساب

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

لذلك، إما أن تكرر التعبير في WHERE، أو تضع الاستعلام داخل استعلام فرعي أو CTE، ثم تصفّي العمود المحسوب في الاستعلام الخارجي.

SELECT *
FROM (
  SELECT *, revenue / NULLIF(visits, 0) AS rev_per_visit
  FROM stats
) t
WHERE t.rev_per_visit > 2.5;

ضع التجميعات في HAVING لا WHERE

لا يمكن أن يوجد الحساب التجميعي داخل WHERE إطلاقًا، لأن WHERE يصفّي الصفوف الفردية قبل حدوث التجميع. ولذلك فإن WHERE SUM(amount) > 1000 يسبب خطأً.

تنتمي مرشحات التجميع إلى HAVING، الذي يُنفَّذ بعد GROUP BY. ومعرفة الجملة التي ترى الحساب تُعد بحد ذاتها سؤالًا شائعًا عن ترتيب التنفيذ.

SELECT customer_id, SUM(amount) AS total
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 1000;

كيف يختبر المحاورون فهمك

يعرضون استعلامًا بطيئًا يحتوي على دالة مطبقة على عمود، ويطلبون منك تسريعه من دون تغيير النتيجة. وما عليك فعله هو:

  • تحديد أن استخدام الدالة على العمود غير قابل للاستفادة من الفهرس
  • إعادة الصياغة مع إبقاء العمود من دون تعديل، باستخدام نطاق أو نقل العملية إلى جانب الثابت
  • إذا لم توجد إعادة صياغة مناسبة، اقتراح فهرس وظيفي أو عمود محسوب مخزّن

وذكر EXPLAIN للتأكد من تغيّر الخطة من فحص تسلسلي إلى فحص بالفهرس يحسم الإجابة.

الوعي بالمفاضلات

كن متوازنًا: تسرّع الفهارس والفهارس الوظيفية عمليات القراءة، لكنها تبطّئ عمليات الكتابة وتستهلك مساحة تخزين. وفي جدول صغير جدًا، يكون الفحص الكامل مناسبًا، وتصبح إضافة فهرس جهدًا ضائعًا.

الإجابة المتقدمة مشروطة بالسياق: إذا كان هذا العمود كبيرًا وتُجرى التصفية عليه بهذه الطريقة كثيرًا، فاجعل الشرط قابلًا للاستفادة من الفهرس أو أضف فهرسًا وظيفيًا؛ وإلا فاتركه كما هو. فالسياق أهم من التمسك بقاعدة جامدة في المقابلات.

الفهارس الوظيفية تجعل الحساب قابلًا للاستفادة من الفهرس

أحيانًا يتعين عليكم فعلًا التصفية وفق قيمة محوَّلة، مثل المطابقة غير الحساسة لحالة الأحرف. بدلًا من التخلي عن الفهارس، أنشئوا فهرسًا تعبيريًا (وظيفيًا) على التعبير نفسه الذي تُجرى التصفية وفقه.

  • يمكن للمحسّن عندئذٍ استخدام الفهرس، حتى مع إحاطة العمود بدالة.
  • يجب أن يطابق تعبير الفهرس تعبير الشرط مطابقة تامة.
-- index the expression you filter on
CREATE INDEX idx_users_lower_email ON users (lower(email));

-- now this predicate stays sargable
SELECT * FROM users WHERE lower(email) = 'amy@example.com';

اختبار سريع

حدّد الشرط الذي يستطيع المُحسِّن فهرسته.

خلاصة

أهم النقاط:

  • يكون الشرط sargable عندما يظهر العمود المفهرس من دون تعديل، لا داخل دالة أو عملية حسابية
  • أعد كتابة YEAR(col) = 2024 كنطاق نصف مفتوح، وانقل العمليات الحسابية إلى جانب الثابت
  • استخدم فهرسًا وظيفيًا أو عمودًا محسوبًا مخزّنًا للتعبيرات التي لا يمكن تجنبها
  • لا يمكنك استخدام اسم مستعار من SELECT في WHERE؛ وتوضع التجميعات في HAVING

السؤال الكلاسيكي هو استعلام بطيء، والحل الكلاسيكي هو إبقاء العمود من دون تعديل.

الأسئلة الشائعة

هل درس «التصفية حسب القيم المحسوبة» مجاني؟

نعم — نص درس «التصفية حسب القيم المحسوبة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة SQL Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة SQL Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «التصفية حسب القيم المحسوبة»؟

سبب تعطيل الدوال المطبقة على الأعمدة لاستخدام الفهارس، وكيف يستكشف مسؤولو المقابلات ذلك تتمرن على SQL Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ SQL Interview Prep؟

لا تُشترط خبرة سابقة. SQL Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «التصفية حسب القيم المحسوبة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس SQL Interview Prep هذا؟

نعم. كل درس في SQL Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أسبقية AND وOR ووضع الأقواس
  2. BETWEEN وIN والحدود الشاملة
  3. LIKE والرموز البديلة وهروب المحارف
  4. التصفية حسب القيم المحسوبة
← العودة إلى SQL Interview Prep