JOIN جدولًا جديدًا من خلال دمج الأعمدة من جدول واحد أو عدة جداول باستخدام القيم المشتركة بينها. وهي عملية شائعة في قواعد البيانات التي تدعم SQL، وتقابل عملية join في الجبر العلاقي. وغالبًا ما يُشار إلى الحالة الخاصة المتمثلة في ربط جدول بنفسه باسم “self-join”.
الصياغة
ON والأعمدة الواردة في عبارة USING “مفاتيح الربط”. ما لم يُذكر خلاف ذلك، فإن JOIN يُنتج حاصل ضرب ديكارتيًا من الصفوف ذات “مفاتيح الربط” المتطابقة، وقد يؤدي ذلك إلى نتائج تضم عددًا من الصفوف أكبر بكثير من الجداول المصدرية.
أنواع JOIN المدعومة
| Type | Description |
|---|---|
INNER JOIN | تُعاد الصفوف المتطابقة فقط. |
LEFT OUTER JOIN | تُعاد الصفوف غير المتطابقة من الجدول الأيسر بالإضافة إلى الصفوف المتطابقة. |
RIGHT OUTER JOIN | تُعاد الصفوف غير المتطابقة من الجدول الأيمن بالإضافة إلى الصفوف المتطابقة. |
FULL OUTER JOIN | تُعاد الصفوف غير المتطابقة من كلا الجدولين بالإضافة إلى الصفوف المتطابقة. |
CROSS JOIN | يُنتج حاصل الضرب الديكارتي للجدولين بالكامل، ولا تُحدَّد “مفاتيح الربط”. |
NATURAL JOIN | يربط تلقائيًا جميع الأعمدة ذات الاسم نفسه في كلا الجدولين؛ ويظهر كل عمود مشترك مرة واحدة في النتيجة. ويدعم الصيغ INNER (الافتراضية) وLEFT وRIGHT وFULL. وهو مكافئ لـ JOIN ... USING (col1, col2, ...) حيث تُشتق قائمة الأعمدة تلقائيًا. |
- يشير
JOINمن دون تحديد نوع إلىINNER. - يمكن حذف الكلمة المفتاحية
OUTERبأمان. - من الصيغ البديلة لـ
CROSS JOINتحديد عدة جداول فيFROMclause مفصولة بفواصل. - إذا لم تكن هناك أعمدة متطابقة لـ
NATURAL JOIN، فإنه يعمل مثلCROSS JOIN.
| Type | Description |
|---|---|
LEFT SEMI JOIN, RIGHT SEMI JOIN | قائمة سماح على “مفاتيح الربط”، من دون إنتاج حاصل ضرب ديكارتي. |
LEFT ANTI JOIN, RIGHT ANTI JOIN | قائمة حظر على “مفاتيح الربط”، من دون إنتاج حاصل ضرب ديكارتي. |
LEFT ANY JOIN, RIGHT ANY JOIN, INNER ANY JOIN | يعطّل جزئيًا (للجانب المقابل من LEFT وRIGHT) أو كليًا (بالنسبة إلى INNER وFULL) حاصل الضرب الديكارتي لأنواع JOIN القياسية. |
ASOF JOIN, LEFT ASOF JOIN | ربط للتسلسلات مع مطابقة غير تامة. يُشرح استخدام ASOF JOIN أدناه. |
PASTE JOIN | يُجري دمجًا أفقيًا لجدولين. |
عند ضبط join_algorithm على
partial_merge، لا يكون RIGHT JOIN وFULL JOIN مدعومَين إلا مع strictness من النوع ALL (SEMI وANTI وANY وASOF غير مدعومة).الإعدادات
JOIN الافتراضي باستخدام الإعداد join_default_strictness.
يعتمد سلوك ClickHouse server في عمليات ANY JOIN على الإعداد any_join_distinct_right_table_keys.
انظر أيضًا
join_algorithmjoin_any_take_last_rowjoin_use_nullspartial_merge_join_rows_in_right_blocksjoin_on_disk_max_files_to_mergeany_join_distinct_right_table_keys
cross_to_inner_join_rewrite لتحديد السلوك عند فشل ClickHouse في إعادة كتابة CROSS JOIN إلى INNER JOIN. القيمة الافتراضية هي 1، ما يسمح بمتابعة عملية JOIN ولكنها ستكون أبطأ. اضبط cross_to_inner_join_rewrite على 0 إذا كنت تريد ظهور خطأ، واضبطه على 2 لعدم تشغيل عمليات cross joins، وبدلًا من ذلك فرض إعادة كتابة جميع عمليات comma/cross joins. وإذا فشلت إعادة الكتابة عندما تكون القيمة 2، فستتلقى رسالة خطأ تنص على: “Please, try to simplify WHERE section”.
شروط قسم ON
ON على عدة شروط مدمجة باستخدام المعاملين AND وOR. ويجب أن تستوفي الشروط التي تحدد مفاتيح الربط ما يلي:
- أن تشير إلى كلٍّ من الجدول الأيسر والجدول الأيمن
- أن تستخدم معامل المساواة
JOIN. لاحظ أنه إذا وُضعت الشروط نفسها في قسم WHERE ولم تتحقق، فستُستبعد الصفوف دائمًا من النتيجة.
يعمل المعامل OR داخل عبارة ON باستخدام خوارزمية الربط بالتجزئة — إذ يُنشأ جدول تجزئة منفصل لكل وسيطة OR تحتوي على مفاتيح ربط لـ JOIN، لذلك يزداد استهلاك الذاكرة ووقت تنفيذ الاستعلام خطيًا مع زيادة عدد تعبيرات OR في عبارة ON.
إذا كان الشرط يشير إلى أعمدة من جداول مختلفة، فلا يدعم النظام حتى الآن سوى معامل المساواة (
=).table_1 وtable_2:
table_2:
Query
C وعمود النص الفارغ. وقد أُدرجت في النتيجة لأن نوع OUTER من join مستخدم هنا.
Response
INNER وبشروط متعددة:
Query
Response
join من النوع INNER وشرط يستخدم OR:
Query
Response
INNER وبشروط تتضمن OR وAND:
افتراضيًا، تكون شروط عدم المساواة مدعومة ما دامت تستخدم أعمدة من الجدول نفسه.
على سبيل المثال،
t1.a = t2.key AND t1.b > 0 AND t2.b > t2.c، لأن t1.b > 0 يستخدم أعمدة من t1 فقط، وt2.b > t2.c يستخدم أعمدة من t2 فقط.
ومع ذلك، يمكنك تجربة الدعم التجريبي لشروط مثل t1.a = t2.key AND t1.b > t2.key؛ راجع القسم أدناه لمزيد من التفاصيل.Query
Response
JOIN مع شروط عدم المساواة للأعمدة من جداول مختلفة
ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN مع شروط عدم المساواة بالإضافة إلى شروط المساواة. ولا تُدعَم شروط عدم المساواة إلا مع خوارزميّتَي JOIN hash وgrace_hash. كما أن شروط عدم المساواة غير مدعومة مع join_use_nulls.
مثال
الجدول t1:
t2
قيم NULL في مفاتيح JOIN
NULL أي قيمة، بما في ذلك نفسها. وهذا يعني أنه إذا كانت قيمة مفتاح JOIN هي NULL في أحد الجدولين، فلن تطابق قيمة NULL في الجدول الآخر.
مثال
الجدول A:
B:
Charlie من الجدول A، والصف الذي درجته 88 من الجدول B، لا يظهران في النتيجة بسبب القيمة NULL في مفتاح JOIN.
إذا أردت مطابقة قيم NULL، فاستخدم الدالة isNotDistinctFrom لمقارنة مفاتيح JOIN.
استخدام ASOF JOIN
ASOF JOIN مفيدة عندما تحتاج إلى ربط سجلات لا يوجد بينها تطابق تام.
تتطلب خوارزمية JOIN هذه عمودًا خاصًا في الجداول. ويجب أن يكون هذا العمود:
- أن يحتوي على تسلسل مرتب.
- من أحد الأنواع التالية: Int, UInt، Float، Date، DateTime، Decimal.
- بالنسبة إلى خوارزمية
hashjoin، لا يمكن أن يكون العمود الوحيد في عبارةJOIN.
ASOF JOIN ... ON:
SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t.
الشروط المدعومة لأقرب مطابقة: >, >=, <, <=.
الصياغة ASOF JOIN ... USING:
ASOF JOIN equi_columnX للربط وفقًا للمساواة، وasof_column للربط بأقرب قيمة مطابقة مع الشرط table_1.asof_column >= table_2.asof_column. ويكون العمود asof_column دائمًا هو الأخير في بند USING.
على سبيل المثال، تأمل الجداول التالية:
ASOF JOIN أخذ الطابع الزمني لحدث مستخدم من table_1 والعثور على حدث في table_2 يكون طابعه الزمني الأقرب إلى الطابع الزمني لحدث table_1 وفقًا لشرط أقرب تطابق. وتُعد قيم الطابع الزمني المتساوية هي الأقرب إذا كانت متاحة. هنا، يمكن استخدام العمود user_id للربط على أساس المساواة، ويمكن استخدام العمود ev_time للربط على أساس أقرب تطابق. في مثالنا، يمكن ربط event_1_1 مع event_2_1، ويمكن ربط event_1_2 مع event_2_3، لكن لا يمكن ربط event_2_2.
لا يدعم
ASOF JOIN إلا خوارزميتي JOIN hash وfull_sorting_merge.
وهو غير مدعوم في محرك الجدول Join.استخدام PASTE JOIN
PASTE JOIN هي جدول يحتوي على جميع الأعمدة من الاستعلام الفرعي الأيسر، ثم جميع الأعمدة من الاستعلام الفرعي الأيمن.
تُطابَق الصفوف بناءً على مواضعها في الجداول الأصلية (يجب أن يكون ترتيب الصفوف محددًا).
إذا أعادت الاستعلامات الفرعية أعدادًا مختلفة من الصفوف، فستُقتطع الصفوف الزائدة.
مثال:
JOIN الموزّع
JOIN يتضمن جداول موزعة:
- عند استخدام
JOINعادي، يُرسَل الاستعلام إلى الخوادم البعيدة. وتُشغَّل الاستعلامات الفرعية على كل خادم منها لتكوين الجدول الأيمن، ثم تُنفَّذ عملية الربط باستخدام هذا الجدول. وبعبارة أخرى، يُنشأ الجدول الأيمن على كل خادم على حدة. - عند استخدام
GLOBAL ... JOIN، يشغّل الخادم الذي أرسل الطلب أولًا استعلامًا فرعيًا لحساب أحد طرفَي الربط ويجمع النتيجة في جدول مؤقت. ثم يُمرَّر هذا الجدول المؤقت إلى كل خادم بعيد، وتُشغَّل الاستعلامات عليها باستخدام البيانات المؤقتة المنقولة. في عمليتَي الربطLEFTوINNER، يُحسَب الجدول الأيمن باعتباره الاستعلام الفرعي. أما في عملية الربطRIGHT، فيُحسَب الجدول الأيسر بدلًا من ذلك، لأن الجدول الأيمن هو الجدول الذي يجري الاحتفاظ به ويجب قراءته من الشظايا.
GLOBAL. لمزيد من المعلومات، راجع قسم الاستعلامات الفرعية الموزعة.
تحويل النوع الضمني
INNER JOIN وLEFT JOIN وRIGHT JOIN وFULL JOIN تحويل النوع الضمني لـ “join keys”. ومع ذلك، لا يمكن تنفيذ الاستعلام إذا تعذر تحويل مفاتيح الربط في الجدولين الأيسر والأيمن إلى نوع واحد (على سبيل المثال، لا يوجد نوع بيانات يمكنه استيعاب جميع القيم من كلٍّ من UInt64 وInt64، أو String وInt32).
مثال
لنأخذ الجدول t_1:
t_2:
توصيات الاستخدام
معالجة الخلايا الفارغة أو NULL
JOIN حقولًا من النوع Nullable، فلن تُربط الصفوف التي تكون قيمة واحد على الأقل من هذه المفاتيح فيها NULL.
البنية
USING الأسماء نفسها في كلا الاستعلامين الفرعيين، وأن تختلف أسماء الأعمدة الأخرى. يمكنك استخدام الأسماء المستعارة لتغيير أسماء الأعمدة في الاستعلامات الفرعية.
تحدّد عبارة USING عمودًا واحدًا أو أكثر للربط، وبذلك تفرض تساوي هذه الأعمدة. تُكتب قائمة الأعمدة من دون أقواس. ولا تُدعَم شروط ربط أكثر تعقيدًا.
قيود الصياغة
JOIN المتعددة ضمن استعلام SELECT واحد:
- لا يتاح استخدام جميع الأعمدة عبر
*إلا إذا كان الربط بين جداول، لا استعلامات فرعية. - عبارة
PREWHEREغير متاحة. - عبارة
USINGغير متاحة.
ON وWHERE وGROUP BY:
- لا يمكن استخدام تعبيرات عشوائية في عبارات
ONوWHEREوGROUP BY، ولكن يمكنك تعريف تعبير في عبارةSELECTثم استخدامه في هذه العبارات عبر اسم مستعار.
الأداء
JOIN، لا يوجد تحسين لترتيب التنفيذ بالنسبة إلى المراحل الأخرى من الاستعلام. ويُنفَّذ الـ join (أي البحث في الجدول الأيمن) قبل التصفية في WHERE وقبل التجميع.
في كل مرة يُنفَّذ فيها استعلام يستخدم JOIN نفسه، يُعاد تنفيذ الاستعلام الفرعي لأن النتيجة غير مخزنة مؤقتًا. ولتجنّب ذلك، استخدم محرك الجدول الخاص Join، وهو مصفوفة مُعدّة مسبقًا لعمليات الربط وتبقى دائمًا في ذاكرة RAM.
في بعض الحالات، يكون استخدام IN أكثر كفاءة من JOIN.
إذا كنت بحاجة إلى JOIN للربط مع جداول الأبعاد (وهي جداول صغيرة نسبيًا تحتوي على خصائص الأبعاد، مثل أسماء الحملات الإعلانية)، فقد لا يكون JOIN مناسبًا جدًا لأن الجدول الأيمن يُعاد الوصول إليه مع كل استعلام. في مثل هذه الحالات، توجد ميزة “Dictionaries” ينبغي استخدامها بدلًا من JOIN. لمزيد من المعلومات، راجع قسم Dictionaries.
قيود الذاكرة
right_table وينشئ له جدول تجزئة في RAM. إذا كان join_algorithm = 'auto' مفعّلًا، فبعد تجاوز عتبة معيّنة من استهلاك الذاكرة، يعود ClickHouse إلى خوارزمية merge join. للاطلاع على وصف خوارزميات JOIN، راجع الإعداد join_algorithm.
إذا كنت بحاجة إلى تقييد استهلاك الذاكرة لعملية JOIN، فاستخدم الإعدادات التالية:
- max_rows_in_join — يحدّ من عدد الصفوف في جدول التجزئة.
- max_bytes_in_join — يحدّ من حجم جدول التجزئة.
أمثلة
- مدونة: ClickHouse: نظام إدارة قواعد بيانات فائق السرعة مع دعم كامل لعمليات JOIN في SQL - الجزء 1
- مدونة: ClickHouse: نظام إدارة قواعد بيانات فائق السرعة مع دعم كامل لعمليات JOIN في SQL - خلف الكواليس - الجزء 2
- مدونة: ClickHouse: نظام إدارة قواعد بيانات فائق السرعة مع دعم كامل لعمليات JOIN في SQL - خلف الكواليس - الجزء 3
- مدونة: ClickHouse: نظام إدارة قواعد بيانات فائق السرعة مع دعم كامل لعمليات JOIN في SQL - خلف الكواليس - الجزء 4