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


답변:


62

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

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

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

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

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


12
임시 테이블은 또한 때때로 필요한 인덱스 및 통계를 허용하지만 CTE는 필요하지 않습니다.
CodeCowboyOrg

9
이 답변은 CTE가 끔찍한 성능으로 이어질 수 있다는 사실을 충분히 강조하지 못한다고 생각합니다. 나는 보통 dba.stackexchange 에서이 답변 을 참조합니다 . 내가 찾고 있어요 경우 귀하의 질문은 내 검색 엔진에 두 번째 등장 cte vs temporary tables이 답변이 더 CTE의의 단점을 강조 할 필요가 이럴 있도록. 링크 된 답변의 TL : DR : CTE를 성능에 사용해서는 안됩니다. . 나는 CTE의 단점을 경험하면서 그 인용에 동의합니다.
TT.

2
@TT. 흥미 롭군 CTE의 성능이 훨씬 뛰어납니다
Squ1rr3lz

198

때에 따라 다르지.

가장 먼저

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

(재귀 적이 지 않은) 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 또는 파생 테이블의 중간 구체화를 강제하는 힌트를 제공하십시오 . 그러나 이에 대한 통계는 작성되지 않으며 스풀 행 수가 예상과 크게 다를지라도 진행중인 실행 계획이 응답에 동적으로 적응할 수는 없습니다 (적어도 현재 버전에서는 적응 쿼리 계획이 가능할 수 있음). 미래).


33
이것은 실제 질문에 답변하는 유일한 답변이며 (차이가 아니거나 가장 좋아하는 것이 아닌 더 나은 성능을 요구하는 것), 해당 질문에 올바르게 답변합니다. "의존"은 정답입니다. 또한 하나 더없는 참조 또는 증명 다른 것보다 것을 명확한 주장을 (높은 투표 번호) 설명하는 데이터, 여러 다른 사람을 지원하는 유일한 대답은 ... 명확하게하기 위해, 그 모든 답변은 또한 잘못 . "그것은 달려있다"
Arkaine55

2
또한 잘 작성되고 잘 참조 된 답변입니다. 진심으로 최고 수준.
Dan Williams

50

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


9
나는 내 자신의 경험에서 이것을 보았다. CTE의 성능이 현저히 느려집니다.
goku_da_master

7
결과가 캐시되지 않기 때문에 CTE도 느리게 수행됩니다. 따라서 CTE를 사용할 때마다 쿼리, 계획 및 모두를 다시 실행합니다.
goku_da_master

1
그리고 DB 엔진은 모든 참조뿐만 아니라 소비자 쿼리의 모든 에 대해 상관 된 하위 쿼리로 쿼리 를 다시 실행하도록 선택할 수 있습니다 .
Mike M

임시 테이블은 디스크 인 SQL Server의 tempdb에 저장되지만 인덱싱되는 이점이 있으며 SQL 최적화 프로그램은이 경우 선택 쿼리에서 잘 작동합니다. CTE가 어떤 db 또는 디스크 영역에 저장되어 있는지 (메모리 크기를 초과하고 IO 페이징을 위해 대기 할 때) 확실하지 않지만 대용량 데이터에 최적화되지는 않았습니다. 컴파일러 옵션 (재 컴파일과 함께)을 사용하여 더 빠르게
만들기도

33

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

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

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

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


2
SQLite 및 PostgreSQL의 경우 임시 테이블 자동으로 삭제됩니다 (일반적으로 세션이 끝날 때). 그래도 다른 DBMS에 대해서는 모른다.
Serrano

1
CTE는 임시보기와 같습니다. AFAIK 데이터는 저장되지 않으므로 메모리 나 디스크에 저장되는 것은 없습니다. CTE를 사용할 때마다 쿼리가 다시 실행됩니다.
Rob

1
개인적으로 나는 CTE가 속도에 대한 임시 테이블보다 더 나은 것을 보지 못했습니다. 그리고 잘 디버깅은 임시 테이블에 훨씬 더 쉽게
마크 Monforti

7

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

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

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

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

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


6

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

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

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

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

select * from #temp

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

select * from #temp

4
>> "조인을 사용할 수있는 결과 집합입니다." -> 이것은 정확하지 않습니다. CTE는 "결과 세트"가 아니라 인라인 코드입니다. SQL Server 쿼리 엔진은 쿼리 텍스트의 일부로 CTE 코드를 구문 분석하고 이에 따라 실행 계획을 작성합니다. CTE가 인라인이라는 생각은 서버가 "결합 실행 계획"을 만들 수 있기 때문에 CTE를 사용하는 것의 큰 이점입니다.
Ronen Ariely

4

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

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


3

파티에 늦었지만 ...

내가 일하는 환경은 제약이 많으며 일부 공급 업체 제품을 지원하고보고와 같은 "부가가치"서비스를 제공합니다. 정책 및 계약 제한으로 인해 일반적으로 별도의 테이블 / 데이터 공간의 고급 스러움 및 / 또는 영구 코드 생성 기능이 허용되지 않습니다 [응용 프로그램에 따라 조금 더 나아집니다].

