Skip to main content
محرك الجدول يخزّن سلسلة زمنية، أي مجموعة من القيم المرتبطة بطوابع زمنية ووسوم (أو تسميات):
هذه ميزة في private preview، وقد تتغير مستقبلًا على نحو غير متوافق مع الإصدارات السابقة. فعِّل استخدام محرك الجدول TimeSeries باستخدام الإعداد enable_time_series_table. أدخِل الأمر set enable_time_series_table = 1.
محرك الجدول TimeSeries متاح في ClickHouse Cloud كميزة في private preview. الخدمات المشارِكة في private preview لديها بالفعل الإعداد enable_time_series_table مهيَّأً. أما خدمات ClickHouse Cloud الأخرى فلا تتوفر لديها هذه التهيئة، ولا يمكنك تفعيل المحرك بنفسك على مثل هذه الخدمة.

الصياغة

للكلمة المفتاحية SAMPLES اسم مستعار هو DATA، وللكلمة المفتاحية METRIC FAMILIES اسم مستعار هو METRICS، وقد أُبقي على كليهما للحفاظ على التوافق مع الإصدارات السابقة. يُكتب تعريف الجدول الخاص بأي version أقدم من 4 باستخدام METRICS، حتى يتمكن خادم أقدم من قراءته.

الاستخدام

من الأسهل البدء بالإعدادات الافتراضية لكل شيء (يُسمح بإنشاء جدول TimeSeries من دون تحديد قائمة بالأعمدة):
بعد ذلك، يمكن استخدام هذا الجدول مع البروتوكولات التالية (يجب تعيين منفذ في تهيئة الخادم):

الأعمدة الخارجية

تُنشأ أعمدة جدول TimeSeries تلقائيًا. وهذه هي الأعمدة الخارجية؛ فهي لا تخزّن أي بيانات، وإنما توفّر فقط واجهة لـ SELECT/INSERT. وتُخزَّن البيانات الفعلية في الجداول الهدف. وفيما يلي قائمة الأعمدة الخارجية: مثال:
يُسمح بأن تكون القيمة metric_name فارغة عند الإدخال، ما يعني أن اسم المقياس يُحدَّد في tags ضمن __name__، على سبيل المثال:
لإدراج البيانات الوصفية للمقاييس، أدرِجها في الأعمدة metric_family وtype وunit وhelp:

تحديد الأعمدة الخارجية

يمكن إدراج العمود الخارجي samples صراحةً في عبارة CREATE TABLE لاستبدال نوعه الافتراضي Array(Tuple(DateTime64(3), Float64)) (كما يُقبل اسمه القديم time_series أيضاً). يستخرج ClickHouse نوعَي الطابع الزمني والقيمة scalar من الـ tuple ويُمرّرهما إلى جدول العينات الداخلي:
وهذا يعادل التصريح مباشرةً بأنواع أعمدة الطابع الزمني والقيمة في عبارة INNER COLUMNS الخاصة بجدول samples:
إذا استُخدمت الصيغتان كلتاهما ضمن عبارة CREATE TABLE نفسها، فيجب أن تتطابق الأنواع المُعلنة.

الجداول الهدف

لا يحتوي جدول TimeSeries على بيانات خاصة به، إذ يُخزَّن كل شيء في جداوله الهدف. وهذا يشبه طريقة عمل العرض المادي، مع فارق أن العرض المادي له جدول هدف واحد، بينما يحتوي جدول TimeSeries على ثلاثة جداول هدف إلزامية باسم samples وtags وعائلة المقياس، وجدول هدف اختياري لـ العينات الحديثة يكون مُمكّنًا افتراضيًا (انظر الإعداد recent_samples_ttl_seconds). يمكن تحديد الجداول الهدف صراحةً في استعلام CREATE TABLE أو يمكن لمحرك الجدول TimeSeries إنشاء الجداول الهدف الداخلية تلقائيًا. تُحوَّل الصفوف المُدرجة في جدول TimeSeries، وتُقسَّم إلى كتل، ثم تُدرج في هذه الجداول الهدف. الجداول الهدف هي كما يلي:

