Будет ли выполняться неиспользуемый CTE в инструкции SQL

#sql #sql-server #common-table-expression

#sql #sql-server #common-table-expression

Вопрос:

У меня вопрос о CTE. Вы можете запустить инструкцию sql с помощью WITH, а затем вы можете создать один или несколько запросов CTE, которые вы затем в конце можете сделать (в данном случае) select on .

Мой вопрос: будут ли выполняться все запросы CTE или только те, которые используются?

Например.

 WITH cte_1
as (
 Select * from table1
),
cte_2
as (
 Select * from table2
)
Select * from cte_1
  

Будет ли это означать, что select будет выполняться в table1 и table2?

Комментарии:

1. Я бы предположил, что ранняя «фаза перефразирования запроса» автоматически удалит его, но я могу ошибаться.

2. Я не думаю, что table2 будет доступен в вашем запросе. Будут выбраны только данные из таблицы1, поскольку вы используете их в своем final / select

3. Быстрый тест. План выполнения будет игнорировать 2-й cte

4. Вероятно, вы могли бы создать запрос, который обманул бы оптимизатора. В большинстве случаев это не должно вызывать проблем, и ненужные cte будут игнорироваться. Вы также не должны думать о нем как о «выполняемом» как о каком-либо отдельном шаге в более крупном запросе.

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

Ответ №1:

Чтобы завершить ответ мастера Гордона (я смею) :

если вы объявите 2 cte и не используете ни один из них, вы также получите это сообщение об ошибке

 with cte as (select 1/0 as val), cte2 as (select 1/0 as val)
select 1

Msg 422 Level 16 State 4 Line 2 
Common table expression defined but not used.
  

Но если вы используете хотя бы один, инструкция принимается :

 with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_divide_by_zero 

Msg 8134 Level 16 State 1 Line 1
Divide by zero error encountered.
  

И если вы выберете другой CTE, это докажет, что ваш неиспользуемый CTE никогда не выполняется, поскольку ошибка не возникает :

 with cte_divide_by_zero as (select 1/0 as val), cte_legit as (select 'it works' as val)
select * from cte_legit 

val
--------
it works
  

Комментарии:

1. Это также работает, если вы объявляете табличную переменную перед cte и выбираете из нее. Я полагаю, это сработает, если вы также выберете из любой другой таблицы. Cte обрабатываются так же, как подзапрос, и присоединяются к внешнему запросу. Если не к чему присоединяться, это очевидная ошибка. Вы не можете выбрать только из подзапроса

Ответ №2:

Я получаю это сообщение:

Сообщение 422 Уровень 16 Состояние 4 Строка 2

Общее табличное выражение определено, но не используется.

при запуске:

 with cte as (select 1/0 as val)
select 1
  

Вот скрипка db<> .

Комментарии:

1. Интересно, это работает, когда основным запросом является SELECT * FROM tab или OPTION (FORCE ORDER) применяется db<>demo

2. Смотрите мой дальнейший эксперимент, Гордон 🙂