Skip to main content
في الإصدار 24.3 من ClickHouse، كان المحلّل مفعّلًا افتراضيًا. يمكنك الاطّلاع على مزيد من التفاصيل حول كيفية عمله هنا.

حالات عدم التوافق المعروفة

على الرغم من إصلاح عدد كبير من الأخطاء وإضافة تحسينات جديدة، فإنه يقدّم أيضًا بعض التغييرات غير المتوافقة مع الإصدارات السابقة في سلوك ClickHouse. يُرجى قراءة التغييرات التالية لمعرفة كيفية إعادة كتابة استعلاماتك لتناسب المحلّل.

لم تعد الاستعلامات غير الصالحة تُحسَّن

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

المثال 1

يستخدم الاستعلام التالي العمود number في قائمة الإسقاط، مع أن المتاح بعد التجميع هو toString(number) فقط. في المحلّل القديم، كان GROUP BY toString(number) يُحسَّن إلى GROUP BY number,، مما يجعل الاستعلام صالحًا.

المثال 2

تحدث المشكلة نفسها في هذا الاستعلام. يُستخدَم العمود number بعد التجميع مع مفتاح آخر. كان محلّل الاستعلام السابق يُصحّح هذا الاستعلام بنقل عامل التصفية number > 5 من عبارة HAVING إلى عبارة WHERE.
لإصلاح الاستعلام، ينبغي نقل جميع الشروط التي تخص الأعمدة غير المجمّعة إلى قسم WHERE للامتثال لصياغة SQL القياسية:
لتسهيل الترحيل، يمكن لمحلّل الاستعلام تكرار إعادة الكتابة القديمة من HAVING إلى WHERE للمقترنات غير التجميعية المتصلة بـ AND. فعِّل analyzer_compatibility_allow_non_aggregate_in_having = 1 لتمكين هذا السلوك. هذا الإعداد متاح منذ ClickHouse 26.7. يُتجاهل هذا الإعداد مع WITH CUBE وWITH ROLLUP وWITH TOTALS وGROUPING SETS. تبقى المقترنات التي تحتوي على دوال تجميعية أو grouping أو دوال غير حتمية في HAVING؛ وإذا احتوى أي مقترن على دالة نافذة أو دالة ذات حالة (مثل rowNumberInBlock)، فستُعطَّل إعادة الكتابة لعبارة HAVING بالكامل، بما يطابق السلوك القديم.

CREATE VIEW مع استعلام غير صالح

يجري المحلِّل دائمًا التحقّق من الأنواع. في السابق، كان من الممكن إنشاء VIEW باستعلام SELECT غير صالح. ثم كان يفشل عند تنفيذ أول SELECT أو INSERT (في حالة MATERIALIZED VIEW). لم يعد إنشاء VIEW بهذه الطريقة ممكنًا.

مثال

أوجه عدم التوافق المعروفة لعبارة JOIN

JOIN باستخدام عمود من إسقاط

لا يمكن افتراضيًا استخدام اسم مستعار من قائمة SELECT كمفتاح JOIN USING. عند تمكين الإعداد الجديد analyzer_compatibility_join_using_top_level_identifier، فإنه يغيّر سلوك JOIN USING بحيث يفضّل تفسير المعرّفات استنادًا إلى التعبيرات الواردة في قائمة الإسقاط ضمن استعلام SELECT، بدلًا من استخدام أعمدة الجدول الأيسر مباشرةً. على سبيل المثال:
عند ضبط analyzer_compatibility_join_using_top_level_identifier على true، يُفسَّر شرط الـ join على أنه t1.a + 1 = t2.b، بما يتوافق مع سلوك الإصدارات السابقة. ستكون النتيجة 2, 'two'. وعندما تكون قيمة الإعداد false، يكون شرط الـ join افتراضيًا t1.b = t2.b، وسيُرجع الاستعلام 2, 'one'. إذا لم يكن b موجودًا في t1، فسيفشل الاستعلام مع ظهور خطأ.

تغيّرات في السلوك مع JOIN USING والأعمدة ALIAS/MATERIALIZED

في المُحلِّل، يؤدي استخدام * في استعلام JOIN USING يتضمن أعمدة ALIAS أو MATERIALIZED إلى إدراج هذه الأعمدة في مجموعة النتائج افتراضيًا. على سبيل المثال:
في المحلل، ستتضمن نتيجة هذا الاستعلام العمود payload إلى جانب id من كلا الجدولين. في المقابل، كان المحلل السابق لا يتضمن أعمدة ALIAS هذه إلا إذا كانت إعدادات محددة (asterisk_include_alias_columns أو asterisk_include_materialized_columns) مفعّلة، كما قد تظهر الأعمدة بترتيب مختلف. ولضمان الحصول على نتائج متسقة ومتوقعة، خاصةً عند ترحيل الاستعلامات القديمة إلى المحلل، يُنصح بتحديد الأعمدة صراحةً في عبارة SELECT بدلًا من استخدام *.

