Общие табличные выражения
Общие табличные выражения — это именованные подзапросы. На них можно ссылаться по имени в любом местеSELECT-запроса, где допускается табличное выражение.
На именованные подзапросы можно ссылаться по имени в области видимости текущего запроса или в областях видимости дочерних подзапросов.
Каждая ссылка на общее табличное выражение в SELECT-запросах всегда заменяется подзапросом из его определения, если CTE явно не определено как материализованное (см. Материализованные общие табличные выражения).
Рекурсия предотвращается за счёт исключения текущего CTE из процесса разрешения идентификаторов.
Обратите внимание, что CTE не гарантируют одинаковые результаты во всех местах, где к ним обращаются, поскольку для каждого случая использования запрос выполняется заново.
Синтаксис
Пример
Пример случая, когда подзапрос выполняется повторно:1000000
Однако поскольку мы дважды обращаемся к cte_numbers, случайные числа каждый раз генерируются заново, и поэтому мы видим разные случайные результаты: 280501, 392454, 261636, 196227 и так далее…
Материализованные общие табличные выражения
По умолчанию ClickHouse разворачивает подзапрос CTE во все места, где на него есть ссылка, и каждый раз выполняет его заново. Добавление ключевого словаMATERIALIZED указывает ClickHouse выполнить подзапрос CTE ровно один раз, сохранить результат во временной таблице и использовать эту таблицу для всех ссылок.
Это особенно полезно, когда один и тот же CTE используется в запросе несколько раз (например, в JOIN с самим собой’ах или нескольких подзапросах IN), поскольку базовое вычисление выполняется только один раз.
Материализованные CTE — экспериментальная возможность.
Для их использования должна быть включена настройка
enable_materialized_cte.
Если настройка отключена, ключевое слово MATERIALIZED игнорируется: CTE разворачивается в каждое место ссылки, как обычный CTE, а в лог записывается предупреждение.Синтаксис
Когда использовать
Материализованные CTE наиболее полезны в следующих случаях:- Один и тот же CTE используется в запросе более одного раза.
Без
MATERIALIZEDкаждая ссылка на него повторно выполняет подзапрос независимо. - CTE содержит недетерминированные функции, такие как
generateRandom. Материализация гарантирует, что все ссылки будут видеть одни и те же данные. - CTE включает ресурсоёмкие вычисления (агрегации, JOIN, сканирование больших объёмов данных), которые не следует выполнять повторно.
Примеры
Пример 1: JOIN материализованного CTE с самим собой БезMATERIALIZED обе стороны JOIN выполняли бы подзапрос независимо.
С MATERIALIZED таблица сканируется один раз, и обе стороны JOIN читают из одной и той же временной таблицы.
generateRandom дают разные результаты при каждом обращении.
Материализация CTE обеспечивает согласованность:
1000000.
Пример 3: Цепочка материализованных CTE
Материализованные CTE могут ссылаться на другие материализованные CTE.
ClickHouse определяет зависимости и материализует их в правильном порядке:
Ограничения
- Требуется экспериментальная настройка: настройка
enable_materialized_cteдолжна быть включена. Если она отключена, ключевое словоMATERIALIZEDигнорируется: CTE разворачивается в каждое место обращения, как обычный CTE, и в лог записывается предупреждение. - Не поддерживается с
RECURSIVE: использование ключевых словMATERIALIZEDиRECURSIVEвместе не допускается и приводит к исключениюUNSUPPORTED_METHOD. - Коррелированные CTE запрещены: материализованный CTE не может ссылаться на столбцы из внешних областей видимости запроса.
Общие скалярные выражения
ClickHouse позволяет объявлять псевдонимы для произвольных скалярных выражений в конструкцииWITH.
На общие скалярные выражения можно ссылаться в любом месте запроса.
Если общее скалярное выражение ссылается не на константный литерал, выражение может приводить к появлению свободных переменных.
ClickHouse разрешает любой идентификатор в ближайшей возможной области видимости, а значит, при конфликтах имен свободные переменные могут ссылаться на неожиданные сущности или приводить к коррелированному подзапросу.
Рекомендуется определять CSE как лямбда-функцию, связывая все используемые идентификаторы, чтобы добиться более предсказуемого разрешения идентификаторов в выражениях.
Синтаксис
Примеры
Пример 1: Использование константного выражения как “переменной”extension не привязана в теле лямбда-функции gen_name.
Хотя extension определена как '.txt' в виде общего скалярного выражения в области видимости определения и использования generated_names, она разрешается как столбец таблицы extension_list, поскольку доступна в подзапросе generated_names.
Рекурсивные запросы
Необязательный модификаторRECURSIVE позволяет запросу WITH обращаться к собственному результату. Пример:
Пример: Суммирование целых чисел от 1 до 100
Рекурсивные CTE опираются на анализатор запросов, добавленный в версии
24.3; начиная с этой версии он используется по умолчанию, а начиная с 26.9 является обязательным. В более старой версии, где анализатор всё ещё отключен для экземпляра, роли или профиля, рекурсивный CTE вызывает исключение (UNKNOWN_TABLE) или (UNSUPPORTED_METHOD); включите там настройку enable_analyzer или обновитесь.WITH всегда состоит из нерекурсивного выражения, затем UNION ALL, затем рекурсивного выражения, при этом только рекурсивное выражение может содержать ссылку на собственный результат запроса. Рекурсивный CTE-запрос выполняется следующим образом:
- Вычислите нерекурсивное выражение. Поместите результат запроса нерекурсивного выражения во временную рабочую таблицу.
- Пока рабочая таблица не пуста, повторяйте следующие шаги:
- Вычислите рекурсивное выражение, подставив текущее содержимое рабочей таблицы вместо рекурсивной самоссылки. Поместите результат запроса рекурсивного выражения во временную промежуточную таблицу.
- Замените содержимое рабочей таблицы содержимым промежуточной таблицы, затем очистите промежуточную таблицу.
Порядок обхода
Чтобы задать порядок обхода в глубину, для каждой результирующей строки мы вычисляем массив строк, которые уже были посещены: Пример: Обход дерева в глубинуОбнаружение циклов
Сначала создадим таблицу графа:Maximum recursive CTE evaluation depth:
Бесконечные запросы
Можно также использовать бесконечные рекурсивные CTE-запросы, если во внешнем запросе указанLIMIT:
Пример: Бесконечный рекурсивный CTE-запрос
Завершающая запятая
Запятая допускается после последнего элемента конструкцииWITH: