Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

محرك الجدول SummingMergeTree

يرث هذا المحرك من MergeTree. ويتمثل الفرق في أنه عند دمج أجزاء البيانات في جداول SummingMergeTree، يستبدل ClickHouse جميع الصفوف التي لها المفتاح الأساسي نفسه (أو بدقة أكبر، مفتاح الترتيب نفسه) بصف واحد يحتوي على قيم مجمَّعة للأعمدة ذات نوع البيانات الرقمي. وإذا كان مفتاح الترتيب مُكوَّنًا بحيث تقابل قيمة مفتاح واحدة عددًا كبيرًا من الصفوف، فإن ذلك يقلل حجم التخزين بشكل كبير ويُسرّع استرجاع البيانات.

نوصي باستخدام هذا المحرك إلى جانب MergeTree. خزّن البيانات الكاملة في جدول MergeTree، واستخدم SummingMergeTree لتخزين البيانات المجمَّعة، على سبيل المثال عند إعداد التقارير. ويساعدك هذا النهج على تجنب فقدان بيانات قيّمة بسبب تكوين غير صحيح للمفتاح الأساسي.

إنشاء جدول

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = SummingMergeTree([columns])
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

للاطلاع على وصف معلمات الطلب، راجع وصف الطلب.

معلمات SummingMergeTree

الأعمدة

columns - عبارة عن tuple يحتوي على أسماء الأعمدة التي ستُجمَّع قيمها. معلمة اختيارية. يجب أن تكون الأعمدة من نوع بيانات رقمي، وألا تكون ضمن القسم أو مفتاح الترتيب.

إذا لم يتم تحديد columns، فسيُجمِّع ClickHouse القيم في جميع الأعمدة ذات نوع البيانات الرقمي غير الموجودة ضمن مفتاح الترتيب.

بنود الاستعلام

عند إنشاء جدول SummingMergeTree، تكون البنود نفسها مطلوبة، كما هو الحال عند إنشاء جدول MergeTree.

الطريقة المتقادمة لإنشاء جدول
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE [=] SummingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, [columns])

جميع المعلمات، باستثناء columns، لها المعنى نفسه كما في MergeTree.

  • columns — tuple تضم أسماء الأعمدة التي ستُجمع قيمها. هذه معلمة اختيارية. للاطلاع على الوصف، راجع النص أعلاه.

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

ضع في الاعتبار الجدول التالي:

CREATE TABLE summtt
(
    key UInt32,
    value UInt32
)
ENGINE = SummingMergeTree()
ORDER BY key

أدرِج البيانات فيه:

INSERT INTO summtt VALUES(1,1),(1,2),(2,1)

قد لا يحسب ClickHouse مجموع كل الصفوف بالكامل (انظر أدناه)، لذا نستخدم دالة تجميع sum وعبارة GROUP BY في الاستعلام.

SELECT key, sum(value) FROM summtt GROUP BY key
┌─key─┬─sum(value)─┐
│   2 │          1 │
│   1 │          3 │
└─────┴────────────┘

معالجة البيانات

عند إدخال البيانات في جدول، تُحفَظ كما هي. ويُجري ClickHouse عمليات دمج لأجزاء البيانات المُدخلة بشكل دوري، وعندها تُجمَع الصفوف التي لها المفتاح الأساسي نفسه وتُستبدَل بصف واحد في كل جزء بيانات ناتج.

يمكن لـ ClickHouse دمج أجزاء البيانات بحيث قد تحتوي أجزاء البيانات الناتجة المختلفة على صفوف لها المفتاح الأساسي نفسه، أي إن الجمع سيكون غير مكتمل. لذلك، يجب استخدام دالة التجميع sum() وعبارة GROUP BY في الاستعلام كما هو موضح في المثال أعلاه.

القواعد العامة للجمع

تُجمع القيم في الأعمدة ذات نوع البيانات الرقمي. وتُحدَّد مجموعة الأعمدة بواسطة المعلمة columns.

إذا كانت القيم تساوي 0 في جميع الأعمدة المخصّصة للجمع، يُحذف الصف.

إذا لم يكن العمود ضمن المفتاح الأساسي ولم تُجمع قيمه، فتُختار قيمة عشوائية من القيم الموجودة.

لا تُجمع القيم في الأعمدة الموجودة ضمن المفتاح الأساسي.

الجمع في أعمدة AggregateFunction

في الأعمدة من النوع AggregateFunction، يتصرف ClickHouse كما يتصرف محرك AggregatingMergeTree، إذ يجري التجميع وفقًا للدالة.

البُنى المتداخلة

يمكن أن يتضمن الجدول بُنى بيانات متداخلة تُعالَج بطريقة خاصة.

