Skip to main content

الوصف

يرث المحرك CollapsingMergeTree من MergeTree ويضيف منطقًا لاختزال الصفوف أثناء عملية الدمج. يقوم محرك الجدول CollapsingMergeTree بحذف (اختزال) أزواج من الصفوف بشكل غير متزامن إذا كانت جميع الحقول في مفتاح الفرز (ORDER BY) متطابقة، باستثناء الحقل الخاص Sign، الذي يمكن أن تكون قيمته 1 أو -1. ويُحتفَظ بالصفوف التي لا يقابلها صف ذو قيمة Sign معاكسة. لمزيد من التفاصيل، راجع قسم Collapsing في الوثيقة.
قد يقلّل هذا المحرك بشكل كبير من حجم التخزين، مما يزيد بالتبعية من كفاءة استعلامات SELECT.

المعلمات

جميع معلمات محرك الجدول هذا، باستثناء المعلمة Sign، لها المعنى نفسه كما في MergeTree.
  • Sign — الاسم المُعطى لعمود يحدد نوع الصف، بحيث تكون القيمة 1 صف «حالة»، وتكون القيمة -1 صف «إلغاء». النوع: Int8.

إنشاء جدول

  • للحصول على وصف لمعلمات الاستعلام، راجع وصف الاستعلام.
  • عند إنشاء جدول CollapsingMergeTree، تكون بنود الاستعلام نفسها مطلوبة، كما هو الحال عند إنشاء جدول MergeTree.

اختزال

البيانات

افترض حالة تحتاج فيها إلى حفظ بيانات تتغير باستمرار لكائن معيّن. قد يبدو من المنطقي أن يكون هناك صف واحد لكل كائن وتحديثه كلما تغيّر شيء ما، لكن عمليات التحديث مكلفة وبطيئة بالنسبة إلى نظام إدارة قواعد البيانات، لأنها تتطلب إعادة كتابة البيانات في التخزين. إذا كنا بحاجة إلى كتابة البيانات بسرعة، فإن إجراء أعداد كبيرة من عمليات التحديث ليس نهجًا مقبولًا، لكن يمكننا دائمًا كتابة تغييرات الكائن بشكل تسلسلي. وللقيام بذلك، نستخدم العمود الخاص Sign.
  • إذا كانت قيمة Sign = 1 فهذا يعني أن الصف هو صف “حالة”: صف يحتوي على حقول تمثل الحالة الحالية الصالحة.
  • إذا كانت قيمة Sign = -1 فهذا يعني أن الصف هو صف “إلغاء”: صف يُستخدم لإلغاء حالة كائن له السمات نفسها.
على سبيل المثال، نريد حساب عدد الصفحات التي تصفحها المستخدمون على موقع ويب ما، والمدة التي قضوها في زيارتها. وفي لحظة زمنية معيّنة، نكتب الصف التالي الذي يمثل حالة نشاط المستخدم:
لاحقًا، نسجّل التغيّر في نشاط المستخدم وندوّنه في الصفّين التاليين:
يلغي الصف الأول الحالة السابقة للكائن (الذي يمثّل مستخدمًا في هذه الحالة). يجب أن ينسخ جميع حقول مفتاح الفرز الخاصة بالصف “الملغى” باستثناء Sign. يحتوي الصف الثاني أعلاه على الحالة الحالية. وبما أننا نحتاج فقط إلى آخر حالة لنشاط المستخدم، يمكن حذف صف “الحالة” الأصلي وصف “الإلغاء” الذي أدرجناه، كما هو موضح أدناه، مع اختزال الحالة غير الصالحة (القديمة) للكائن:
ينفّذ CollapsingMergeTree سلوك الاختزال هذا تحديدًا أثناء دمج أجزاء البيانات.
تُناقَش أسباب الحاجة إلى صفّين لكل تغيير بمزيد من التفصيل في فقرة Algorithm.
خصائص هذا النهج
  1. يجب أن يتذكّر البرنامج الذي يكتب البيانات حالة الكائن حتى يتمكّن من إلغائها. ويجب أن يحتوي صف “إلغاء” على نُسخ من حقول مفتاح الفرز الخاصة بـ “حالة”، مع قيمة Sign معاكسة. يزيد هذا من الحجم الأولي للتخزين، لكنه يتيح كتابة البيانات بسرعة.
  2. تؤدي المصفوفات الطويلة والمتزايدة في الأعمدة إلى تقليل كفاءة المحرّك بسبب زيادة العبء عند الكتابة. وكلما كانت البيانات أبسط، ارتفعت الكفاءة.
  3. تعتمد نتائج SELECT بدرجة كبيرة على اتساق سجل تغييرات الكائن. توخَّ الدقة عند إعداد البيانات لإدراجها. فقد تحصل على نتائج غير متوقعة إذا كانت البيانات غير متسقة. على سبيل المثال، قيم سالبة لمقاييس غير سالبة مثل عمق الجلسة.

الخوارزمية