جدول العينات

يحتوي جدول samples على سلاسل زمنية مرتبطة بمعرّف معيّن. يجب أن يحتوي جدول samples على الأعمدة التالية: تستخدم الأعمدة التي ينشئها المحرك تلقائيًا برامج ترميز ضغط للسلاسل الزمنية: timestamp CODEC(Delta, T64, ZSTD(3)) وvalue CODEC(ALP, ZSTD(3)). بالكاد تُضغط الطوابع الزمنية شبه الرتيبة باستخدام برامج الترميز العامة، وقد تستحوذ لولا ذلك على معظم حجم جدول العينات على القرص. يفعّل المحرك ALP لجداول العينات الداخلية وجداول العينات الحديثة الخاصة به دون الحاجة إلى ضبط enable_alp_codec. انظر أيضًا ضبط أنواع الأعمدة.

جدول العينات الحديثة

جدول العينات الحديثة اختياري ومُفعّل افتراضيًا (راجع إعداد recent_samples_ttl_seconds؛ إذ يؤدي ضبطه على صفر إلى تعطيل الجدول). يحتوي على نسخة من العينات الأحدث من قيمة TTL التي يحددها هذا الإعداد، ويجب أن يتضمن الأعمدة نفسها الموجودة في جدول العينات. يستخدم العمود المُولَّد timestamp الترميز CODEC(Delta, T64, ZSTD(3))، ويستخدم العمود المُولَّد value الترميز CODEC(ALP, ZSTD(3)). تُكتب كل عينة مُدرجة في كلٍّ من جدول العينات وجدول العينات الحديثة. تقرأ الاستعلامات التي يقع نطاقها الزمني ضمن نافذة TTL من جدول العينات الحديثة بدلًا من جدول العينات الرئيسي لأنه أصغر بكثير (يمكن تعطيل ذلك باستخدام إعداد على مستوى الاستعلام time_series_prefer_recent_samples_table). تُشتق قيمة TTL لجدول العينات الحديثة الداخلي دائمًا من إعداد recent_samples_ttl_seconds.

جدول الوسوم

يحتوي جدول tags على المعرّفات المحسوبة لكل توليفة من اسم مقياس والوسوم. يجب أن يحتوي جدول tags على الأعمدة التالية: تحتوي جداول الوسوم الداخلية الجديدة من version 5 فما بعد، والتي تستخدم محركًا من عائلة MergeTree، على فهرس نصي معكوس على tags: INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs'). وهو يسرّع المطابقات التامة للوسوم مثل {job="api"} في PromQL عبر البحث عن المفتاح والقيمة معًا. أما المقارنات مع سلسلة فارغة فتطابق أيضًا الوسوم المفقودة ولا تستفيد من هذا الفهرس. تحلّ الفهارس الصريحة المعلَنة في TAGS INNER COLUMNS محل الفهرس الافتراضي. أما الجداول الموجودة وجداول الوسوم الخارجية فتحتفظ بفهارسها؛ ولتفعيله عليها، أضف الفهرس وجسّده على جدول الهدف الخاص بوسومها.

جدول عائلات المقاييس

يحتوي جدول metric families على بعض المعلومات حول عائلات المقاييس التي تُجمع، وأنواع تلك العائلات وأوصافها. عائلة المقياس هي مجموعة من المقاييس التي تحمل الاسم نفسه (الوسم __name__) والنوع نفسه، فعلى سبيل المثال المُدرَّج التكراري هو عائلة مقياس تتكون من عدة مقاييس. يجب أن يحتوي جدول metric families على الأعمدة التالية:

الإنشاء

