Обязан ли SQL-движок вычислять CTE, который нигде не используется?
Нет. Для обычного запросного CTE отсутствие ссылок означает, что его результат не влияет на семантику оператора, поэтому оптимизатор вправе полностью исключить его вычисление. При этом CTE всё равно должен быть корректно разобран и проверен на синтаксические и семантические ошибки.
CTE появился как именованный способ описывать промежуточные наборы данных внутри одного оператора. Изначально это решало проблему читаемости сложных запросов и позволяло разделять вычисление на логические этапы без создания временных таблиц.
Такое логическое представление не означает обязательного физического шага выполнения. Оптимизатор может убрать ненужный этап, встроить его в основной запрос или выбрать другой эквивалентный план.
Разработчик иногда воспринимает объявление CTE как приказ сначала вычислить его целиком. Это может привести к ошибочным ожиданиям о времени выполнения, потреблении памяти и побочных эффектах.
Для обычного CTE, содержащего только запрос, неиспользуемый результат не должен влиять на строки основного запроса. Однако сам текст всё равно анализируется: ошибка в синтаксисе, именах столбцов или типах может сделать весь оператор недопустимым.
CTE является частью декларативного выражения запроса, а не гарантированной временной таблицей. Если основной оператор не ссылается на имя CTE, оптимизатор может удалить соответствующую ветвь плана как недостижимую для результата.
В этом примере строки unused не могут попасть в результат. Движок может обработать объявление при разборе запроса, но не обязан выполнять его как отдельное чтение или вычисление.
Нельзя переносить этот вывод на конструкции с побочными эффектами без оговорок. Модифицирующие CTE, пользовательские функции с побочными эффектами и специальные режимы конкретной СУБД могут иметь собственные правила; их поведение нужно проверять по документации данной системы.
Важно также различать семантику и диагностику. Даже если CTE не используется, ошибка вроде обращения к несуществующей таблице или некорректного числа столбцов может привести к отказу всего запроса, потому что оператор должен быть валидным до построения плана.
В отчёте оставили старый CTE, который строил большой промежуточный набор, но после рефакторинга основной запрос перестал на него ссылаться. Команда предположила, что база всё ещё сканирует исходные таблицы, и начала оптимизировать этот удалённый этап.
Возможные варианты были такими:
Выбранным решением стало удаление неиспользуемого CTE и проверка плана после изменения. Это уменьшило сложность запроса и исключило ложное предположение о гарантированном предварительном вычислении. Если CTE содержал бы потенциально побочные действия, сначала потребовалась бы отдельная проверка поведения конкретной СУБД.
Да. Неиспользование результата не отменяет разбора и проверки всего оператора. Ошибка синтаксиса, неизвестное имя таблицы или столбца, несовместимые типы и другие ошибки компиляции могут сделать запрос неисполняемым.
Нет. Сам факт ссылки на CTE не устанавливает способ материализации. В зависимости от СУБД, версии, подсказок и структуры запроса результат может быть встроен в места использования или материализован. Поэтому число физических вычислений определяется планом, а не только текстом CTE.
Нет, полагаться на это нельзя. Оптимизатор вправе удалить ветвь, не влияющую на результат, а порядок и факт вычисления выражений с побочными эффектами зависят от конкретной СУБД. Такие действия следует выполнять явным оператором с документированными гарантиями, а не скрывать в неиспользуемом CTE.