التعامل مع معدِّلات النوع للأعمدة في بند USING

في المحلّل، جرى توحيد قواعد تحديد النوع الأعلى المشترك للأعمدة المحددة في بند USING لإعطاء نتائج أكثر قابلية للتنبؤ، خصوصًا عند التعامل مع معدِّلات النوع مثل LowCardinality وNullable.
  • LowCardinality(T) وT: عند ضمّ عمود من النوع LowCardinality(T) إلى عمود من النوع T، سيكون النوع الأعلى المشترك الناتج هو T، ما يعني عمليًا تجاهل معدِّل LowCardinality.
  • Nullable(T) وT: عند ضمّ عمود من النوع Nullable(T) إلى عمود من النوع T، سيكون النوع الأعلى المشترك الناتج هو Nullable(T)، بما يضمن الحفاظ على خاصية قبول القيم NULL.
على سبيل المثال:
في هذا الاستعلام، يُحدَّد النوع الأعلى المشترك لـ id على أنه String، مع إسقاط المُعدِّل LowCardinality من t1.

تغييرات على أسماء أعمدة الإسقاط

أثناء حساب أسماء الإسقاطات، لا يجري استبدال الأسماء المستعارة.

أنواع وسائط الدالة غير المتوافقة

في المحلّل، يحدث استنتاج الأنواع أثناء تحليل الاستعلام الأوّلي. ويعني هذا التغيير أن عمليات التحقق من الأنواع تُجرى قبل التقييم المختصر؛ لذلك، يجب أن تمتلك وسائط الدالة if دائمًا نوعًا أعلى مشتركًا. على سبيل المثال، يفشل الاستعلام التالي مع There is no supertype for types Array(UInt8), String because some of them are Array and some of them are not:

العناقيد غير المتجانسة

يُحدِث المُحلِّل تغييرًا كبيرًا في بروتوكول الاتصال بين الخوادم داخل العنقود. لذلك، يتعذّر تشغيل الاستعلامات الموزعة على خوادم تستخدم قيماً مختلفة للإعداد enable_analyzer.

تُفسَّر عمليات التعديل بواسطة المحلّل السابق

لا تزال عمليات التعديل تستخدم المحلّل القديم. وهذا يعني أنه لا يمكن استخدام بعض ميزات ClickHouse SQL الجديدة في عمليات التعديل، مثل عبارة QUALIFY. يمكن الاطلاع على الحالة هنا.

الميزات غير المدعومة

فيما يلي قائمة بالميزات التي لا يدعمها المحلّل حاليًا:
  • فهرس Annoy.
  • فهرس Hypothesis. العمل جارٍ عليه هنا.
  • ميزة Window View غير مدعومة. ولا توجد خطط لدعمها مستقبلًا.

الترحيل إلى Cloud

نعمل على تمكين المحلّل في جميع المثيلات التي يكون معطّلًا فيها حاليًا، وذلك لدعم تحسينات جديدة في الوظائف والأداء. يفرض هذا التغيير قواعد أكثر صرامة لتحديد النطاق في SQL، ما يتطلب من العملاء تحديث الاستعلامات غير المتوافقة يدويًا.

سير عمل الترحيل

  1. حدِّد الاستعلام بتصفية system.query_log باستخدام normalized_query_hash:
  1. نفّذ الاستعلام بعد تفعيل المحلّل بإضافة هذه الإعدادات.
  1. أعد صياغة الاستعلام وتحقّق من نتائج الاستعلام للتأكد من أنها تطابق المخرجات الناتجة عند تعطيل المحلِّل.
يُرجى الرجوع إلى أكثر حالات عدم التوافق شيوعًا التي ظهرت أثناء الاختبارات الداخلية.

معرّف تعبير غير معروف

الخطأ: Unknown expression identifier ... in scope ... (UNKNOWN_IDENTIFIER). رمز الاستثناء: 47 السبب: تُعرَّف الآن الاستعلامات التي تعتمد على سلوكيات قديمة متساهلة وغير قياسية — مثل الإشارة إلى الأسماء المستعارة المحسوبة داخل عوامل التصفية، أو عناصر الإسقاط الملتبسة في الاستعلامات الفرعية، أو نطاق تعبير الجدول الشائع “dynamic” — تعريفًا صحيحًا على أنها غير صالحة، وتُرفض فورًا. الحل: حدّث أنماط SQL لديك كما يلي:
  • منطق التصفية: انقل المنطق من WHERE إلى HAVING إذا كنت تطبّق التصفية على النتائج، أو كرّر التعبير في WHERE إذا كنت تطبّق التصفية على البيانات المصدر.
  • نطاق الاستعلام الفرعي: حدّد صراحةً جميع الأعمدة التي يحتاجها الاستعلام الخارجي.
  • مفاتيح JOIN: استخدم ON مع تعبيرات كاملة بدلًا من USING إذا كان المفتاح اسمًا مستعارًا.
  • في الاستعلامات الخارجية، ارجع إلى الاسم المستعار الخاص بالاستعلام الفرعي/تعبير الجدول الشائع نفسه، لا إلى الجداول الموجودة داخله.