توجد عدة طرق لإنشاء جدول باستخدام محرك الجدول TimeSeries. أبسط عبارة
سينشئ فعليًا الجدول التالي (يمكنك التحقق من ذلك بتنفيذ SHOW CREATE TABLE my_table):
لذلك، جرى إنشاء الأعمدة تلقائيًا، وهناك أيضًا أربعة جداول هدف داخلية، لكل منها تعريفات أعمدة خاصة مخزنة في عبارات INNER COLUMNS. وكُتب الإعداد recent_samples_ttl_seconds في عبارة SETTINGS بقيمته الافتراضية: يحدد الإعداد TTL لجدول العينات الحديثة، لذا تُثبَّت قيمته الفعلية عند الإنشاء. كما جرى تثبيت أحدث إصدار من المخطط في الإعداد version (انظر إصدارات المخطط). تحمل الجداول الهدف الداخلية أسماء مثل .inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx، و.inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx، و.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx، و.inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ولكل جدول هدف مجموعته الخاصة من الأعمدة:

إنشاء جدول AS جدول موجود

تنشئ العبارة CREATE TABLE new_table AS existing_table جدول TimeSeries مهيأً على غرار existing_table، الذي يجب أن يكون بدوره جدول TimeSeries. لا تُنسخ الأهداف الخارجية لـ existing_table؛ إذ يجب أن تعرّفها العبارة بنفسها. تنسخ العبارة من existing_table:
  • عبارة SETTINGS، باستثناء version: يحصل الجدول الجديد دائمًا على أحدث إصدار. تُدمج الإعدادات المكتوبة في العبارة نفسها مع الإعدادات المنسوخة بحسب الاسم، لذا يتقدم الإعداد المكتوب على الإعداد المنسوخ، ويؤدي name = DEFAULT إلى إعادة ضبط إعداد منسوخ إلى قيمته الافتراضية؛
  • عبارتا INNER COLUMNS وINNER ENGINE لكل جدول داخلي. يُحتفظ بالأعمدة المخصصة (مثل الأعمدة الإضافية والأعمدة التي تحتوي على برنامج ترميز الضغط أو تعبير DEFAULT) وأجزاء المحرك المخصصة (مثل محرك ذي arguments أو sorting key مخصص أو إعداد للمحرك)، بينما تُضبط الأعمدة وأجزاء المحرك الأخرى وفقًا لإعدادات الجدول الجديد، بحيث تسري، على سبيل المثال، قيم tags_to_columns أو aggregate_min_time_and_max_time أو tags_index_granularity المكتوبة في العبارة.
تُؤخذ أيضًا أنواع أعمدة id والطابع الزمني والقيمة، ونوع النسخ المتماثل للمحركات الداخلية (MergeTree، ReplicatedMergeTree أو SharedMergeTree) من existing_table، ما لم تعرّفها العبارة بنفسها. تُعاد إنشاء قائمة الأعمدة الخارجية ولا تُنسخ. يمكن استخدام جدول أنشأه إصدار أقدم من ClickHouse بصفته existing_table: يحصل الجدول الجديد على البنية الحالية، مثل نوع id الحالي وتعبير المعرّف الافتراضي.

ضبط أنواع الأعمدة

يمكنك ضبط أنواع الأعمدة في الجداول الهدف الداخلية باستخدام عبارة INNER COLUMNS. على سبيل المثال، لتخزين الطوابع الزمنية بالميكروثانية والقيم كـ Float32، استخدم:
يعني تحديد الأعمدة الداخلية دون برامج ترميز الضغط استخدام برنامج ترميز الضغط الافتراضي لها:

العمود id

