| إدخال | إخراج | اسم مستعار |
|---|---|---|
| ✔ | ✔ |
الوصف
Native متاحة هنا، كما تتوفر هنا المواصفة المرافقة لبروتوكول Native — أي بروتوكول TCP الذي ينقله.
جرى توليد كلتا المواصفتين بواسطة نماذج لغوية كبيرة انطلاقًا من الشيفرة المصدرية لـ ClickHouse. وتبقى الشيفرة المصدرية هي المرجع الأساسي: إذا وُجد اختلاف بين المواصفة والشيفرة، فالشيفرة هي الصحيحة.
Native أكثر تنسيقات ClickHouse كفاءة لأنه “عمودي” بالفعل
إذ لا يحوّل الأعمدة إلى صفوف.
في هذا التنسيق، تُكتب البيانات وتُقرأ على شكل كتل بتنسيق ثنائي.
ولكل كتلة، يُسجَّل عدد الصفوف، وعدد الأعمدة، وأسماء الأعمدة وأنواعها، وأجزاء الأعمدة في الكتلة، واحدًا تلو الآخر.
وهذا هو التنسيق المستخدم في الواجهة الأصلية للتفاعل بين الخوادم، ولاستخدام عميل سطر الأوامر، ولعملاء C++.
تنسيق أنواع البيانات wire
عند استخدام بروتوكول TCP الثنائي الأصلي (أو عندما تتلقى نقطة نهاية HTTP القيمة
?client_protocol_version=<n>)،
تُكتَب بنية BlockInfo قبل عدد الأعمدة والصفوف. وتستخدم الأمثلة في هذا القسم
واجهة HTTP العادية من دون إصدار للبروتوكول، ولذلك لا تتضمن BlockInfo.بنية الكتلة
number وstr، في ثلاثة صفوف:
كتل متعددة
أنواع البيانات البسيطة
RowBinary/RowBinaryWithNamesAndTypes.
تتضمن القائمة الكاملة للأنواع التي ينطبق عليها هذا الوصف ما يلي:
- (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256
- Float32, Float64
- Bool
- String
- FixedString(N)
- Date
- Date32
- DateTime
- DateTime64
- IPv4
- IPv6
- UUID
أنواع البيانات المعقدة
RowBinary وRowBinaryWithNamesAndTypes.
- Nullable
- LowCardinality
- Array
- Map
- Variant
- Dynamic
- JSON
Nullable
Native، يسبق البيانات الفعلية في العمود القابل لأن تكون قيمته NULL عددٌ من البايتات يساوي عدد الصفوف في الكتلة. ويشير كل بايت من هذه البايتات إلى ما إذا كانت القيمة NULL أم لا. على سبيل المثال، في هذا الاستعلام، ستكون كل قيمة فردية NULL بدلًا من ذلك:
Nullable(String). يأتي مؤشر null دائمًا من بايت قناع nullable —
فقيمة القناع 0x01 تعني أن الصف هو NULL بغضّ النظر عن محتوى السلسلة. بالنسبة إلى الصفوف ذات القيمة NULL،
تُخزَّن السلسلة الأساسية كسلسلة فارغة (طول LEB128 يساوي 0). لاحظ أن السلسلة الفارغة غير NULL
يكون طول LEB128 لها أيضًا 0، لذا فإن بايت القناع وحده هو ما يميّز بين الحالتين. على سبيل المثال، الاستعلام التالي:
LowCardinality
LowCardinality شفافًا، يستخدم تنسيق Native ترميزًا عموديًا قائمًا على القاموس. ويُرمَّز العمود على هيئة بادئة إصدار، ثم قاموس للقيم الفريدة، ثم Array من فهارس الأعداد الصحيحة التي تشير إلى ذلك القاموس.
يمكن تعريف العمود على أنه
LowCardinality(Nullable(T))، لكن لا يمكن تعريفه على أنه Nullable(LowCardinality(T)) — إذ يؤدي ذلك دائمًا إلى خطأ من الخادم.UInt64(LE) بقيمة 1، وتُكتب مرة واحدة لكل عمود. ثم، لكل كتلة، يُكتب ما يلي:
UInt64(LE)— حقل بتاتIndexesSerializationType. ترمّز البتات 0–7 عرض الفهرس (0 = UInt8، 1 = UInt16، 2 = UInt32، 3 = UInt64). ولا يُضبط البت 8 (NeedGlobalDictionaryBit) مطلقًا في تنسيق Native (ويُطلق الخادم استثناءً إذا تمت مصادفته). ويشير البت 9 إلى وجود مفاتيح إضافية في القاموس. ويشير البت 10 إلى أنه ينبغي إعادة تعيين القاموس.UInt64(LE)— عدد مفاتيح القاموس، تليه المفاتيح مُسلسلةً دفعةً واحدة باستخدام ترميز النوع الداخلي.UInt64(LE)— عدد الصفوف، تليه قيم الفهارس مُسلسلةً دفعةً واحدة باستخدام عرض UInt المناسب.
String و0 للأنواع الرقمية). وبالنسبة إلى LowCardinality(Nullable(T))، يمثّل الفهرس 0 القيمة NULL، وتُسلسَل المفاتيح من دون الغلاف Nullable.
على سبيل المثال، LowCardinality(String) مع 5 صفوف ['foo', 'bar', 'baz', 'foo', 'bar']:
LowCardinality(Nullable(String))، تكون القيمة عند الفهرس 0 هي NULL:
Array
- عدد N من إزاحات
UInt64التراكمية (بترتيب little-endian، 8 بايت لكل إزاحة). يحتوي الصفiعلىoffset[i] - offset[i-1]عنصرًا، مع اعتبارoffset[-1]مساويًا ضمنيًا لـ 0. - جميع العناصر المتداخلة عبر كل الصفوف، مُسلسلة دفعةً واحدة وبشكل متجاور.
Array(UInt32) مع 3 صفوف [[0, 10], [1, 11], [2, 12]]:
Array(String) مع 4 صفوف [[], ['0'], ['0','1'], ['0','1','2']]:
Map
Map(K, V) على شكل Array(Tuple(K, V)) — إزاحات المصفوفة، تليها جميع المفاتيح، ثم جميع القيم. ويختلف ذلك عن RowBinary، حيث تتعاقب المفاتيح والقيم في كل عنصر.
على سبيل المثال، Map(String, UInt64) مع 3 صفوف [{'a':0,'b':10}, {'a':1,'b':11}, {'a':2,'b':12}]:
Variant
Variant على النحو التالي:
- بادئة وضع المميِّزات
UInt64(LE)(0= BASIC،1= COMPACT). يستخدم خرج تنسيق Native عادةً BASIC (0)؛ وقد يظهر وضع COMPACT عند قراءة بيانات مخزَّنة مع تفعيلuse_compact_variant_discriminators_serialization. - N من المميِّزات
UInt8، واحد لكل صف. - بيانات كل variant type كـ عمود مجمّع منفصل لا يحتوي إلا على الصفوف المطابقة، وفق ترتيب المميِّزات.
Variant(String, UInt32) مع 5 صفوف [0::UInt32, 'hello', NULL, 3::UInt32, 'hello'] (مرتبة: String = 0، UInt32 = 1):
Dynamic
Dynamic كبادئة بنية تتبعها عمود Variant.
تحتوي بادئة البنية على إصدار التسلسل من نوع UInt64(LE)، ثم عدد الأنواع الديناميكية (بصيغة VarUInt)، ثم type names كسلاسل نصية. في الإصدار V1، يُكتَب عدد الأنواع مرتين لأغراض التوافق. أما البيانات التي تلي ذلك فهي عمود Variant تكون قائمة أنواعه هي الأنواع الديناميكية بالإضافة إلى النوع الداخلي SharedVariant، مرتبةً أبجديًا.
على سبيل المثال، Dynamic مع 5 صفوف [0::UInt32, 'hello', NULL, 3::UInt32, 'hello']:
JSON
JSON ببنية عمودية. ويكون هذا الترميز معقدًا ومعتمدًا على الإصدار: إذ يتكون من بادئة بنية تتضمن إصدار التسلسل، وأسماء المسارات الديناميكية، وتخطيط البيانات المشتركة، ثم تليها مسارات محددة النوع (كل منها على هيئة عمود مجمّع)، ومسارات ديناميكية (كل منها عمود Dynamic)، وبيانات مشتركة لمسارات overflow.
لتحقيق توافقية أبسط، يُنصح باستخدام الإعداد output_format_native_write_json_as_string=1، الذي يُسلسل أعمدة JSON كسلاسل نصية عادية بتنسيق JSON (قيمة String واحدة لكل صف).