0Pricing
Coding Interview Prep · درس

توسّع الربط وتضاعف الصفوف

سبب إمكانية إرجاع الربط عددًا من الصفوف أكبر من أي من الجدولين، وكيف يختبر مسؤولو المقابلات ذلك

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

عندما يعيد الربط عددًا كبيرًا جدًا من الصفوف

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

يفوّت المرشحون الذين يقولون "إن الربط يدمج الجداول فحسب" هذه النقطة. أما المرشحون القادرون على توقّع العدد الدقيق للصفوف فيحصلون على الوظيفة. يبني هذا الدرس مهارة التوقّع هذه.

السبب: المطابقات واحد إلى متعدد

يحدث التفرع عندما يطابق صف واحد على اليسار عدة صفوف على اليمين. وينتج عن كل مطابقة صف إخراج مستقل.

في حالة العملاء والطلبات، لدى Ada (عميل واحد) طلبان. يُخرج الربط صفًا لكل طلب، لذلك تتكرر Ada. وتتكرر حقول العميل، بينما تختلف حقول الطلب فقط.

SELECT c.name, o.amount
FROM customers c
JOIN orders o ON o.customer_id = c.id;
-- Ada appears twice (she has 2 orders)
-- name | amount
-- Ada  | 50
-- Ada  | 20
-- Bob  | 99

حساب صفوف الإخراج

يساوي عدد صفوف الإخراج مجموع المطابقات لكل صف أيسر، وليس عدد العملاء.

  • Ada -> طلبان -> صفان
  • Bob -> طلب واحد -> صف واحد
  • Cleo -> 0 طلبات -> 0 صفوف (تُحذف بواسطة INNER JOIN)

المجموع = 3 صفوف، مع أن جدول العملاء يحتوي أيضًا على 3 صفوف. إذا غيّرتم عدد طلبات Ada إلى 10، فستقفز النتيجة إلى 11 صفًا.

المطابقات المتعددة من الجانبين تتضخم

يتضاعف التفرع عندما يحتوي كلا الجانبين على عدة مطابقات للمفتاح نفسه. إذا ظهر المفتاح K ثلاث مرات على اليسار وأربع مرات على اليمين، فإن الربط ينتج 3 x 4 = 12 صفًا لهذا المفتاح.

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

-- left has 3 rows with tag 'A', right has 4 rows with tag 'A'
SELECT l.id, r.id
FROM left_t l
JOIN right_t r ON r.tag = l.tag;
-- tag 'A' alone yields 3 * 4 = 12 output rows

فخ التجميع

إليكم الخطأ الذي يزرعه القائمون على المقابلات في أغلب الأحيان. تربطون الطلبات بـ order_items للحصول على تفاصيل العناصر، ثم تجمعون قيمة الطلب باستخدام SUM. وبما أن كل طلب يتفرع إلى عدة صفوف للعناصر، تُحتسب قيمة الطلب مرة لكل عنصر.

تصبح قيمة SUM متضخمة جدًا. ويبدو الاستعلام صحيحًا بل ويعمل أيضًا، وهذا ما يجعله خطيرًا.

-- BUG: order.amount duplicated across items
SELECT SUM(o.amount) AS total
FROM orders o
JOIN order_items i ON i.order_id = o.id;
-- a 3-item order counts o.amount 3 times

رؤية التضخم

افترضوا أن أحد الطلبات قيمته 100 ويحتوي على ثلاثة عناصر. ينتج الربط ثلاثة صفوف، يحمل كل منها القيمة 100. تعيد SUM(o.amount) القيمة 300، لا 100.

يكمن الإصلاح في إجراء التجميع عند مستوى التفاصيل الصحيح: اجمعوا العناصر، أو اجمعوا الطلبات المميزة كلًّا على حدة. لا تستخدموا SUM مطلقًا لقيمة من الجدول الأصل عبر ربط متفرع بجدول تابع.

o.id | o.amount | i.id
7    | 100      | 71
7    | 100      | 72
7    | 100      | 73
-- SUM(o.amount) = 300  (WRONG, should be 100)

الإصلاح 1: تجميع الجدول التابع أولًا

أنظف إصلاح هو إجراء تجميع مسبق للجانب المتعدد في استعلام فرعي أو CTE، بحيث يطابق كل أصل صفًا ملخّصًا واحدًا بالضبط. لا تفرع ولا تضخم.

نختصر العناصر هنا إلى صف واحد لكل طلب قبل إجراء الربط، لذلك لا تتكرر قيمة الأصل مطلقًا.