يحتوي العمود id على معرّفات، ويُحتسب كل معرّف استنادًا إلى تركيبة من اسم المقياس والوسوم. يمكن تخصيص النوع وتعبير DEFAULT المستخدم لتوليد المعرّفات عبر العبارة TAGS INNER COLUMNS:
يمكن أن يكون العمود id من أي نوع غير Nullable قابل للمقارنة. يجب أن تتطابق أنواع id المُعلنة في الجدولين الداخليين samples وtags. إذا لم يتم تحديد التعبير DEFAULT للعمود id ولم يكن الإعداد id_generator مُعيَّنًا، فسيختار ClickHouse التعبير DEFAULT تلقائيًا بناءً على نوع id، ولكن فقط إذا كان نوع id أحد الأنواع UUID أو UInt64 أو UInt128 أو FixedString(16)، أو الأنواع نفسها المغلّفة بـLowCardinality، أو زوجًا من اثنين من هذه الأنواع. بالنسبة إلى هذا الزوج، يحسب التعبير المختار تلقائيًا تجزئةً لاسم المقياس في المكوّن الأول وتجزئةً لجميع الوسوم في المكوّن الثاني. يُبقي نوع المعرّف LowCardinality، مثل Tuple(UInt64, LowCardinality(UUID))، المعرّفات مُرمَّزة بالقاموس: إذ يخزّن جدول samples قواميس صغيرة لكل كتلة مع فهارس القاموس بدلًا من تكرار المعرّف الكامل في كل صف، مما يقلل كمية البيانات التي تقرؤها الاستعلامات. يوفّر الإعداد id_generator مستوى التخصيص نفسه من دون استخدام العبارة INNER COLUMNS:
إذا كان هذا الإعداد مُعيَّنًا، فسيُستخدم لتوليد id حتى إذا كانت قيمة DEFAULT الخاصة بالعمود تحتوي على تعبير مختلف. يمكن أيضًا تحديد نوع العمود id في الإعداد id_type بدلًا من العبارة INNER COLUMNS:
عندما يكون الإعداد id_generator مُعيَّنًا، يُسجَّل الإعداد id_type تلقائيًا عند CREATE، بحيث يحتفظ التعريف بالنوع الذي كُتب التعبير من أجله.

العمود tags

يحتوي العمود tags على جميع وسوم السلسلة الزمنية، بما في ذلك الوسم __name__ الذي يحتوي على اسم المقياس. يتيح الإعداد tags_to_columns تحديد وسم معيّن لتخزينه أيضًا في عمود منفصل بالإضافة إلى الخريطة داخل العمود tags:
ستضيف هذه العبارة العمودين instance وjob إلى جدول الوسوم الهدف الداخلي. ستُخزَّن قيم الوسمين instance وjob في العمودين المذكورين وفي العمود tags.
في الجداول التي أنشأتها إصدارات أقدم من ClickHouse، يحتوي العمود tags على الوسوم التي لا توجد لها أعمدة مخصصة فقط، ولا يتضمن اسم المقياس، بينما يكون العمود all_tags عمودًا مؤقتًا جرى ملؤه عند الإدراج بجميع الوسوم باستثناء اسم المقياس.

محركات الجداول الخاصة بالجداول الهدف الداخلية

تستخدم الجداول الهدف الداخلية، افتراضيًا، محركات الجداول التالية:
  • يستخدم جدول العينات محرك MergeTree;
  • يستخدم جدول العينات الحديثة محرك MergeTree مقسمًا إلى حاويات زمنية مدتها 5 ساعات (راجع إعداد recent_samples_partition_by) مع قيمة TTL مشتقة من إعداد recent_samples_ttl_seconds ومع تمكين ttl_only_drop_parts، بحيث تُحذف الأجزاء المنتهية الصلاحية كاملةً؛
  • يستخدم جدول الوسوم محرك AggregatingMergeTree لأن البيانات نفسها تُدرج في هذا الجدول غالبًا عدة مرات، لذا نحتاج إلى طريقة لإزالة التكرارات، وكذلك لأن التجميع مطلوب للعمودين min_time و max_time;
  • يستخدم جدول عائلات المقاييس محرك ReplacingMergeTree لأن البيانات نفسها تُدرج في هذا الجدول غالبًا عدة مرات، لذا نحتاج إلى طريقة لإزالة التكرارات.