إذا كان اسم جدول متداخل ينتهي بـ Map وكان يحتوي على عمودين على الأقل يستوفيان المعايير التالية:

  • يكون العمود الأول رقميًا (*Int*, Date, DateTime) أو سلسلة نصية (String, FixedString)، ولنسمّه key،
  • وتكون الأعمدة الأخرى حسابية (*Int*, Float32/64)، ولنسمّها (values...)،

فعندئذٍ يُفسَّر هذا الجدول المتداخل على أنه تعيين من key => (values...)، وعند دمج صفوفه، تُدمَج عناصر مجموعتي البيانات بحسب key مع جمع قيم (values...) المقابلة.

أمثلة:

DROP TABLE IF EXISTS nested_sum;
CREATE TABLE nested_sum
(
    date Date,
    site UInt32,
    hitsMap Nested(
        browser String,
        imps UInt32,
        clicks UInt32
    )
) ENGINE = SummingMergeTree
PRIMARY KEY (date, site);

INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['Firefox', 'Opera'], [10, 5], [2, 1]);
INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['Chrome', 'Firefox'], [20, 1], [1, 1]);
INSERT INTO nested_sum VALUES ('2020-01-01', 12, ['IE'], [22], [0]);
INSERT INTO nested_sum VALUES ('2020-01-01', 10, ['Chrome'], [4], [3]);

OPTIMIZE TABLE nested_sum FINAL; -- emulate merge

SELECT * FROM nested_sum;
┌───────date─┬─site─┬─hitsMap.browser───────────────────┬─hitsMap.imps─┬─hitsMap.clicks─┐
│ 2020-01-01 │   10 │ ['Chrome']                        │ [4]          │ [3]            │
│ 2020-01-01 │   12 │ ['Chrome','Firefox','IE','Opera'] │ [20,11,22,5] │ [1,3,0,1]      │
└────────────┴──────┴───────────────────────────────────┴──────────────┴────────────────┘

SELECT
    site,
    browser,
    impressions,
    clicks
FROM
(
    SELECT
        site,
        sumMap(hitsMap.browser, hitsMap.imps, hitsMap.clicks) AS imps_map
    FROM nested_sum
    GROUP BY site
)
ARRAY JOIN
    imps_map.1 AS browser,
    imps_map.2 AS impressions,
    imps_map.3 AS clicks;

┌─site─┬─browser─┬─impressions─┬─clicks─┐
│   12 │ Chrome  │          20 │      1 │
│   12 │ Firefox │          11 │      3 │
│   12 │ IE      │          22 │      0 │
│   12 │ Opera   │           5 │      1 │
│   10 │ Chrome  │           4 │      3 │
└──────┴─────────┴─────────────┴────────┘

عند طلب البيانات، استخدم الدالة sumMap(key, value) لإجراء التجميع على Map.

بالنسبة إلى بنية البيانات المتداخلة، لا تحتاج إلى تحديد أعمدتها ضمن tuple الأعمدة المخصّص للجمع.

تجميع عناصر Tuple

عندما يكون الإعداد allow_tuple_element_aggregation ممكّنًا، تُسطَّح أعمدة Tuple تكراريًا بحيث يُجمَع كل عنصر طرفي فيها على حدة. يتيح لك ذلك تخزين عدة مقاييس في عمود Tuple واحد وجمعها عنصرًا بعنصر أثناء عمليات الدمج.

تنطبق القواعد نفسها على الأعمدة الفرعية المسطّحة كما تنطبق على الأعمدة العادية:

  • لا تُجمع إلا الأعمدة الفرعية الرقمية.
  • تُستثنى من الجمع الأعمدة الفرعية التابعة لـ Tuple ضمن مفتاح الفرز أو مفتاح التقسيم.
  • إذا تم تحديد columns، فلن تُجمع إلا الأعمدة الفرعية التابعة لأعمدة Tuple المُدرجة.
  • إذا أصبحت جميع الأعمدة الفرعية الرقمية في صف ما تساوي صفرًا بعد الجمع، فسيُحذف الصف.
CREATE TABLE summing_tuples
(
    key UInt32,
    metrics Tuple(
        impressions UInt64,
        clicks UInt64,
        nested Tuple(
            conversions UInt64
        )
    )
) ENGINE = SummingMergeTree()
ORDER BY key
SETTINGS allow_tuple_element_aggregation = 1;

INSERT INTO summing_tuples VALUES (1, (100, 10, (1)));
INSERT INTO summing_tuples VALUES (1, (200, 20, (3)));

OPTIMIZE TABLE summing_tuples FINAL;

SELECT key, metrics.impressions, metrics.clicks, metrics.nested.conversions FROM summing_tuples;
┌─key─┬─metrics.impressions─┬─metrics.clicks─┬─metrics.nested.conversions─┐
│   1 │                 300 │             30 │                          4 │
└─────┴─────────────────────┴────────────────┴────────────────────────────┘
Navigation