- في أي لحظة، قد يظل جدولك يحتوي على صفوف مكررة (صفوف لها مفتاح الفرز نفسه)
- يحدث الحذف الفعلي للصفوف المكررة أثناء دمج الأجزاء
- يجب أن تراعي استعلاماتك احتمال وجود صفوف مكررة
| يوفّر ClickHouse تدريبًا مجانيًا حول إزالة التكرار والعديد من الموضوعات الأخرى. وتُعد Deleting and Updating Data training module نقطة انطلاق جيدة. |
خيارات إزالة التكرار
-
محرك الجدول
ReplacingMergeTree: مع محرك الجدول هذا، تُزال الصفوف المكررة ذات مفتاح الترتيب نفسه أثناء عمليات الدمج. ويُعدReplacingMergeTreeخيارًا جيدًا لمحاكاة سلوك upsert (عندما تريد أن تُرجع الاستعلامات آخر صف تم إدراجه). -
طيّ الصفوف: يستخدم محركا الجدول
CollapsingMergeTreeوVersionedCollapsingMergeTreeمنطقًا يُلغى فيه صف موجود ويُدرج صف جديد. وهما أكثر تعقيدًا في التنفيذ منReplacingMergeTree، لكن يمكن أن تكون الاستعلامات وعمليات التجميع أبسط في الكتابة دون الحاجة إلى القلق بشأن ما إذا كانت البيانات قد دُمجت بالفعل أم لا. ويكون محركا الجدول هذان مفيدين عندما تحتاج إلى تحديث البيانات بشكل متكرر.
استخدام ReplacingMergeTree لعمليات upsert
views، أدرِج صفًا جديدًا بالمفتاح الأساسي نفسه (لاحظ القيم الجديدة للعمود views):
FINAL في استعلام SELECT، ما يؤدي إلى دمج منطقي لنتيجة الاستعلام:
يكون استخدام
FINAL مناسبًا إذا كانت كمية البيانات صغيرة. أما إذا كنت تتعامل مع كمية كبيرة من البيانات،
فربما لا يكون استخدام FINAL الخيار الأفضل. لنناقش خيارًا أفضل
للعثور على أحدث قيمة في عمود.تجنّب FINAL
views مرة أخرى لكلٍّ من الصفّين الفريدين:
FINAL).
FINAL، لنستخدم بعض منطق الأعمال — نحن نعلم أن العمود views يزداد دائماً، لذا يمكننا اختيار الصف ذي القيمة الأكبر باستخدام الدالة max بعد التجميع حسب الأعمدة المطلوبة:
FINAL.
تتوسع Deleting and Updating Data training module في شرح هذا المثال، بما في ذلك كيفية استخدام عمود version مع ReplacingMergeTree.
استخدام CollapsingMergeTree لتحديث الأعمدة بشكل متكرر
ALTER TABLE..UPDATE والاكتفاء بإدراج البيانات الجديدة إلى جانب البيانات الحالية. يمكننا إضافة عمود يوضح ما إذا كانت البيانات قديمة أم جديدة… وفي الواقع، يوجد بالفعل محرك جدول يطبق هذا السلوك بكفاءة كبيرة، لا سيما أنه يحذف البيانات القديمة تلقائيًا نيابةً عنك. لنرَ كيف يعمل ذلك.
لنفترض أننا نتتبع عدد مشاهدات تعليق على Hacker News باستخدام نظام خارجي، وكل بضع ساعات ندفع البيانات إلى ClickHouse. نريد حذف الصفوف القديمة وأن تمثل الصفوف الجديدة الحالة الجديدة لكل تعليق على Hacker News. يمكننا استخدام CollapsingMergeTree لتنفيذ هذا السلوك.
لنعرّف جدولًا لتخزين عدد المشاهدات:
hackernews_views يحتوي على عمود من النوع Int8 باسم sign، ويُشار إليه باسم عمود sign. اسم عمود الإشارة اختياري، لكن نوع البيانات Int8 مطلوب، ولاحظ أنه تم تمرير اسم العمود إلى مُنشئ جدول CollapsingMergeTree.
ما عمود الإشارة في جدول CollapsingMergeTree؟ إنه يمثّل حالة الصف، ولا يمكن أن تكون قيمة عمود الإشارة إلا 1 أو -1. وإليك آلية عمله:
- إذا كان لصفَّين المفتاح الأساسي نفسه (أو ترتيب الفرز إذا كان مختلفًا عن المفتاح الأساسي)، لكن كانت قيم عمود الإشارة فيهما مختلفة، فإن آخر صف أُدرج بقيمة +1 يصبح صف الحالة، وتُلغي الصفوف الأخرى بعضها بعضًا
- تُحذف الصفوف التي يُلغي بعضها بعضًا أثناء عمليات الدمج
- تُحتفَظ بالصفوف التي لا تملك زوجًا مطابقًا
hackernews_views. وبما أنه الصف الوحيد لهذا المفتاح الأساسي، فسنضبط حالته على 1:
(123, 'ricardo'):
FINAL يُرجع صف الحالة الحالي:
FINAL مع الجداول الكبيرة.
القيمة المُمرَّرة للعمود
views في مثالنا ليست مطلوبة فعليًا، ولا يلزم أن تتطابق مع القيمة الحالية لـ views في الصف القديم. بل يمكنك في الواقع إلغاء صف باستخدام المفتاح الأساسي فقط والقيمة -1:تحديثات آنية من خيوط تنفيذ متعددة
CollapsingMergeTree، تُلغي الصفوف بعضها بعضًا باستخدام عمود الإشارة، وتُحدَّد حالة الصف بناءً على آخر صف تم إدراجه. لكن قد يصبح هذا إشكاليًا إذا كنت تُدرِج الصفوف من خيوط تنفيذ مختلفة، إذ قد تُدرَج الصفوف بترتيب غير متسق. لذلك فإن الاعتماد على الصف “الأخير” لا ينجح في هذه الحالة.
وهنا تبرز فائدة VersionedCollapsingMergeTree — فهو يطوي الصفوف مثل CollapsingMergeTree تمامًا، لكنه بدلًا من الاحتفاظ بآخر صف تم إدراجه، يحتفظ بالصف ذي أعلى قيمة في عمود الإصدار الذي تحدده.
لنلقِ نظرة على مثال. لنفترض أننا نريد تتبّع عدد مشاهدات تعليقات Hacker News لدينا، وأن البيانات تتحدّث باستمرار. نريد أن تستخدم التقارير أحدث القيم من دون فرض عمليات الدمج أو انتظار اكتمالها. نبدأ بجدول مشابه لـ CollapsedMergeTree، لكننا نضيف عمودًا لتخزين إصدار حالة الصف:
VersionsedCollapsingMergeTree كمحرّك، ويحدّد عمود الإشارة وعمود الإصدار. إليك كيفية عمل الجدول:
- يحذف كل زوج من الصفوف لهما المفتاح الأساسي نفسه والإصدار نفسه، مع اختلاف الإشارة
- لا يهم الترتيب الذي أُدرجت به الصفوف
- لاحظ أنه إذا لم يكن عمود الإصدار جزءًا من المفتاح الأساسي، فإن ClickHouse يضيفه ضمنيًا إلى المفتاح الأساسي باعتباره الحقل الأخير
hackernews_views_vcmt:
VersionedCollapsingMergeTree مفيدًا جدًا عندما تريد تطبيق إزالة التكرار أثناء إدراج الصفوف من عدة عملاء و/أو خيوط تنفيذ.
لماذا لا تُزال الصفوف المكررة من صفوفي؟
INSERT. على سبيل المثال، إذا كنت تُدرج صفوفًا مع العمود createdAt DateTime64(3) DEFAULT now()، فستكون صفوفك فريدة حتمًا لأن كل صف سيحصل على قيمة افتراضية فريدة للعمود createdAt. ولن يتمكن محرك الجدول MergeTree / ReplicatedMergeTree من إزالة التكرار من الصفوف، لأن كل صف مُدرج سينتج عنه checksum فريد.
في هذه الحالة، يمكنك تحديد insert_deduplication_token خاص بك لكل دفعة من الصفوف لضمان ألا تؤدي عمليات الإدراج المتعددة للدفعة نفسها إلى إعادة إدراج الصفوف نفسها. يُرجى الاطلاع على الوثائق الخاصة بـ insert_deduplication_token لمزيد من التفاصيل حول كيفية استخدام هذا الإعداد.