تتبع عائلة محركات الجداول الداخلية المُنشأة إعداد مستوى الاستعلام default_table_engine: فعند استخدام default_table_engine = ReplicatedMergeTree أو SharedMergeTree، تستخدم الجداول الداخلية محركات Replicated أو Shared المقابلة. ومع default_table_engine = None (أو أي قيمة أخرى)، يجب تحديد محركات الجداول الداخلية صراحةً. يجب أن تكون جميع الجداول الداخلية من نفس نوع النسخ المتماثل: فإذا كان أحدها متماثلًا (أو مشتركًا)، يجب أن تكون الجداول الداخلية الأخرى متماثلة (أو مشتركة) أيضًا، وإلا فستتباين محتوياتها بين النسخ المتماثلة. على سبيل المثال، يتطلب تعريف SAMPLES INNER ENGINE = ReplicatedMergeTree(...) أن تكون المحركات الداخلية الأخرى متماثلة أيضًا - إما بتعريفها صراحةً أو بإنشائها باستخدام default_table_engine = ReplicatedMergeTree. كما يمكن استخدام محركات جداول أخرى للجداول الهدف الداخلية إذا تم تحديد ذلك:
يُبقي جدول الوسوم أعمدة الوسوم (والـ Map tags) خارج مفتاح الفرز الخاص به، وهو ما يرفضه AggregatingMergeTree افتراضيًا (راجع allow_dimensions_outside_sorting_key). وهذا آمن هنا لأن تلك الأعمدة تعتمد وظيفيًا على id، وهو جزء من مفتاح الفرز، لذا فإن جميع الصفوف التي تدمجها عملية دمج في الخلفية معًا تتشارك القيم نفسها. وعندما يُنشأ جدول الوسوم الداخلي أو يُحدَّد محركه inline كما هو موضح أعلاه، يضبط TimeSeries القيمة allow_dimensions_outside_sorting_key = 1 عليه تلقائيًا؛ أما بالنسبة إلى جدول الوسوم التجميعي الخارجي الذي يُنشأ يدويًا، فيجب عليك تعيين هذا الإعداد بنفسك.

الجداول الهدف الخارجية

يمكن إعداد جدول TimeSeries لاستخدام جدول أُنشئ يدويًا:
يمكن أيضًا استخدام جدول خارجي كهدف للعينات الحديثة (العبارة RECENT SAMPLES my_recent_samples_table). يجب أن يحتوي هذا الجدول على الأعمدة نفسها الموجودة في جدول عينات خارجي، وأن يحتفظ ببيانات لمدة لا تقل عن recent_samples_ttl_seconds ثانية، وتقع مسؤولية ذلك على عاتق المستخدم. يجب أن تتطابق أنواع أعمدة الجداول الخارجية (id وtimestamp وvalue وأعمدة <tag_value_column> المدرجة في tags_to_columns) مع ما كان جدول TimeSeries سيُنشئه داخليًا في الحالة العادية (راجع جدول العينات وجدول الوسوم وجدول عائلات المقاييس للاطلاع على قيود الأنواع). ويُبلَّغ عن أي عدم تطابق في الأنواع عند تنفيذ CREATE. يُسجَّل نوع عمود id في جدول الوسوم الخارجي والتعبير المولِّد للمعرّفات في الإعدادين id_type وid_generator عند تنفيذ CREATE (بدءًا من الإصدار 2)، بحيث يحتفظ بهما تعريف جدول TimeSeries: على سبيل المثال، يقرأ CREATE TABLE ... AS my_table نوع id من تعريف my_table دون قراءة جداوله الهدف الخارجية. وإذا لم يُحدَّد الإعداد id_generator، فيُعيَّن إلى DEFAULT المعرَّف في عمود id للجدول الخارجي (إن وجد)، وإلا فإلى المولِّد القياسي المشتق من نوع id. ويُستخدَم التعبير المسجَّل لتوليد id حتى إذا تغيّرت قيمة DEFAULT في الجدول الخارجي لاحقًا — راجع عمود id للتفاصيل.

