ON CLUSTER، وهي موصوفة بشكل منفصل.
صيغة بناء الجملة
مع تحديد المخطط صراحةً
table_name في قاعدة البيانات db أو في قاعدة البيانات الحالية إذا لم يتم تعيين db، بالبنية المحددة بين الأقواس وباستخدام محرّك engine.
تتكون بنية الجدول من قائمة بأوصاف الأعمدة، والفهارس الثانوية، والإسقاطات، والقيود. إذا كان المفتاح الأساسي مدعومًا من قِبل المحرّك، فسيُشار إليه على أنه معلمة لمحرّك الجدول.
يكون وصف العمود، في أبسط الحالات، على الشكل name type. مثال: RegionID UInt32.
يمكن أيضًا تعريف تعبيرات للقيم الافتراضية (انظر أدناه).
عند الحاجة، يمكن تحديد المفتاح الأساسي باستخدام تعبير مفتاح واحد أو أكثر.
يمكن إضافة تعليقات إلى الأعمدة وإلى الجدول.
مع مخطط جدول موجود
باستخدام مخطط وبيانات جدول موجود
db.table. وبعبارة أخرى، تُستنسخ بيانات db.table إلى db2.table_clone عند إنشائه. وهذا الاستعلام مكافئ لما يلي:
db.table).
من table function
باستخدام استعلام SELECT
SELECT، باستخدام المحرك engine، ويملؤه ببيانات من SELECT. ويمكنك أيضًا تحديد وصف الأعمدة بشكل صريح.
إذا كان الجدول موجودًا بالفعل وتم تحديد IF NOT EXISTS، فلن ينفّذ الاستعلام أي إجراء.
يمكن أن تتضمن العبارة بنودًا أخرى بعد بند ENGINE. راجع الوثائق التفصيلية حول كيفية إنشاء الجداول في أوصاف محركات الجداول.
مثال
Query
Response
معدِّلات NULL أو NOT NULL
NULL وNOT NULL، اللذان يأتيان بعد نوع البيانات في تعريف العمود، بجعل النوع Nullable أو بعدم جعله كذلك.
إذا لم يكن النوع Nullable وتم تحديد NULL، فسيُعامل على أنه Nullable؛ أما إذا تم تحديد NOT NULL، فلن يُعامل كذلك. على سبيل المثال، INT NULL تعادل Nullable(INT). وإذا كان النوع Nullable وتم تحديد المعدِّلين NULL أو NOT NULL، فسيتم طرح استثناء.
انظر أيضًا إلى الإعداد data_type_default_nullable.
القيم الافتراضية
DEFAULT expr أو MATERIALIZED expr أو ALIAS expr. مثال: URLDomain String DEFAULT domain(URL).
يكون التعبير expr اختياريًا. وإذا أُهمل، فيجب تحديد نوع العمود صراحةً، وتكون القيمة الافتراضية 0 للأعمدة الرقمية، و'' (السلسلة الفارغة) لأعمدة السلاسل النصية، و[] (المصفوفة الفارغة) لأعمدة المصفوفات، و1970-01-01 لأعمدة التاريخ، أو NULL للأعمدة Nullable.
يمكن حذف نوع العمود في عمود ذي قيمة افتراضية، وفي هذه الحالة يُستدل عليه من نوع expr. على سبيل المثال، سيكون نوع العمود EventDate DEFAULT toDate(EventTime) هو التاريخ.
إذا جرى تحديد كلٍّ من نوع بيانات وتعبير قيمة افتراضية، فستُدرج دالة ضمنية لتحويل النوع تقوم بتحويل التعبير إلى النوع المحدد. مثال: Hits UInt32 DEFAULT 0 تُمثَّل داخليًا على النحو Hits UInt32 DEFAULT toUInt32(0).
يمكن أن يشير تعبير القيمة الافتراضية expr إلى أي أعمدة في الجدول وإلى الثوابت. ويتحقق ClickHouse من أن التغييرات في بنية الجدول لا تؤدي إلى ظهور حلقات في حساب التعبير. وبالنسبة إلى INSERT، فإنه يتحقق من أن التعابير قابلة للحل — أي إن جميع الأعمدة التي يمكن حسابها انطلاقًا منها قد تم تمريرها.
DEFAULT
DEFAULT expr
القيمة الافتراضية العادية. إذا لم تُحدَّد قيمة هذا العمود في استعلام INSERT، فستُحتسب من expr.
مثال:
MATERIALIZED
MATERIALIZED expr
تعبير MATERIALIZED. تُحتسب قيم هذه الأعمدة تلقائيًا وفقًا لتعبير MATERIALIZED المحدد عند إدراج الصفوف. ولا يمكن تحديد هذه القيم صراحةً أثناء عمليات INSERT.
كذلك، لا تُدرج الأعمدة ذات القيم الافتراضية من هذا النوع في نتيجة SELECT *. والغرض من ذلك هو الحفاظ على الثابت الذي ينص على أن نتيجة SELECT * يمكن دائمًا إدراجها مرة أخرى في الجدول باستخدام INSERT. ويمكن تعطيل هذا السلوك باستخدام الإعداد asterisk_include_materialized_columns.
مثال:
EPHEMERAL
EPHEMERAL [expr]
عمود مؤقت. الأعمدة من هذا النوع لا تُخزَّن في الجدول، ولا يمكن إجراء SELECT عليها. والغرض الوحيد من الأعمدة المؤقتة هو إنشاء تعبيرات القيم الافتراضية لأعمدة أخرى بالاعتماد عليها.
أي عملية إدراج لا تُحدَّد فيها الأعمدة صراحةً ستتجاوز الأعمدة من هذا النوع. وذلك للحفاظ على الثابت القائل إن نتيجة SELECT * يمكن دائمًا إدراجها مجددًا في الجدول باستخدام INSERT.
مثال:
ALIAS
ALIAS expr
الأعمدة المحسوبة (مرادف). الأعمدة من هذا النوع لا تُخزَّن في الجدول، ولا يمكن إدراج قيم فيها باستخدام INSERT.
عندما تشير استعلامات SELECT صراحةً إلى أعمدة من هذا النوع، تُحتسَب القيمة وقت الاستعلام من expr. افتراضيًا، يستبعد SELECT * أعمدة ALIAS. ويمكن تعطيل هذا السلوك باستخدام الإعداد asterisk_include_alias_columns.
عند استخدام استعلام ALTER لإضافة أعمدة جديدة، لا تُكتب البيانات القديمة لهذه الأعمدة. وبدلًا من ذلك، عند قراءة البيانات القديمة التي لا تحتوي على قيم للأعمدة الجديدة، تُحتسَب التعبيرات تلقائيًا افتراضيًا. ومع ذلك، إذا كان تقييم هذه التعبيرات يتطلب أعمدة أخرى غير مذكورة في الاستعلام، فستُقرأ هذه الأعمدة أيضًا، ولكن فقط لكتل البيانات التي تحتاج إلى ذلك.
إذا أضفت عمودًا جديدًا إلى جدول ثم غيّرت لاحقًا تعبيره الافتراضي، فستتغيّر القيم المستخدمة للبيانات القديمة (أي البيانات التي لم تُخزَّن قيمها على القرص). لاحظ أنه عند تنفيذ عمليات الدمج في الخلفية، تُكتب بيانات الأعمدة المفقودة في أحد الأجزاء التي يجري دمجها إلى الجزء المدمج.
لا يمكن تعيين قيم افتراضية لعناصر هياكل البيانات المتداخلة.
يمكنك تحديد مفتاح أساسي عند إنشاء جدول. ويمكن تحديد المفتاح الأساسي بإحدى طريقتين:
- ضمن قائمة الأعمدة
- خارج قائمة الأعمدة
القيود
CONSTRAINT
boolean_expr_1 أي تعبير Boolean. إذا كانت هناك قيود معرّفة للـ table، فسيتم التحقق من كل واحد منها لكل صف في استعلام INSERT. وإذا لم يُستوفَ أي قيد، فسيرفع server استثناءً يتضمن اسم القيد وتعبير التحقق.
قد تؤثر إضافة عدد كبير من القيود سلبًا في أداء استعلامات INSERT الكبيرة.
يمكن فحص القيود الموجودة في جميع الـ tables من خلال table system.constraints.
ASSUME
ASSUME لتعريف CONSTRAINT على جدول يُفترض أنها true. ويمكن للمُحسِّن بعد ذلك استخدام هذا القيد لتحسين أداء استعلامات SQL.
خذ هذا المثال الذي يُستخدم فيه ASSUME CONSTRAINT عند إنشاء الجدول users_a:
ASSUME CONSTRAINT للتأكيد على أن الدالة length(name) تساوي دائمًا قيمة العمود name_len. وهذا يعني أنه كلما استُدعيت length(name) في استعلام، يمكن لـ ClickHouse استبدالها بـ name_len، ومن المفترض أن يكون ذلك أسرع لأنه يتجنب استدعاء الدالة length().
بعد ذلك، عند تنفيذ الاستعلام SELECT name FROM users_a WHERE length(name) < 5;، يمكن لـ ClickHouse تحسينه إلى SELECT name FROM users_a WHERE name_len < 5; بفضل ASSUME CONSTRAINT. وقد يجعل ذلك تنفيذ الاستعلام أسرع لأنه يتجنب حساب طول name لكل صف.
ASSUME CONSTRAINT لا يفرض القيد، بل يقتصر على إبلاغ المُحسِّن بأن القيد صحيح. وإذا لم يكن القيد صحيحًا بالفعل، فقد تكون نتائج الاستعلامات غير صحيحة. لذلك، ينبغي ألا تستخدم ASSUME CONSTRAINT إلا إذا كنت متأكدًا من صحة هذا القيد.
تعبير TTL
ترميزات ضغط الأعمدة
lz4 في الإصدار المُدار ذاتيًا، وzstd في ClickHouse Cloud.
بالنسبة إلى عائلة المحرك MergeTree، يمكنك تغيير طريقة الضغط الافتراضية في قسم compression من تهيئة الخادم.
يمكنك أيضًا تحديد طريقة الضغط لكل عمود على حدة في استعلام CREATE TABLE.
Default للإشارة إلى الضغط الافتراضي، والذي قد يعتمد على إعدادات مختلفة (وخصائص البيانات) أثناء وقت التشغيل.
مثال: value UInt64 CODEC(Default) — وهو مماثل لعدم تحديد أي ترميز.
يمكنك أيضًا إزالة CODEC الحالي من العمود واستخدام الضغط الافتراضي من config.xml:
CODEC(Delta, Default).
الضغط مدعوم لمحركات الجداول التالية:
- عائلة MergeTree. تدعم برامج ترميز ضغط الأعمدة وإمكانية اختيار طريقة الضغط الافتراضية عبر إعدادات compression.
- عائلة Log. تستخدم طريقة الضغط
lz4افتراضيًا، وتدعم برامج ترميز ضغط الأعمدة. - Set. يدعم الضغط الافتراضي فقط.
- Join. يدعم الضغط الافتراضي فقط.
برامج الترميز للأغراض العامة
NONE
NONE — بدون ضغط.
LZ4
LZ4 — خوارزمية ضغط بيانات بلا فقدان تُستخدم افتراضيًا. تطبّق ضغط LZ4 السريع.
LZ4HC
LZ4HC[(level)] — خوارزمية LZ4 HC (ضغط عالٍ) بمستوى قابل للضبط. المستوى الافتراضي: 9. يطبّق ضبط level <= 0 المستوى الافتراضي. المستويات الممكنة: [1, 12]. النطاق الموصى به للمستوى: [4, 9].
ZSTD
ZSTD[(level)] — خوارزمية ضغط ZSTD مع level قابل للضبط. المستويات الممكنة: [1, 22]. المستوى الافتراضي: 1.
تكون مستويات الضغط العالية مفيدة في السيناريوهات غير المتناظرة، مثل الضغط مرة واحدة وفك الضغط مرارًا. وتعني المستويات الأعلى ضغطًا أفضل وزيادة في استخدام CPU.
متقادِم: ZSTD_QAT
متقادم: DEFLATE_QPL
برامج الترميز المتخصصة
Delta
Delta(delta_bytes) — أسلوب ضغط تُستبدل فيه القيم الخام بالفارق بين قيمتين متجاورتين، باستثناء القيمة الأولى التي تبقى دون تغيير. يمثّل delta_bytes الحد الأقصى لحجم القيم الخام، والقيمة الافتراضية هي sizeof(type). لم يعد يُنصح بتحديد delta_bytes كـ argument، وسيُزال الدعم له في إصدار مستقبلي. يُعد Delta ترميزًا لإعداد البيانات، أي لا يمكن استخدامه بصورة مستقلة.
DoubleDelta
DoubleDelta(bytes_size) — يحسب فروق الفروق (delta of deltas) ويكتبها بصيغة ثنائية مضغوطة. يحمل bytes_size معنى مشابهًا لـ delta_bytes في ترميز Delta. لم يعد يُنصح بتحديد bytes_size كوسيط، وستُزال هذه الإمكانية في إصدار مستقبلي. تتحقق أفضل معدلات الضغط مع المتتاليات الرتيبة ذات الخطوة الثابتة، مثل بيانات السلاسل الزمنية. ويمكن استخدامه مع أي نوع رقمي. يطبّق الخوارزمية المستخدمة في Gorilla TSDB، مع توسيعها لدعم الأنواع ذات 64 بت. ويستخدم 1 بت إضافيًا لفروق 32 بت: بادئات من 5 بت بدلًا من بادئات من 4 بت. لمزيد من المعلومات، راجع Compressing Time Stamps في Gorilla: A Fast, Scalable, In-Memory Time Series Database. يُعد DoubleDelta ترميزًا لإعداد البيانات، أي لا يمكن استخدامه بصورة مستقلة.
GCD
GCD() - - يحسب القاسم المشترك الأكبر (GCD) للقيم في العمود، ثم يقسم كل قيمة على GCD. يمكن استخدامه مع الأعمدة ذات القيم الصحيحة والعشرية وأعمدة التاريخ/الوقت. هذا الترميز مناسب جدًا للأعمدة التي تتغير قيمها (زيادةً أو نقصانًا) بمضاعفات GCD، مثل 24 و28 و16 و24 و8 و24 (GCD = 4). GCD هو ترميز لتهيئة البيانات، أي لا يمكن استخدامه بشكل مستقل.
Gorilla
Gorilla(bytes_size) — يحسب عملية XOR بين قيمة الفاصلة العائمة الحالية والسابقة، ويكتب النتيجة بصيغة ثنائية مدمجة. وكلما كان الفرق بين القيم المتتالية أصغر، أي كلما تغيّرت قيم السلسلة ببطء أكبر، كان معدل الضغط أفضل. يطبّق الخوارزمية المستخدمة في Gorilla TSDB، مع توسيعها لدعم الأنواع ذات 64 بت. قيم bytes_size الممكنة هي: 1 و2 و4 و8، وتكون القيمة الافتراضية sizeof(type) إذا كانت مساوية لـ 1 أو 2 أو 4 أو 8. وفي جميع الحالات الأخرى، تكون 1. لمزيد من المعلومات، راجع القسم 4.1 من Gorilla: A Fast, Scalable, In-Memory Time Series Database.
ALP
ALP() — ضغط تكيّفي بلا فقدان لبيانات الفاصلة العائمة، يعتمد على التحجيم العشري. يحاول ALP تمثيل كل قيمة كعدد صحيح مُحجَّم بدقة باستخدام قوى العدد 10، ثم يضغط الأعداد الصحيحة الناتجة باستخدام Frame-of-Reference وbit-packing. وتُخزَّن القيم التي يتعذر تمثيلها بدقة كاستثناءات خام. يعمل بأفضل كفاءة مع الأرقام المشتقة من القيم العشرية (مثل القياسات والعملات). ويدعم Float32 وFloat64. لمزيد من التفاصيل، راجع ALP: Adaptive lossless floating-point compression.
هذا الترميز تجريبي، ويتطلب
SET allow_experimental_codecs = 1 لاستخدامه.FPC
FPC(level, float_size) - يتنبأ بشكل متكرر بالقيمة التالية ذات الفاصلة العائمة في التسلسل باستخدام الأفضل من بين متنبئين، ثم يُجري XOR بين القيمة الفعلية والقيمة المتنبأ بها، ويضغط النتيجة باستخدام ضغط الأصفار البادئة. وعلى غرار Gorilla، يكون هذا فعالًا عند تخزين سلسلة من القيم ذات الفاصلة العائمة التي تتغير ببطء. بالنسبة إلى القيم ذات 64 بت (double)، يكون FPC أسرع من Gorilla، أما بالنسبة إلى القيم ذات 32 بت فقد يختلف الأداء. قيم level الممكنة هي: 1-28، والقيمة الافتراضية هي 12. قيم float_size الممكنة هي: 4، 8، والقيمة الافتراضية هي sizeof(type) إذا كان النوع Float. وفي جميع الحالات الأخرى، تكون 4. للاطلاع على وصف مفصل للخوارزمية، انظر High Throughput Compression of Double-Precision Floating-Point Data.
T64
T64 — أسلوب ضغط يقتطع البتات العليا غير المستخدمة من القيم في أنواع البيانات الصحيحة (بما في ذلك Enum وDate وDateTime). في كل خطوة من خوارزميته، يأخذ الترميز block من 64 قيمة، ويضعها في مصفوفة بتات 64x64، ثم يجري لها عملية منقول، ويقتطع البتات غير المستخدمة من القيم، ويُرجع الباقي على شكل sequence. والبتات غير المستخدمة هي البتات التي لا تختلف بين القيمتين العظمى والدنيا في data part بالكامل الذي يُستخدم له الضغط.
يُستخدم ترميزا DoubleDelta وGorilla في Gorilla TSDB بوصفهما جزءًا من خوارزمية الضغط الخاصة به. ويكون نهج Gorilla فعّالًا في الحالات التي توجد فيها sequence من القيم التي تتغير ببطء مع timestamps الخاصة بها. وتُضغط timestamps بكفاءة باستخدام ترميز DoubleDelta، كما تُضغط القيم بكفاءة باستخدام ترميز Gorilla. على سبيل المثال، للحصول على table مخزّن بكفاءة، يمكنك إنشاؤه بالconfiguration التالية:
ترميزات التشفير
AES_128_GCM_SIV
CODEC('AES-128-GCM-SIV') — يشفّر البيانات باستخدام AES-128 في وضع GCM-SIV المحدد في RFC 8452.
AES-256-GCM-SIV
CODEC('AES-256-GCM-SIV') — يشفّر البيانات باستخدام AES-256 في وضع GCM-SIV.
تستخدم هذه الترميزات قيمة nonce ثابتة، ولذلك يكون التشفير حتميًا. وهذا يجعله متوافقًا مع المحركات التي تدعم إزالة التكرار مثل ReplicatedMergeTree، لكنه ينطوي على نقطة ضعف: فعند تشفير كتلة البيانات نفسها مرتين، سيكون النص المشفّر الناتج متطابقًا تمامًا، ما يتيح لجهة مهاجمة يمكنها قراءة القرص ملاحظة هذا التطابق (مع أنها لا ترى سوى التطابق نفسه من دون الوصول إلى المحتوى).
معظم المحركات، بما في ذلك عائلة “*MergeTree”، تنشئ ملفات الفهرسة على القرص من دون تطبيق الترميزات. وهذا يعني أن النص الصريح سيظهر على القرص إذا تمت فهرسة عمود مشفّر.
إذا نفّذت استعلام SELECT يذكر قيمة محددة في عمود مشفّر (مثلًا في عبارة WHERE الخاصة به)، فقد تظهر هذه القيمة في system.query_log. وقد ترغب في تعطيل التسجيل.
إذا لزم تطبيق الضغط، فيجب النصّ عليه صراحةً. وإلا فسيُطبَّق التشفير فقط على البيانات.
الجداول المؤقتة
يُرجى ملاحظة أن الجداول المؤقتة غير مكرّرة. ونتيجةً لذلك، لا يوجد ما يضمن أن تكون البيانات المُدرجة في جدول مؤقت متاحةً في النُسخ المتماثلة الأخرى. وتكون الجداول المؤقتة مفيدةً أساسًا عند الاستعلام عن مجموعات بيانات خارجية صغيرة أو ربطها خلال جلسة واحدة.
- تختفي الجداول المؤقتة عند انتهاء الجلسة، بما في ذلك عند فقدان الاتصال.
- يستخدم الجدول المؤقت محرك الجدول Memory إذا لم يتم تحديد engine، ويمكنه استخدام أي محرك جدول باستثناء Replicated و
KeeperMap. - لا يمكن تحديد DB لجدول مؤقت، إذ يُنشأ خارج databases.
- يستحيل إنشاء جدول مؤقت باستخدام استعلام DDL موزّع على جميع خوادم العنقود (باستخدام
ON CLUSTER)، لأن هذا الجدول لا يوجد إلا في الجلسة الحالية. - إذا كان لجدول مؤقت الاسم نفسه لجدول آخر، وكان الاستعلام يحدد اسم الجدول من دون تحديد DB، فسيُستخدم الجدول المؤقت.
- في معالجة الاستعلامات الموزعة، تُمرَّر الجداول المؤقتة ذات المحرك Memory المستخدمة في الاستعلام إلى الخوادم البعيدة.
(GLOBAL) IN الموزّع. لمزيد من المعلومات، راجع الأقسام ذات الصلة.
يمكن استخدام جداول ذات ENGINE = Memory بدلًا من الجداول المؤقتة.
REPLACE TABLE
REPLACE تحديث جدول ذرّياً.
هذه العبارة مدعومة لمحركَي قاعدة البيانات
Atomic وReplicated،
وهما محركا قاعدة البيانات الافتراضيان في ClickHouse وClickHouse Cloud على التوالي.SELECT لا تجلب البيانات غير المرغوب فيها،
ثم حذف الجدول القديم وإعادة تسمية الجدول الجديد.
يوضح المثال أدناه هذا الأسلوب:
REPLACE (إذا كنت تستخدم محركات قواعد البيانات الافتراضية) للحصول على النتيجة نفسها:
الصيغة
تعمل جميع صيغ بناء الجملة الخاصة بعبارة
CREATE أيضًا مع هذه العبارة. وسيؤدي استدعاء REPLACE على جدول غير موجود إلى حدوث خطأ.أمثلة:
- محلي
- Cloud
لنفترض الجدول التالي:يمكننا استخدام عبارة أو يمكننا استخدام عبارة
REPLACE لمسح جميع البيانات:REPLACE لتغيير بنية الجدول:جملة COMMENT
يجب تحديد بند
COMMENT بعد أي بنود خاصة بالتخزين، مثل PARTITION BY وORDER BY وSETTINGS الخاصة بالتخزين.بعد بند COMMENT، لن تُحلَّل إلا SETTINGS الخاصة بالاستعلام (مثل max_threads وما إلى ذلك)، وليس الإعدادات المرتبطة بالتخزين.وهذا يعني أن الترتيب الصحيح للبنود هو:ENGINE- بنود التخزين
COMMENT- إعدادات الاستعلام (إن وجدت)
Query
Response