Анализатор
В версии ClickHouse 24.3 новый анализатор запросов включён по умолчанию.
Подробнее о том, как он работает, можно прочитать здесь.
Известные несовместимости
Несмотря на исправление большого числа ошибок и внедрение новых оптимизаций, также были внесены некоторые изменения в поведении ClickHouse, нарушающие обратную совместимость. Пожалуйста, ознакомьтесь со следующими изменениями, чтобы понять, как переписать ваши запросы для нового анализатора.
Некорректные запросы больше не оптимизируются
Предыдущая инфраструктура планирования запросов применяла оптимизации на уровне AST до шага проверки запроса. Оптимизации могли переписать исходный запрос так, чтобы он стал корректным и исполнимым.
В новом анализаторе проверка запроса выполняется до шага оптимизации. Это означает, что некорректные запросы, которые ранее можно было выполнить, больше не поддерживаются. В таких случаях запрос должен быть исправлен вручную.
Пример 1
Следующий запрос использует столбец number в списке проекции, хотя после агрегации доступен только toString(number).
В старом анализаторе GROUP BY toString(number) оптимизировался в GROUP BY number, что делало запрос корректным.
Пример 2
Та же проблема возникает в этом запросе. Столбец number используется после агрегации с другим ключом.
Предыдущий анализатор запросов исправил этот запрос, переместив фильтр number > 5 из условия HAVING в условие WHERE.
Чтобы исправить запрос, перенесите все условия, относящиеся к неагрегированным столбцам, в предложение WHERE, чтобы запрос соответствовал стандартному синтаксису SQL:
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 условие соединения интерпретируется как t1.a + 1 = t2.b, что соответствует поведению более ранних версий.
Результатом будет 2, 'two'.
Если настройка установлена в значение false, по умолчанию используется условие соединения 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, что потребует от клиентов вручную обновить запросы, не соответствующие этим правилам.
Процесс миграции
- Определите запрос, отфильтровав
system.query_logпоnormalized_query_hash:
- Выполните запрос с включённым анализатором, добавив эти настройки.
- Перепишите и проверьте результаты запроса, чтобы убедиться, что они совпадают с результатом, получаемым при отключённом анализаторе.
Пожалуйста, ознакомьтесь с наиболее частыми несовместимостями, выявленными во время внутреннего тестирования.
Неизвестный идентификатор выражения
Ошибка: Unknown expression identifier ... in scope ... (UNKNOWN_IDENTIFIER). Код исключения: 47
Причина: запросы, которые полагаются на нестандартное, чрезмерно либеральное устаревшее поведение — например, обращение к вычисляемым псевдонимам в фильтрах, неоднозначные проекции подзапросов или «динамическую» область видимости CTE, — теперь корректно распознаются как недопустимые и немедленно отклоняются.
Решение: обновите шаблоны SQL следующим образом:
- Логика фильтрации: перенесите логику из WHERE в HAVING, если фильтрация выполняется по результатам, или продублируйте выражение в WHERE, если фильтруются исходные данные.
- Область видимости подзапроса: явно выбирайте все столбцы, необходимые внешнему запросу.
- Ключи JOIN: используйте ON с полными выражениями вместо USING, если ключ — это псевдоним.
- Во внешних запросах ссылайтесь на псевдоним самого подзапроса/CTE, а не на таблицы внутри него.
Неагрегированные столбцы в GROUP BY
Ошибка: Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). Код исключения: 215
Причина: старый анализатор позволял выбирать столбцы, отсутствующие в предложении GROUP BY (часто выбирая произвольное значение). Новый анализатор следует стандарту SQL: каждый столбец в SELECT должен быть либо агрегатом, либо ключом группировки.
Решение: оберните столбец в any(), argMax() или добавьте его в GROUP BY.
Повторяющиеся имена CTE
Ошибка: CTE with name ... already exists (MULTIPLE_EXPRESSIONS_FOR_ALIAS). Код исключения: 179
Причина: старый анализатор допускал определение нескольких Common Table Expressions (WITH ...) с одинаковым именем, при котором более позднее определение перекрывало предыдущее. Новый анализатор запрещает такую неоднозначность.
Решение: переименуйте повторяющиеся CTE так, чтобы их имена были уникальными.
Неоднозначные идентификаторы столбцов
Ошибка: 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) или специфичную для ClickHouse функцию uniq.