عندما يدمج ClickHouse أجزاء البيانات، تُختزل كل مجموعة من الصفوف المتتالية التي لها مفتاح الفرز نفسه (ORDER BY) إلى ما لا يزيد على صفّين: صف “حالة” حيث Sign = 1، وصف “إلغاء” حيث Sign = -1. وبعبارة أخرى، في ClickHouse تُختزل الإدخالات. لكل جزء بيانات ناتج، يحفظ ClickHouse ما يلي: بالإضافة إلى ذلك، عندما يكون هناك صفّان إضافيان على الأقل من نوع “حالة” مقارنةً بصفوف “إلغاء”، أو صفّان إضافيان على الأقل من نوع “إلغاء” مقارنةً بصفوف “حالة”، تستمر عملية الدمج. ومع ذلك، يتعامل ClickHouse مع هذا الوضع على أنه خطأ منطقي ويسجّله في سجل الخادم. قد يحدث هذا الخطأ إذا أُدرجت البيانات نفسها أكثر من مرة. ولذلك، يجب ألا يغيّر الاختزال نتائج حساب الإحصاءات. وتُختزل التغييرات تدريجيًا بحيث لا تبقى في النهاية إلا الحالة الأخيرة لكل كائن تقريبًا. العمود Sign مطلوب لأن خوارزمية الدمج لا تضمن أن تكون جميع الصفوف ذات مفتاح الفرز نفسه في جزء البيانات الناتج نفسه، أو حتى على الخادم الفعلي نفسه. يعالج ClickHouse استعلامات SELECT باستخدام خيوط تنفيذ متعددة، ولا يمكنه التنبؤ بترتيب الصفوف في النتيجة. يلزم التجميع إذا كانت هناك حاجة إلى الحصول على بيانات “مختزلة” بالكامل من جدول CollapsingMergeTree. ولإتمام الاختزال، اكتب استعلامًا باستخدام عبارة GROUP BY ودوال التجميع التي تراعي الإشارة. فعلى سبيل المثال، لحساب العدد، استخدم sum(Sign) بدلًا من count(). ولحساب مجموع قيمة ما، استخدم sum(Sign * x) مع HAVING sum(Sign) > 0 بدلًا من sum(x) كما في المثال أدناه. يمكن حساب الدوال التجميعية count وsum وavg بهذه الطريقة. ويمكن حساب الدالة التجميعية uniq إذا كان للكائن حالة واحدة غير مختزلة على الأقل. أما الدالتان التجميعيتان min وmax فلا يمكن حسابهما لأن CollapsingMergeTree لا يحفظ سجل الحالات المختزلة.
إذا كنت بحاجة إلى استخراج البيانات من دون تجميع (على سبيل المثال، للتحقق مما إذا كانت الصفوف التي تتطابق أحدث قيمها مع شروط معيّنة موجودة)، فيمكنك استخدام المعدِّل FINAL لعبارة FROM. وسيؤدي ذلك إلى دمج البيانات قبل إرجاع النتيجة. وبالنسبة إلى CollapsingMergeTree، لا يُعاد إلا أحدث صف حالة لكل مفتاح.

أمثلة

مثال للاستخدام

إذا كانت لدينا بيانات المثال التالية:
لنُنشئ جدول UAct باستخدام CollapsingMergeTree:
بعد ذلك، سنُدرِج بعض البيانات:
نستخدم استعلامَي INSERT لإنشاء جزأَي بيانات مختلفين.
إذا أدرجنا البيانات باستعلام واحد فقط، فسينشئ ClickHouse جزء بيانات واحدًا فقط ولن يُجري أي عملية دمج مطلقًا.
يمكننا الاستعلام عن البيانات باستخدام:
لنلقِ نظرة على البيانات المُعادة أعلاه ولنرَ ما إذا كان الاختزال قد حدث… باستخدام استعلامَي INSERT، أنشأنا جزأين من البيانات. نُفِّذ استعلام SELECT على خيطَي تنفيذ، وحصلنا على ترتيب عشوائي للصفوف. ومع ذلك، لم يحدث الاختزال لأنه لم يكن هناك أي دمج لأجزاء البيانات بعد، كما أن ClickHouse يدمج أجزاء البيانات في الخلفية في وقت غير معلوم لا يمكننا التنبؤ به. لذلك نحتاج إلى تجميع، ونُجري ذلك باستخدام دالة التجميع sum وعبارة HAVING:
إذا لم نكن بحاجة إلى التجميع وأردنا فرض عملية الاختزال، فيمكننا أيضًا استخدام المُعدِّل FINAL مع عبارة FROM.
هذا الأسلوب في تحديد البيانات أقل كفاءة، ولا يُنصح باستخدامه مع الكميات الكبيرة من البيانات التي يجري فحصها (ملايين الصفوف).

مثال على نهج آخر

تقوم فكرة هذا النهج على أن عمليات الدمج لا تأخذ في الحسبان سوى حقول المفتاح. لذلك يمكننا، في الصف “إلغاء”، تحديد قيم سالبة تلغي أثر الإصدار السابق من الصف عند الجمع من دون استخدام العمود Sign. في هذا المثال، سنستخدم بيانات العينة الواردة أدناه:
في هذا النهج، يلزم تغيير أنواع البيانات للحقلين PageViews وDuration بحيث يمكن تخزين القيم السالبة. لذلك نغيّر نوعَي هذين العمودين من UInt8 إلى Int16 عند إنشاء الجدول UAct باستخدام collapsingMergeTree:
لنختبر هذا النهج عبر إدخال البيانات في جدولنا. ومع ذلك، يُعد ذلك مقبولًا في الأمثلة أو مع الجداول الصغيرة:
آخر تعديل في ٢٣ يوليو ٢٠٢٦