تعديل الإعدادات

يمكن تغيير إعدادَين بعد CREATE:
  • id_generator
  • filter_by_min_time_and_max_time
لاحظ أن تغيير id_generator بعد وجود بيانات بالفعل في جدول الوسوم قد يؤدي إلى إنشاء معرّفات مختلفة لنفس تركيبة metric+tag — إذ تحتفظ الصفوف القديمة بمعرّفاتها القديمة، بينما تستخدم الصفوف الجديدة المولِّد الجديد. ولا يمكن تغيير الإعدادات الأخرى باستخدام ALTER ... MODIFY SETTING: فمعظمها يكون مدمجًا في مخطط الجداول الداخلية عند CREATE، كما أن الإعداد version يُثبَّت تلقائيًا عند CREATE ويُعرِّف المخطط نفسه (انظر إصدارات المخطط).

الإعدادات

فيما يلي قائمة بالإعدادات التي يمكن تحديدها عند تعريف جدول TimeSeries:

إصدارات المخطط

لا يزال محرك الجدول TimeSeries وطبقة تنفيذ PromQL قيد التطوير النشط: فمجموعة الجداول الهدف وبنيتها قد تتغيّر بين إصدارات ClickHouse. ولجعل مثل هذه التغييرات قابلة للاكتشاف، يخزّن كل جدول TimeSeries إصداره في الإعداد version. ويُثبَّت الإصدار تلقائيًا في استعلام CREATE عند إنشاء الجدول - وقيمته هي أحدث إصدار معروف للخادم (حاليًا 5) - ويبقى محفوظًا في بيانات الجدول الوصفية، ولا يمكن تغييره باستخدام ALTER. أما الجداول التي أُنشئت قبل أن يُضاف هذا الإعداد فتُعدّ من الإصدار 0. وفي الأحوال العادية يُستحسن إغفال هذا الإعداد في استعلام CREATE TABLE، فيحصل الجدول عندئذٍ على أحدث إصدار. ويُقبل تحديد version صراحةً إذا كان الخادم يدعم ذلك الإصدار؛ عندئذٍ يُعرَّف الجدول بالطريقة التي يعتمدها ذلك الإصدار (انظر سجل الإصدارات). ولا ينسخ CREATE TABLE ... AS other_table إصدار الجدول الآخر، انظر إنشاء جدول AS جدول موجود. يدعم الخادم نطاقًا من الإصدارات، وقد يختلف الحد الأدنى للإصدار بين القراءة عبر SELECT، والكتابة عبر INSERT أو بروتوكول remote-write الخاص بـ Prometheus، وتقييم PromQL (دوال الجداول prometheusQuery وprometheusQueryRange وtimeSeriesSelector، ولهجة promql، وواجهة برمجة تطبيقات الاستعلام عبر HTTP الخاصة بـ Prometheus):
  • إذا كان إصدار جدول TimeSeries أقدم مما يدعمه PromQL، تُرفض استعلامات PromQL التي تجري عليه. ويقترح الاستثناء إعادة إنشاء الجدول: أنشئ جدول TimeSeries جديدًا، وانسخ البيانات باستعلام INSERT ... SELECT، ثم استبدل الجدول القديم بالجديد.
  • إذا كان الإصدار أقدم من أن يُكتب فيه، تُرفض استعلامات INSERT وبروتوكول remote-write الخاص بـ Prometheus، بينما تظل استعلامات SELECT تعمل.
  • وإذا كان الإصدار أقدم من أن يدعمه الخادم أصلًا، يُرفض كل استعلام على الجدول (باستثناء SHOW CREATE TABLE وDETACH وDROP).

سجل الإصدارات

الدوال

فيما يلي قائمة بالدوال التي تقبل جدول TimeSeries كوسيطة:
آخر تعديل في ٢٦ سبتمبر ٢٠٢٦