[sql-server] 더 성능이 뛰어난 CTE 또는 임시 테이블은 무엇입니까?

어떤 더 확대됨에있는, CTE또는 Temporary Tables?



답변

나는 그것들이 다른 개념이지만 “분과 치즈”라고 말하기에는 너무 다르지 않다고 말하고 싶습니다.

  • 임시 테이블은 재사용하거나 일련의 데이터에 대해 여러 처리 단계를 수행하는 데 적합합니다.

  • CTE는 재귀 또는 가독성을 향상시키기 위해 사용될 수 있습니다.
    또한 뷰 또는 인라인 테이블 값 함수와 같이 주 쿼리에서 확장되는 매크로처럼 처리 될 수 있습니다.

  • 임시 테이블은 범위와 관련된 몇 가지 규칙이있는 다른 테이블입니다.

둘 다 사용하는 procs를 저장했습니다 (및 테이블 변수도).


답변

때에 따라 다르지.

가장 먼저

공통 테이블식이 란 무엇입니까?

(재귀 적이 지 않은) CTE는 SQL Server에서 인라인 테이블 식으로 사용할 수있는 다른 구문과 매우 유사하게 처리됩니다. 파생 테이블, 뷰 및 인라인 테이블 값 함수 BOL은 CTE가 “임시 결과 집합으로 생각할 수있다”고 말하지만 이것은 순수한 논리적 설명입니다. 종종 그 자체로는 materlialized되지 않습니다.

임시 테이블이란 무엇입니까?

이것은 tempdb의 데이터 페이지에 저장된 행의 모음입니다. 데이터 페이지는 부분적으로 또는 전체적으로 메모리에 상주 할 수 있습니다. 또한 임시 테이블이 색인화되고 열 통계가있을 수 있습니다.

테스트 데이터

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

실시 예 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

계획 1

위 계획에서 CTE1에 대한 언급은 없습니다. 기본 테이블에 직접 액세스하고 다음과 동일하게 처리됩니다.

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

여기에서 CTE를 중간 임시 테이블로 구체화하여 다시 작성하는 것은 상당히 역효과를 낳습니다.

의 CTE 정의 구체화

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

약 8GB의 데이터를 임시 테이블에 복사하면 여전히 테이블에서 선택하는 오버 헤드가 있습니다.

실시 예 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

위의 예는 내 컴퓨터에서 약 4 분이 걸립니다.

1,000,000 개의 임의로 생성 된 값 중 15 개 행만이 술어와 일치하지만 값이 비싼 테이블 스캔은 16 번 발생하여이 값을 찾습니다.

여기에 이미지 설명을 입력하십시오

이것은 중간 결과를 구체화하기에 좋은 후보가 될 것입니다. 동등한 임시 테이블 다시 쓰기에 25 초가 걸렸습니다.

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

계획

쿼리의 일부를 임시 테이블로 중간에 구체화하는 경우 한 번만 평가하더라도 구체화 된 결과에 대한 통계를 활용하여 나머지 쿼리를 다시 컴파일 할 수있는 경우에 유용 할 수 있습니다. 이 접근 방식의 예는 SQL Cat 기사 복잡한 쿼리를 분석 할 때를 참조하십시오 .

경우에 따라 SQL Server는 스풀을 사용하여 CTE와 같은 중간 결과를 캐시하고 해당 하위 트리를 다시 평가하지 않아도됩니다. 이것은 (이주 된) 연결 항목에서 설명됩니다 . CTE 또는 파생 테이블의 중간 구체화를 강제하는 힌트를 제공하십시오 . 그러나 이에 대한 통계는 작성되지 않으며 스풀 행 수가 예상과 크게 다를지라도 진행중인 실행 계획이 응답에 동적으로 적응할 수는 없습니다 (적어도 현재 버전에서는 적응 쿼리 계획이 가능할 수 있음). 미래).


답변

CTE의 용도는 CTE의 데이터가 작고 재귀 테이블의 경우와 같이 가독성이 크게 개선 된 경우입니다. 그러나 그 성능은 확실히 테이블 변수보다 낫지 않으며 매우 큰 테이블을 처리 할 때 임시 테이블이 CTE보다 훨씬 뛰어납니다. CTE에서 인덱스를 정의 할 수없고 다른 테이블과 조인해야하는 많은 양의 데이터가있는 경우 (CTE는 단순히 매크로와 같습니다) 때문입니다. 각 행에 수백만 행의 레코드가있는 여러 테이블을 조인하는 경우 CTE는 임시 테이블보다 성능이 크게 저하됩니다.


답변

임시 테이블은 항상 디스크에 있으므로 CTE를 메모리에 보관할 수있는 한 테이블 변수와 같이 속도가 더 빠릅니다.

그러나 CTE (또는 임시 테이블 변수)의 데이터로드가 너무 커지면 디스크에도 저장되므로 큰 이점이 없습니다.

일반적으로 CTE는 사용 후 사라지기 때문에 임시 테이블보다 CTE를 선호합니다. 명시 적으로 삭제하는 것에 대해 생각할 필요가 없습니다.

따라서 결국 명확한 대답은 없지만 개인적으로 임시 테이블보다 CTE를 선호합니다.


답변

그래서 내가 최적화하도록 할당 된 쿼리는 SQL Server에서 두 개의 CTE로 작성되었습니다. 28 초가 걸렸습니다.

나는 그들을 임시 테이블로 변환하는 데 2 ​​분을 보냈고 쿼리는 3 초가 걸렸다.

조인중인 필드의 임시 테이블에 인덱스를 추가하고 2 초로 줄였습니다.

CTE를 제거하여 3 분의 작업 시간과 12 배 빠른 속도로 실행 나는 개인적으로 CTE를 사용하지 않을 것입니다.

미친 점은 CTE가 한 번만 사용되었지만 여전히 CTE가 50 % 더 빠른 것으로 판명되었다는 것입니다.


답변

CTE는 물리적 공간을 차지하지 않습니다. join을 사용할 수있는 결과 집합 일뿐입니다.

임시 테이블은 임시입니다. 인덱스를 생성하고 모든 변수를 정의해야하는 일반 테이블처럼 제한 할 수 있습니다.

세션 내에서만 임시 테이블의 범위. 예 : 두 개의 SQL 쿼리 창 열기

create table #temp(empid int,empname varchar)
insert into #temp 
select 101,'xxx'

select * from #temp

첫 번째 창 에서이 쿼리를 실행 한 다음 두 번째 창에서 아래 쿼리를 실행하면 차이점을 찾을 수 있습니다.

select * from #temp


답변

나는 두 가지를 모두 사용했지만 대규모 복잡한 절차에서 항상 임시 테이블을 사용하는 것이 더 좋고 체계적이라는 것을 알았습니다. CTE는 용도가 있지만 일반적으로 작은 데이터를 사용합니다.

예를 들어 15 초 안에 큰 계산 결과가 나오는 sprocs를 만들었지만이 코드를 CTE에서 실행되도록 변환하고 동일한 결과를 얻기 위해 8 분 이상 실행되는 것을 보았습니다.