SELECT o.id, o.amount, i.item_count
FROM orders o
JOIN (
  SELECT order_id, COUNT(*) AS item_count
  FROM order_items
  GROUP BY order_id
) i ON i.order_id = o.id;

الإصلاح 2: COUNT(DISTINCT) والمجاميع الشرطية

إذا اضطررتم إلى إجراء التجميع بعد ربط متفرع، فعدّوا أو اجمعوا عند مستوى التفاصيل الصحيح. استخدموا COUNT(DISTINCT o.id) لعدّ الطلبات بدلًا من صفوف العناصر.

ملاحظة: إن SUM(DISTINCT o.amount) ليس إصلاحًا آمنًا، لأن طلبين مختلفين قد يتشاركان القيمة نفسها بصورة مشروعة، وعندها سيُدمجان. التجميع المسبق أكثر موثوقية.

SELECT COUNT(DISTINCT o.id)   AS num_orders,
       COUNT(i.id)            AS num_items
FROM orders o
JOIN order_items i ON i.order_id = o.id;

اكتشاف التفرع قبل أن يسبب مشكلة

من أساليب التشخيص السريعة التي يفضّلها القائمون على المقابلات: تحقّقوا مما إذا كان مفتاح الربط فريدًا في الجانب الذي تتوقعون أن يكون جانب "الواحد". فإذا كان عدد المفاتيح المميزة أقل من عدد الصفوف، فهذا الجانب يحتوي على تكرارات وسيتسبب في التفرع.

-- if this returns rows, order_id is NOT unique in order_items
SELECT order_id, COUNT(*) AS n
FROM order_items
GROUP BY order_id
HAVING COUNT(*) > 1;

التحقق من مستوى التفاصيل باستخدام العدّ

قبل الوثوق بأي تجميع على نتيجة مرتبطة، تحقّقوا منطقيةً من عدد الصفوف. ومن الطرق السريعة مقارنة عدد الصفوف المرتبطة بعدد صفوف الجدول الذي تتوقعون أن يحدد مستوى التفاصيل.

إذا كان COUNT(*) على الربط أكبر من COUNT(*) على الطلبات، فهذا يعني أن الربط قد تفرّع وأن أي تجميع على مستوى الطلب معرض للخطر. لقد أنقذ هذا الفحص المؤلف من سطر واحد إجابات كثيرة في المقابلات.

-- joined rows should equal order count if no fan-out
SELECT COUNT(*) AS joined_rows
FROM orders o
JOIN order_items i ON i.order_id = o.id;

SELECT COUNT(*) AS order_rows FROM orders;
-- joined_rows > order_rows  =>  fan-out present

التفرع ليس خطأً دائمًا

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

حدّدوا مستوى التفاصيل قبل كتابة الاستعلام. فعبارة "أريد صفًا واحدًا لكل عنصر طلب" مقابل "صف واحد لكل طلب" هي التي تحدّد ما إذا كان التفرع ميزة أم خطأ.

اختبار سريع

توقّعوا ناتج ربط واحد إلى متعدد.

مراجعة: التفرع وتضاعف الصفوف

ما ينبغي تذكّره:

  • ينتج الربط صفًا واحدًا لكل زوج متطابق، لذلك تؤدي المطابقات واحد إلى متعدد إلى تكرار جانب "الواحد".
  • تضاعف المفاتيح متعدد إلى متعدد: 3 x 4 = 12 صفًا لذلك المفتاح.
  • يؤدي تجميع قيمة من الجدول الأصل عبر ربط متفرع إلى تضخيم المجاميع وعمليات العد.
  • أصلحوا ذلك عبر التجميع المسبق للجدول التابع، أو عبر العدّ والجمع عند مستوى التفاصيل الصحيح، مثل COUNT(DISTINCT).
  • حدّدوا دائمًا مستوى التفاصيل المقصود أولًا؛ فالتفرع لا يكون خطأً إلا عندما يخالفه.

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

هل درس «توسّع الربط وتضاعف الصفوف» مجاني؟

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

ماذا ستتعلم في «توسّع الربط وتضاعف الصفوف»؟

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

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

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

كم من الوقت يستغرق درس «توسّع الربط وتضاعف الصفوف»؟

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

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

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

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

  1. كيفية مطابقة INNER JOIN للصفوف
  2. ON مقابل WHERE في عمليات الربط
  3. توسّع الربط وتضاعف الصفوف
  4. ربط ثلاثة جداول أو أكثر
← العودة إلى Coding Interview Prep