Skip to main content
يدعم ClickHouse طيفًا واسعًا من أنواع JOIN وخوارزمياته، وقد تحسّن أداء JOIN بشكل ملحوظ في الإصدارات الأخيرة. ومع ذلك، تظل عمليات JOIN بطبيعتها أعلى كلفة من الاستعلام من جدول واحد غير مُطبَّع. وتنقل إزالة التطبيع العبء الحاسوبي من وقت الاستعلام إلى وقت الإدراج أو المعالجة المسبقة، ما يؤدي غالبًا إلى خفض كبير في زمن الاستجابة أثناء التشغيل. وبالنسبة إلى الاستعلامات التحليلية الفورية أو الحساسة لزمن الاستجابة، يُنصح بشدة بإزالة التطبيع. بوجه عام، استخدم إزالة التطبيع عندما:
  • تكون تغييرات الجداول غير متكررة أو عندما تكون عمليات التحديث الدفعي مقبولة.
  • لا تكون العلاقات من متعدد إلى متعدد، أو لا تكون ذات كاردينالية مرتفعة بشكل مفرط.
  • لن يُستعلَم إلا عن مجموعة فرعية محدودة من الأعمدة، أي يمكن استبعاد أعمدة معيّنة من إزالة التطبيع.
  • تكون لديك القدرة على نقل المعالجة خارج ClickHouse إلى أنظمة المصدر مثل Flink، حيث يمكن إدارة الإثراء الفوري أو التسطيح.
ليست كل البيانات بحاجة إلى إزالة التطبيع — ركّز على الحقول التي يُستعلَم عنها كثيرًا. وفكّر أيضًا في العروض المادية لحساب القيم المجمّعة تدريجيًا بدلًا من تكرار الجداول الفرعية بالكامل. وعندما تكون تحديثات المخطط نادرة ويكون زمن الاستجابة عاملًا حاسمًا، توفّر إزالة التطبيع أفضل مفاضلة من حيث الأداء. للاطلاع على دليل كامل حول إزالة تطبيع البيانات في ClickHouse، راجع هنا.

عندما تكون عمليات JOIN مطلوبة

عندما تكون عمليات JOIN مطلوبة، تأكد من استخدام الإصدار 24.12 على الأقل، ويُفضَّل أحدث إصدار، إذ يواصل أداء JOIN التحسن مع كل إصدار جديد. واعتبارًا من ClickHouse 24.12، أصبح مخطط الاستعلام يضع تلقائيًا الجدول الأصغر على الجانب الأيمن من JOIN لتحقيق أفضل أداء — وهي مهمة كان لا بد من تنفيذها يدويًا في السابق. كما ستصل قريبًا تحسينات إضافية، منها pushdown أكثر فعالية لعوامل التصفية، وإعادة الترتيب التلقائي لعدة عمليات JOIN. اتبع أفضل الممارسات التالية لتحسين أداء JOIN:
  • تجنّب النواتج الديكارتية: إذا كانت قيمة في الجانب الأيسر تطابق عدة قيم في الجانب الأيمن، فستُرجع JOIN عدة صفوف — وهو ما يُعرف بالناتج الديكارتي. وإذا كانت حالة الاستخدام لديك لا تتطلب كل التطابقات من الجانب الأيمن، بل أي تطابق واحد فقط، فيمكنك استخدام عمليات JOIN من النوع ANY (مثل LEFT ANY JOIN). فهي أسرع وتستخدم ذاكرة أقل من عمليات JOIN العادية.
  • قلّل أحجام الجداول المنضمّة: يزداد زمن التنفيذ واستهلاك الذاكرة في عمليات JOIN تناسبيًا مع حجمَي الجدولين الأيسر والأيمن. ولتقليل كمية البيانات التي تعالجها JOIN، أضف شروط تصفية إضافية في العبارتين WHERE أو JOIN ON داخل الاستعلام. يدفع ClickHouse شروط التصفية إلى أعمق نقطة ممكنة في query plan، وغالبًا قبل عمليات JOIN. وإذا لم تُدفَع عوامل التصفية إلى الأسفل تلقائيًا (لأي سبب)، فأعد كتابة أحد جانبي JOIN على هيئة استعلام فرعي لفرض هذا الـ pushdown.
  • استخدم direct joins عبر القواميس عند الاقتضاء: تُنفَّذ عمليات JOIN القياسية في ClickHouse على مرحلتين: مرحلة build، حيث يُجرى التكرار على الجانب الأيمن لبناء hash table، تليها مرحلة probe، حيث يُجرى التكرار على الجانب الأيسر للعثور على الأطراف المطابقة في JOIN عبر عمليات lookup في hash table. إذا كان الجانب الأيمن قاموسًا أو table engine آخر بخصائص key-value (مثل EmbeddedRocksDB أو محرك الجدول Join)، فيمكن لـ ClickHouse استخدام خوارزمية join “direct”، ما يلغي فعليًا الحاجة إلى بناء hash table ويُسرّع query processing. يعمل ذلك مع JOIN من النوع INNER وLEFT OUTER، ويُفضَّل لأعباء العمل التحليلية real-time.
  • استفد من فرز الجداول في عمليات JOIN: يُرتَّب كل جدول في ClickHouse حسب أعمدة primary key الخاصة به. ويمكن الاستفادة من هذا الترتيب باستخدام ما يُعرف بخوارزميات sort-merge JOIN مثل full_sorting_merge وpartial_merge. وعلى عكس خوارزميات JOIN القياسية المعتمدة على hash tables (انظر أدناه: parallel_hash وhash وgrace_hash)، تقوم خوارزميات sort-merge JOIN أولًا بفرز الجدولين ثم دمجهما. وإذا كان الاستعلام يُجري JOIN على كلا الجدولين باستخدام أعمدة primary key الخاصة بكل منهما، فهناك تحسين في sort-merge يتخطى خطوة الفرز، مما يوفر وقت المعالجة ويقلل overhead.
  • تجنّب عمليات JOIN التي يحدث فيها spill إلى disk: قد تصبح الحالات الوسيطة في عمليات JOIN (مثل hash tables) كبيرة لدرجة أنها لا تعود تتسع في main memory. في هذه الحالة، سيُرجع ClickHouse افتراضيًا خطأ نفاد الذاكرة. بعض خوارزميات join (انظر أدناه)، مثل grace_hash وpartial_merge وfull_sorting_merge، قادرة على spill الحالات الوسيطة إلى disk ومواصلة تنفيذ الاستعلام. ومع ذلك، ينبغي استخدام خوارزميات join هذه بحذر، لأن الوصول إلى disk قد يبطئ query processing بشكل كبير. ونوصي بدلًا من ذلك بتحسين استعلام JOIN بطرق أخرى لتقليل حجم الحالات الوسيطة.
  • القيم الافتراضية كعلامات على عدم وجود تطابق في outer JOINs: تتضمن left/right/full outer joins جميع القيم من الجدول الأيسر أو الأيمن أو كليهما. وإذا لم يُعثر على طرف مطابق في JOIN داخل الجدول الآخر لبعض القيم، يستبدل ClickHouse هذا الطرف بعلامة خاصة. ويفرض معيار SQL أن تستخدم databases القيمة NULL بوصفها هذه العلامة. في ClickHouse، يتطلب هذا تغليف عمود النتيجة في Nullable، مما يضيف عبئًا إضافيًا على الذاكرة والأداء. وكبديل، يمكنك ضبط الإعداد join_use_nulls = 0 واستخدام default value لنوع بيانات عمود النتيجة بوصفها العلامة.
