متى تستخدم النوع JSON
JSON للاستعلام عن حقول محددة داخل كائنات JSON وتصفيتها وتجميعها عندما تكون بنيتها ديناميكية أو غير متوقعة. ويحقق ذلك عبر تقسيم كائنات JSON إلى أعمدة فرعية منفصلة، ما يقلل بدرجة كبيرة من حجم البيانات المقروءة ويُسرّع الاستعلامات على الحقول المحددة مقارنةً ببدائل مثل Map أو تحليل السلاسل النصية.
لكن هذا ينطوي على بعض المقايضات المهمة:
- بطء عمليات
INSERT- إن تقسيم JSON إلى أعمدة فرعية، وإجراء استنتاج النوع، وإدارة هياكل تخزين مرنة، يجعل عمليات الإدراج أبطأ مقارنةً بتخزين JSON في عمودStringبسيط. - بطء عند قراءة الكائنات كاملةً - إذا كنت بحاجة إلى استرجاع مستندات JSON كاملة (بدلاً من حقول محددة)، فإن النوع
JSONيكون أبطأ من القراءة من عمودString. فالعبء الإضافي الناتج عن إعادة تكوين الكائنات من الأعمدة الفرعية المنفصلة لا يحقق أي فائدة عندما لا تُجري استعلامات على مستوى الحقول. - عبء تخزيني إضافي - إن الاحتفاظ بأعمدة فرعية منفصلة يضيف عبئًا بنيويًا مقارنةً بتخزين JSON كسلسلة نصية واحدة.
استخدم النوع JSON عندما:
- تكون بياناتك ذات بنية ديناميكية أو غير متوقعة، مع مفاتيح تختلف من مستند إلى آخر
- تتغير أنواع الحقول أو البُنى بمرور الوقت أو تختلف بين السجلات
- تحتاج إلى الاستعلام أو التصفية أو التجميع على مسارات محددة داخل كائنات JSON التي لا يمكنك توقّع بنيتها مسبقًا
- تتضمن حالة الاستخدام لديك بيانات شبه مهيكلة مثل السجلات أو الأحداث أو المحتوى الذي ينشئه المستخدم، مع بُنى غير متسقة
استخدم عمود String (أو الأنواع المهيكلة) عندما:
- تكون بنية بياناتك معروفة ومتسقة — في هذه الحالة، استخدم الأعمدة العادية أو الأنواع
TupleوArrayوDynamicوVariantبدلًا من ذلك - تُعامَل مستندات
JSONعلى أنها blobs معتمة لا تُخزَّن ولا تُسترجَع إلا كاملةً، من دون تحليل على مستوى الحقول - لا تحتاج إلى إجراء استعلامات أو تصفية على حقول
JSONالفردية داخل قاعدة البيانات - يكون
JSONمجرد تنسيق للنقل/التخزين، ولا يُحلَّل داخل ClickHouse
اعتبارات ونصائح لاستخدام JSON
- حدِّد أنواع المسارات باستخدام تلميحات في تعريف العمود لتحديد أنواع الأعمدة الفرعية المعروفة، وتجنّب استدلال الأنواع غير الضروري.
- تخطَّ بعض المسارات إذا لم تكن بحاجة إلى قيمها، باستخدام SKIP و SKIP REGEXP لتقليل التخزين وتحسين الأداء.
- تجنّب ضبط
max_dynamic_pathsعلى قيمة مرتفعة جدًا—إذ تؤدي القيم الكبيرة إلى زيادة استهلاك الموارد وتقليل الكفاءة. وكقاعدة عامة، اجعله أقل من 10,000.
تلميحات الأنواعتوفّر تلميحات الأنواع أكثر من مجرد وسيلة لتجنّب استدلال الأنواع غير الضروري، إذ إنها تلغي بالكامل طبقة عدم المباشرة في التخزين والمعالجة. فمسارات JSON التي تتضمن تلميحات أنواع تُخزَّن دائمًا بالطريقة نفسها التي تُخزَّن بها الأعمدة التقليدية، من دون الحاجة إلى أعمدة التمييز أو التحليل الديناميكي وقت الاستعلام. وهذا يعني أنه عند تحديد تلميحات الأنواع بشكل جيد، تحقق حقول JSON المتداخلة الأداء والكفاءة نفسيهما كما لو أنها صُممت منذ البداية كحقول من المستوى الأعلى. ونتيجةً لذلك، بالنسبة إلى مجموعات البيانات المتسقة في معظمها مع الاستفادة في الوقت نفسه من مرونة JSON، توفّر تلميحات الأنواع وسيلة عملية للحفاظ على الأداء من دون الحاجة إلى إعادة هيكلة المخطط أو مسار إدخال البيانات.
الميزات المتقدمة
- يمكن استخدام أعمدة JSON في المفاتيح الأساسية مثل أي أعمدة أخرى. ولا يمكن تحديد خوارزميات الضغط لعمود فرعي.
- وهي تدعم الفحص الداخلي عبر دوال مثل
JSONAllPathsWithTypes()وJSONDynamicPaths(). - يمكنك قراءة الكائنات الفرعية المتداخلة باستخدام الصياغة
.^. - قد تختلف بنية الاستعلام عن SQL القياسية، وقد تتطلب تحويل أنواع خاصًا أو عوامل خاصة للحقول المتداخلة.
أمثلة
tags. إذا كانت هذه مجرد قائمة من السلاسل النصية، فيمكننا تمثيلها على أنها Array(String)، لكن لنفترض أنه يمكنك إضافة هياكل وسوم عشوائية بأنواع مختلطة (لاحظ أن score قد يكون سلسلة نصية أو عددًا صحيحًا). مستند JSON المعدَّل لدينا:
tags من نوع JSON. نوفّر كلا المثالين أدناه:
نقدّم تلميحًا للنوع للعمود
update_date في تعريف JSON، لأننا نستخدمه في الترتيب/المفتاح الأساسي. وهذا يساعد ClickHouse على معرفة أن هذا العمود لن تكون قيمته NULL، ويضمن أيضًا معرفة أي عمود فرعي update_date يجب استخدامه (إذ قد يوجد أكثر من عمود فرعي واحد لكل نوع، ولولا ذلك لكان الأمر ملتبسًا).JSONAllPathsWithTypes وoutput format PrettyJSONEachRow:
tags. ويُفضَّل هذا النهج عمومًا لأنه يقلّل من مقدار الاستدلال الذي يتطلبه ClickHouse:
tags.