الأعمدة غير المجمّعة في GROUP BY

الخطأ: Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). رمز الاستثناء: 215 السبب: كان المحلّل القديم يسمح بتحديد أعمدة غير موجودة في بند GROUP BY (وغالبًا ما كان يختار قيمة عشوائية). يلتزم المحلّل بمعيار SQL القياسي: يجب أن يكون كل عمود محدد إما تجميعيًا أو مفتاح تجميع. الحل: غلّف العمود داخل any() أو argMax()، أو أضِفه إلى GROUP BY.

الأعمدة غير المجمّعة في HAVING

الخطأ: Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). رمز الاستثناء: 215 السبب: كان المحلّل القديم ينقل بصمت الشروط غير التجميعية من مقترنات AND من HAVING إلى WHERE، ويعاملها كعوامل تصفية قبل التجميع. يلتزم المحلّل بـ SQL القياسية: لا يجوز أن يشير HAVING إلا إلى مفاتيح التجميع والدوال التجميعية. الحل: انقل الشرط من HAVING إلى WHERE يدويًا، أو فعّل analyzer_compatibility_allow_non_aggregate_in_having = 1 (متاح منذ ClickHouse 26.7) لاستعادة إعادة الكتابة القديمة كمساعدة في الترحيل. يتم تجاهل إعداد compatibility مع WITH CUBE وWITH ROLLUP وWITH TOTALS وGROUPING SETS. وتبقى الشروط التي تحتوي على دوال تجميعية أو grouping أو دوال غير حتمية داخل HAVING؛ وإذا احتوى أي شرط على دالة نافذة أو دالة ذات حالة (مثل rowNumberInBlock)، فسيتم تعطيل إعادة الكتابة لكل HAVING، بما يتوافق مع السلوك القديم.

أسماء تعبيرات الجدول الشائعة المكررة

الخطأ: CTE with name ... already exists (MULTIPLE_EXPRESSIONS_FOR_ALIAS). رمز الاستثناء: 179 السبب: كان المُحلِّل القديم يسمح بتعريف عدة تعبيرات جدول شائعة (WITH …) بالاسم نفسه، بحيث يطغى التعريف اللاحق على السابق. ويمنع المُحلِّل هذا الالتباس. الحل: أعد تسمية تعبيرات الجدول الشائعة المكررة لتكون فريدة.

معرّفات الأعمدة الملتبسة

الخطأ: JOIN [JOIN TYPE] ambiguous identifier ... (AMBIGUOUS_IDENTIFIER) رمز الاستثناء: 207 السبب: يشير الاستعلام إلى اسم عمود موجود في عدة جداول ضمن JOIN من دون تحديد الجدول المصدر. وكان المحلّل القديم غالبًا ما يستنتج العمود استنادًا إلى المنطق الداخلي، بينما يتطلب المحلّل تحديد الاسم صراحةً. الحل: حدّد العمود بالكامل باستخدام table_alias.column_name.

استخدام غير صحيح لـ FINAL

الخطأ: Table expression modifiers FINAL are not supported for subquery... أو Storage ... doesn't support FINAL (UNSUPPORTED_METHOD). رموز الاستثناء: 1، 181 السبب: FINAL هو معدِّل لتخزين الجدول (وتحديدًا [Shared]ReplacingMergeTree). يرفض المحلِّل FINAL عند تطبيقه على:
  • الاستعلامات الفرعية أو الجداول المشتقة (مثل FROM (SELECT …) FINAL).
  • محركات الجداول التي لا تدعمه (مثل SharedMergeTree).
الحل: طبِّق FINAL فقط على الجدول المصدر داخل الاستعلام الفرعي، أو أزِله إذا كان المحرك لا يدعمه.

عدم التمييز بين حالات الأحرف في الدالة countDistinct()

الخطأ: Function with name countdistinct does not exist (UNKNOWN_FUNCTION). رمز الاستثناء: 46 السبب: أسماء الدوال تميّز بين حالات الأحرف، أو تُطابَق بشكل صارم ضمن المحلّل. لم يعد countdistinct (بحروف صغيرة بالكامل) يُعرَف تلقائيًا. الحل: استخدم الصيغة القياسية countDistinct (camelCase) أو الدالة uniq الخاصة بـ ClickHouse.
آخر تعديل في ٢٣ يوليو ٢٠٢٦