IOW, 나는 일반적으로 저장 프로 시저 또는 UDF 또는 임시 테이블 등을 개발할 수 없습니다 . 나는 거의 내 응용 프로그램 인터페이스 (Crystal Reports-테이블 추가 / 링크, w / in CR의 절 설정 등)를 통해 모든 것을해야합니다. ). 작은 절약 효과 중 하나는 Crystal을 통해 COMMANDS (SQL 식)를 사용할 수 있다는 것입니다. 정기적 인 추가 / 링크 테이블 기능을 통해 비효율적 인 작업은 SQL 명령을 정의하여 수행 할 수 있습니다. 이를 통해 CTE를 사용하며 "원격으로"매우 좋은 결과를 얻었습니다. CTE는 또한 코드를 개발할 필요가 없으며 DBA에 전달하여 컴파일, 암호화, 전송, 설치 및 다중 레벨 테스트가 필요하지 않은 유지 보수 보고서를 제공합니다. 로컬 인터페이스를 통해 CTE를 수행 할 수 있습니다.

CR을 사용하는 CTE 사용의 단점은 각 보고서는 별개입니다. 각 CTE는 각 보고서마다 유지 관리되어야합니다. SP와 UDF를 수행 할 수있는 곳에서는 SP에 연결하고 일반 테이블에서 작업하는 것처럼 매개 변수를 전달하기 만하면 여러 보고서에서 사용할 수있는 것을 개발할 수 있습니다. CR은 SQL 명령에서 매개 변수를 처리하는 데 실제로 좋지 않으므로 CR / CTE 측면이 부족할 수 있습니다. 이 경우 일반적으로 CTE를 정의하여 충분한 데이터 (모든 데이터가 아님)를 반환 한 다음 CR의 레코드 선택 기능을 사용하여 슬라이스 및 다이 싱합니다.

그래서 ... 내 투표는 CTE에 대한 것입니다 (데이터 공간을 확보 할 때까지).


3

CTE의 우수한 성능을 현명하게 발견 한 한 가지 용도는 상대적으로 복잡한 쿼리를 각각 수백만 행이있는 몇 개의 테이블에 조인해야하는 곳이었습니다.

CTE를 사용하여 먼저 인덱스 열을 기반으로 하위 집합을 선택하여 이러한 테이블을 각각 몇 천 개의 관련 행으로 줄인 다음 CTE를 기본 쿼리에 연결했습니다. 이것은 내 쿼리의 런타임을 기하 급수적으로 줄였습니다.

CTE에 대한 결과가 캐시되지 않고 테이블 변수가 더 나은 선택 일 수는 있지만 실제로 시도해보고 위의 시나리오에 적합하다는 것을 알았습니다.


(가) 난 단지 정말 CTE를 실행 가입에 난 단지 CTE를 사용하기 때문에 또한, 내가 생각하는 내 쿼리에 한 번 결과를 캐싱하는 것은이 점에서 그렇게 큰 문제가 아니었다 그래서
purchas

1

이것은 실제로 개방형 질문이며, 모두 사용 방법과 임시 테이블 유형 (테이블 변수 또는 전통적인 테이블)에 달려 있습니다.

전통적인 임시 테이블은 임시 테이블에 데이터를 저장하여 임시 테이블을 느리게합니다. 그러나 테이블 변수는 그렇지 않습니다.


1

방금 CTE와 CTE가 아닌 (모든 유니온 인스턴스에 대해 쿼리가 입력 된) 둘 다 ~ 31 초가 걸렸습니다. CTE는 코드를 더 읽기 쉽게 만들었지 만 241 줄에서 130 줄로 줄였습니다. 반면 임시 테이블은 132 줄로 줄이고 5 초가 걸렸습니다. 농담이 없습니다. 이 테스트는 모두 캐시되었습니다. 쿼리는 모두 여러 번 실행되었습니다.


1

SQL Server에 대한 경험을 통해 CTE가 Temp 테이블보다 우수한 시나리오 중 하나를 발견했습니다.

스토어드 프로 시저에서 복잡한 쿼리의 DataSet (~ 100000)을 ONCE 만 사용해야했습니다.

  • 임시 테이블은 내 프로 시저가 느리게 수행되는 SQL에서 오버 헤드를 유발했습니다 (임시 테이블은 tempdb에 존재하고 현재 프로 시저의 수명 동안 지속되는 실제 구체화 된 테이블이므로)

  • 반면 CTE를 사용하면 CTE는 다음 쿼리가 실행될 때까지만 지속됩니다. 따라서 CTE는 범위가 제한된 편리한 메모리 내 구조입니다. CTE는 기본적으로 tempdb를 사용하지 않습니다.

이것은 CTE가 코드를 단순화하고 임시 테이블을 능가하는 데 실제로 도움이 될 수있는 시나리오입니다. 나는 2 CTE를 사용했다.

WITH CTE1(ID, Name, Display) 
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO

1
귀하의 답변은 매우 일반적인 것 같습니다 ... "CTE가 Temp 테이블보다 성능이 뛰어남"을 어떻게 측정합니까? 시간 측정을 했습니까? 내 의견으로는 답변을 편집하고 자세한 내용을 추가해야합니다.
Il Vic

예, 진술을 뒷받침 할 시간 측정 및 실행 계획이 있습니다.
Amardeep Kohli

제한된 권한으로 인해 실행 계획에 대한 img를 추가 할 수 없습니다. 세부 정보가 해결되면 업데이트됩니다
Amardeep Kohli
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.