Перейти к основному содержимому
Перейти к основному содержимому

Анализатор

В версии ClickHouse 24.3 новый анализатор запросов был включен по умолчанию. Вы можете прочитать более подробную информацию о его работе здесь.

Известные несовместимости

Несмотря на устранение большого числа багов и внедрение новых оптимизаций, это также вносит некоторые критические изменения в поведение ClickHouse. Пожалуйста, ознакомьтесь с приведенными ниже изменениями, чтобы определить, как переписать ваши запросы для нового анализатора.

Недействительные запросы больше не оптимизируются

Предыдущая инфраструктура планирования запросов применяла оптимизации на уровне AST до шага валидации запроса. Оптимизации могли переписывать начальный запрос, чтобы сделать его допустимым и исполняемым.

В новом анализаторе валидация запроса происходит перед этапом оптимизации. Это означает, что недействительные запросы, которые ранее можно было исполнять, теперь не поддерживаются. В таких случаях запрос необходимо исправить вручную.

Пример 1

Следующий запрос использует колонку number в списке проекций, когда после агрегации доступна только toString(number). В старом анализаторе, GROUP BY toString(number) оптимизировался в GROUP BY number, делая запрос действительным.

SELECT number
FROM numbers(1)
GROUP BY toString(number)

Пример 2

Та же проблема возникает в этом запросе. Колонка number используется после агрегации с другим ключом. Предыдущий анализатор запросов исправлял этот запрос, перемещая фильтр number > 5 из предложения HAVING в предложение WHERE.

SELECT
    number % 2 AS n,
    sum(number)
FROM numbers(10)
GROUP BY n
HAVING number > 5

Чтобы исправить запрос, вы должны переместить все условия, относящиеся к неагрегированным колонкам, в раздел WHERE, чтобы соответствовать стандартному синтаксису SQL:

SELECT
    number % 2 AS n,
    sum(number)
FROM numbers(10)
WHERE number > 5
GROUP BY n

CREATE VIEW с недействительным запросом

Новый анализатор всегда выполняет проверку типов. Ранее было возможно создать VIEW с недействительным запросом SELECT. В этом случае он бы неудачно выполнялся при первом SELECT или INSERT (в случае MATERIALIZED VIEW).

Теперь невозможно создать VIEW таким образом.

Пример

CREATE TABLE source (data String)
ENGINE=MergeTree
ORDER BY tuple();

CREATE VIEW some_view
AS SELECT JSONExtract(data, 'test', 'DateTime64(3)')
FROM source;

Известные несовместимости оператора JOIN

JOIN, использующий колонку из проекции

Псевдоним из списка SELECT по умолчанию не может использоваться в качестве ключа JOIN USING.

Новая настройка, analyzer_compatibility_join_using_top_level_identifier, при включении изменяет поведение JOIN USING, чтобы предпочитать разрешение идентификаторов на основе выражений из списка проекций запроса SELECT, а не использовать колонки из левой таблицы напрямую.

Например:

SELECT a + 1 AS b, t2.s
FROM VALUES('a UInt64, b UInt64', (1, 1)) AS t1
JOIN VALUES('b UInt64, s String', (1, 'one'), (2, 'two')) t2
USING (b);

При установленной 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, по умолчанию будет включать эти колонки в результирующий набор.

Например:

CREATE TABLE t1 (id UInt64, payload ALIAS sipHash64(id)) ENGINE = MergeTree ORDER BY id;
INSERT INTO t1 VALUES (1), (2);

CREATE TABLE t2 (id UInt64, payload ALIAS sipHash64(id)) ENGINE = MergeTree ORDER BY id;
INSERT INTO t2 VALUES (2), (3);

SELECT * FROM t1
FULL JOIN t2 USING (payload);

В новом анализаторе результат этого запроса будет включать колонку 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.

Например:

SELECT id, toTypeName(id)
FROM VALUES('id LowCardinality(String)', ('a')) AS t1
FULL OUTER JOIN VALUES('id String', ('b')) AS t2
USING (id);

В этом запросе общий суперттип для id определяется как String, отбрасывая модификатор LowCardinality от t1.

Изменения имен колонок проекции

Во время вычисления имен проекций псевдонимы не подменяются.

SELECT
    1 + 1 AS x,
    x + 1
SETTINGS enable_analyzer = 0
FORMAT PrettyCompact

   ┌─x─┬─plus(plus(1, 1), 1)─┐
1. │ 2 │                   3 │
   └───┴─────────────────────┘

SELECT
    1 + 1 AS x,
    x + 1
SETTINGS enable_analyzer = 1
FORMAT PrettyCompact

   ┌─x─┬─plus(x, 1)─┐
1. │ 2 │          3 │
   └───┴────────────┘

Несовместимые типы аргументов функций

В новом анализаторе вывод типов происходит во время первоначального анализа запроса. Это изменение означает, что проверки типов выполняются перед коротким замыканием; таким образом, аргументы функции if всегда должны иметь общий суперттип.

Например, следующий запрос завершится ошибкой Нет суперттипа для типов Array(UInt8), String, так как некоторые из них являются Array, а некоторые - нет:

SELECT toTypeName(if(0, [2, 3, 4], 'String'))

Гетерогенные кластеры

Новый анализатор значительно изменяет протокол связи между серверами в кластере. Таким образом, невозможно выполнять распределенные запросы на серверах с разными значениями настройки enable_analyzer.

Мутации интерпретируются предыдущим анализатором

Мутации по-прежнему используют старый анализатор. Это означает, что некоторые новые возможности SQL ClickHouse не могут быть использованы в мутациях. Например, оператор QUALIFY. Статус можно проверить здесь.

Неподдерживаемые функции

Список функций, которые новый анализатор в настоящее время не поддерживает, приведен ниже:

  • Annoy index.
  • Hypothesis index. В процессе работы здесь.
  • Окно представления не поддерживается. Нет планов по его поддержке в будущем.