استخدم القواميس بحذرعند استخدام القواميس في عمليات JOIN في ClickHouse، من المهم فهم أنها، بحكم تصميمها، لا تسمح بالمفاتيح المكررة. أثناء تحميل البيانات، تُزال المفاتيح المكررة بصمت، ولا يُحتفَظ إلا بآخر قيمة جرى تحميلها لمفتاح معيّن. وهذا يجعل القواميس مثالية للعلاقات من واحد إلى واحد أو من متعدد إلى واحد، حيث تكون الحاجة إلى أحدث قيمة أو إلى القيمة المعتمدة فقط. لكن استخدام قاموس في علاقة من واحد إلى متعدد أو من متعدد إلى متعدد (مثل ربط الأدوار بالجهات الفاعلة، حيث يمكن أن تكون للجهة الفاعلة الواحدة عدة أدوار) سيؤدي إلى فقدان صامت للبيانات، لأن جميع الصفوف المتطابقة، باستثناء صف واحد، ستُستبعَد. لذلك، لا تُعد القواميس مناسبة للحالات التي تتطلب الحفاظ الكامل على العلاقات عند وجود عدة مطابقات. ولمعرفة المزيد عن الحالات التي تكون فيها القواميس مفيدة (ومتى لا تكون كذلك)، راجع أفضل ممارسات القواميس.

اختيار خوارزمية JOIN المناسبة

يدعم ClickHouse عدة خوارزميات JOIN توازن بين السرعة واستهلاك الذاكرة:
  • Parallel Hash JOIN (default): سريع للجداول الموجودة على الجانب الأيمن ذات الحجم الصغير إلى المتوسط والتي تتسع في الذاكرة.
  • Direct JOIN: مثالي عند استخدام القواميس (أو محركات الجداول الأخرى ذات خصائص key-value) مع INNER أو LEFT ANY JOIN — وهو أسرع أسلوب لعمليات lookup المباشرة، لأنه يلغي الحاجة إلى إنشاء hash table.
  • Full Sorting Merge JOIN: فعّال عندما يكون كلا الجدولين مرتَّبين حسب join key.
  • Partial Merge JOIN: يقلّل استهلاك الذاكرة إلى الحد الأدنى، لكنه أبطأ — وهو الأنسب لربط الجداول الكبيرة عند محدودية الذاكرة.
  • Grace Hash JOIN: مرن وقابل لضبط الذاكرة، ومناسب لمجموعات البيانات الكبيرة مع إمكانية ضبط خصائص الأداء.
يختلف دعم كل خوارزمية لأنواع JOIN. ويمكن العثور على قائمة كاملة بأنواع JOIN المدعومة لكل خوارزمية هنا.
يمكنك ترك ClickHouse يختار أفضل خوارزمية عبر ضبط join_algorithm = 'auto' (وهو الإعداد الافتراضي)، أو التحكّم بها صراحةً وفقًا لـ workload لديك. وإذا كنت بحاجة إلى اختيار خوارزمية JOIN لتحسين الأداء أو تقليل overhead الذاكرة، فنوصي بهذا الدليل. لتحقيق أفضل أداء:
  • اجعل استخدام عمليات JOIN في الحد الأدنى ضمن workloads عالية الأداء.
  • تجنّب استخدام أكثر من 3–4 joins في query واحدة.
  • أجرِ benchmark لخوارزميات مختلفة على بيانات حقيقية — إذ يختلف الأداء بحسب توزيع join key وحجم البيانات.
للمزيد حول استراتيجيات تحسين JOIN، وخوارزميات JOIN، وكيفية ضبطها، راجع وثائق ClickHouse وهذه سلسلة المدونات.
آخر تعديل في ٣ يوليو ٢٠٢٦