CTE가 쿼리에 정의되어 있고 사용되지 않은 경우 소리가 나나요?


답변:


21

그들이하는 것처럼 보이지는 않지만 이것은 실제로 중첩 된 CTE에만 적용됩니다.

두 임시 테이블을 만듭니다.

CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );

CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );

쿼리 1 :

WITH your_mom AS (
    SELECT TOP 1 *
    FROM #t1 AS t 
),
also_your_mom AS (
    SELECT TOP 1 *
    FROM #t2 AS t
)
SELECT *
FROM your_mom;

쿼리 2 :

WITH your_mom AS (
    SELECT TOP 1 *
    FROM #t1 AS t 
),
also_your_mom AS (
    SELECT TOP 1 *
    FROM #t2 AS t
)
SELECT *
FROM also_your_mom;

쿼리 계획 :

견과류

오버 헤드가 있지만 쿼리의 불필요한 부분은 매우 일찍 제거됩니다 (이 경우 구문 분석 중, 더 복잡한 경우 단순화 단계). 추가 작업이 최소화되고 잠재적으로 비용이 많이 드는 비용 기반에 기여하지 않습니다 최적화.


28

Erik에게 +1하지만 두 가지를 추가하고 싶었습니다 (주석에서 잘 작동하지 않음).

  1. 사용하지 않을 때 무시되는 것을 확인하기 위해 실행 계획을 볼 필요조차 없습니다. 다음은 "0으로 나누기"오류를 발생 시키지만 cte2전혀 선택 하지 않았기 때문에 발생하지 않습니다 .

    ;WITH cte1 AS
    (
      SELECT 1 AS [Bob]
    ),
    cte2 AS (
      SELECT 1 / 0 AS [Err]
      FROM cte1
    )
    SELECT *
    FROM   cte1;
    
  2. CTE의 그들이 유일한 CTE 경우에도 그들이에서 선택하더라도 무시할 수 있다면 논리적으로 모든 행 어쨌든 제외된다. 다음은 쿼리 최적화 프로그램이 CTE에서 행을 반환 할 수 없다는 것을 미리 알고 있으므로 실행하는 데 방해가되지 않습니다.

    ;WITH cte AS
    (
      SELECT 1 / 0 AS [Bob]
    )
    SELECT TOP (1) [object_id]
    FROM   sys.objects
    UNION ALL
    SELECT cte.[Bob]
    FROM   cte
    WHERE  1 = 0;
    

성능과 관련하여 사용되지 않은 CTE는 구문 분석 및 컴파일 (또는 적어도 아래의 경우에는 컴파일)되므로 100 % 무시되지 않지만 비용은 무시해도되며 걱정할 가치가 없습니다.

구문 분석 만 할 때 오류가 없습니다.

SET PARSEONLY ON;

;WITH cte1 AS
(
  SELECT obj.[NotHere]
  FROM   sys.objects obj
)
SELECT TOP (1) so.[name]
FROM   sys.objects so

GO
SET PARSEONLY OFF;
GO

실행이 짧은 모든 것을 할 때 문제가 있습니다.

GO
SET NOEXEC ON;
GO

;WITH cte1 AS
(
  SELECT obj.[NotHere]
  FROM   sys.objects obj
)
SELECT TOP (1) so.[name]
FROM   sys.objects so

GO
SET NOEXEC OFF;
GO
/*
Msg 207, Level 16, State 1, Line XXXXX
Invalid column name 'NotHere'.
*/

하나 이상의 답변을 올바른 것으로 표시 할 수 있기를 바랍니다. 그러나 Erik은 당신을 권총 추첨으로 이겼습니다. :) 그러나 당신의 대답은 매우 유익하고 훌륭합니다. 감사합니다!
JD

CTE가 뷰에 있고 뷰가 3 회 이상 중첩 된 경우 어떻게합니까? 옵티마이 저가 모두 포기하고 실행하는 지점이 없습니까?
Zikato

@Zikato 잘 모르겠지만 좋은 질문입니다. 처음 두 예제에서 보여준 0으로 나누기 트릭을 사용하여 뷰를 만들어 너무 많은 노력없이 테스트를 설정할 수 있어야합니다. 이 시나리오에 대해 지금 매우 궁금한 결과를 알려주십시오 :-).
Solomon Rutzky

@SolomonRutzky 공정하게하기 위해 테스트했지만 결정적이지는 않았습니다. 나는 당신의 cte 예제에서 뷰를 생성하고 5 번 중첩했지만, 모두 일정한 스캔이고 실제로 복잡하지 않기 때문에 옵티마이 저가 잘 처리했습니다. 앞으로 더 철저하게 테스트하고 더 복잡한 논리 뒤에 숨기고 싶습니다. 내가 알려 주마.
Zikato

@Zikato 재미있는. 무엇이 "복잡한"것으로 여겨 질지 잘 모르겠지만, 제 예는 매우 단순합니다. "5 번 중첩"이라고 말하면 서로를 부르고 깊이가 5 개인 하위 뷰 / CTE 인 다른 뷰 / 프로 크를 의미합니까? 충분한 수준을 중첩하면 건너 뛸 수 있지만 참조되지 않기 때문에 대신 높은 중첩 수준을 사용하지 않고 낮은 수준으로 가정 할 가능성이 있다고 생각합니다. NEWID()UDF에서 사용하기 위해 뷰를 배치하는 트릭이 옵티마이 저가 캐싱하기 때문에 여러 호출에서 동일한 값을 반환 할 수있는 곳을 보았습니다 .
Solomon Rutzky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.