CTE와 임시 테이블의 차이점은 무엇입니까?


174

공통 테이블 표현식 (CTE)과 임시 테이블의 차이점은 무엇입니까? 그리고 언제 다른 것을 사용해야합니까?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

임시 테이블

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


답변:


200

이것은 꽤 광범위하지만 가능한 한 일반적인 답변을 드릴 것입니다.

CTE ...

  • 색인을 생성 할 수 없습니다 (그러나 참조 된 객체에서 기존 색인을 사용할 수 있음)
  • 제약 조건을 가질 수 없습니다
  • 기본적으로 일회용 VIEW
  • 다음 쿼리가 실행될 때까지만 지속
  • 재귀 가능
  • 전용 통계가 없습니다 (기본 개체의 통계에 의존)

#Temp 테이블 ...

  • tempdb에 존재하는 실제 구체화 된 테이블입니까
  • 인덱스 가능
  • 제약이있을 수 있습니다
  • 현재 CONNECTION의 수명 동안 지속
  • 다른 쿼리 나 하위 프로 시저에서 참조 가능
  • 엔진에 의해 생성 된 전용 통계가 있습니다

각각을 사용할 때까지는 사용 사례가 매우 다릅니다. 결과 세트가 매우 크거나 두 번 이상 참조해야하는 경우 #temp테이블에 넣으십시오 . 재귀 적이거나 일회용이거나 논리적으로 무언가를 단순화하려는 경우 a CTE가 선호됩니다.

또한 성능을 위해 사용CTE 해서는 안됩니다 . CTE를 사용하여 속도를 높이는 일은 거의 없습니다. 다시 말해, 일회용 뷰일뿐입니다. 당신은 그들과 함께 깔끔한 일을 할 수 있지만 쿼리 속도를 높이는 것은 실제로 그중 하나가 아닙니다.


CTE를 사용하여 MERGE 속도를 높이는 것은 일입니다
AgentFire

1
CTE를 사용하면 많은 쿼리 속도를 높일 수 있습니다. CTE를 사용하면 자체 비즈니스 지식을 추가하여 쿼리 옵티 마이저를 능가 할 수 있습니다. 예를 들어 결과 행이 매우 작다는 것을 알고있는 테이블에서 CTE의 1 부를 선택하도록 할 수 있습니다. 동일한 쿼리 내에서이 작은 결과 집합을 더 큰 결과 집합에 결합하고 오래된 통계 등으로 인해 발생한 문제를 완전히 무시할 수 있습니다. 이렇게하려면 쿼리 힌트를 추가하여 순서를 적용해야합니다. 작동하고 성능을 향상시킵니다.
데이브 힐 디치

나는 당신의 요점을 이해하지만 "성능에 사용되지 마십시오"는 광범위하고 다소 주관적인 진술입니다. 다른 의견 외에도 CTE를 사용하면 재귀 프로 시저 호출이나 커서와 같은 다른 형태의 재귀에서 재귀 CTE로 전환 할 때 CTE를 사용하여 또 다른 잠재적 인 성능 향상을 얻을 수 있습니다.
JD

29

편집하다:

아래 Martin의 의견을 참조하십시오.

CTE는 메모리의 테이블로 구체화되지 않습니다. 쿼리 정의를 캡슐화하는 방법 일뿐입니다. OP의 경우 인라인되고 방금 수행하는 것과 동일 SELECT Column1, Column2, Column3 FROM SomeTable합니다. 대부분의 경우 사전에 구체화되지 않으므로 행이 리턴되지 않으므로 WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X실행 계획을 확인하십시오. 때로는 스풀을 얻기 위해 계획을 해킹하는 것이 가능합니다. 이에 대한 힌트를 요청하는 연결 항목이 있습니다. – Martin Smith 2 월 15 일 12시 17:08


원래 답변

CTE

MSDN에서 더 읽어보기

CTE는 메모리에서 사용중인 테이블을 작성하지만 그 뒤에 오는 특정 쿼리에만 유효합니다. 재귀를 사용할 때 효과적인 구조가 될 수 있습니다.

테이블 변수 사용을 고려할 수도 있습니다. 이것은 사용 으로 임시 테이블을 사용하고 가입 각각에 대해 다시 구체화 할 필요없이 여러 번 사용할 수 있습니다. 또한 지금 몇 개의 레코드를 유지해야하는 경우 다음 선택 후 몇 개의 레코드를 추가하고 다른 op 다음에 몇 개의 레코드를 추가 한 다음 소수의 레코드 만 리턴하면 편리한 구조가 될 수 있습니다. 실행 후 삭제하지 않아도됩니다. 주로 구문 설탕. 그러나 행 수를 낮게 유지하면 디스크로 구체화되지 않습니다. SQL Server에서 임시 테이블과 테이블 변수의 차이점무엇입니까?를 참조하십시오 . 상세 사항은.

임시 테이블

MSDN에 대한 자세한 내용-약 40 % 아래로 스크롤

임시 테이블은 말 그대로 모든 사람이 삭제할 수있는 특정 데이터베이스에서 디스크에 생성 된 테이블입니다. 더 이상 필요하지 않을 때 해당 테이블을 삭제하는 것은 좋은 개발자의 책임이지만 DBA도 테이블을 지울 수 있습니다.

임시 테이블은 로컬과 글로벌의 두 가지 종류가 있습니다. MS Sql Server의 #tableName경우 로컬 ##tableName지정과 전역 지정을 사용합니다 (식별 특성으로 단일 또는 이중 #을 사용합니다).

임시 변수 테이블에서는 테이블 변수 또는 CTE와 달리 일반적인 단어 의미의 테이블이므로 인덱스 등을 적용 할 수 있습니다.


일반적으로 더 길거나 더 큰 쿼리에는 임시 테이블을 사용하고 이미 작은 데이터 세트가 있고 작은 코드를 신속하게 스크립팅하려는 경우 CTE 또는 테이블 변수를 사용합니다. 다른 사람들의 경험과 조언에 따르면 CTE를 적은 수의 행으로 반환하는 경우 CTE를 사용해야합니다. 숫자가 큰 경우 임시 테이블에서 색인을 작성하는 기능이 도움이 될 수 있습니다.


11
CTE는 메모리의 테이블로 구체화되지 않습니다. 쿼리 정의를 캡슐화하는 방법 일뿐입니다. OP의 경우, 그것은 인라인되고 방금하는 것과 동일합니다SELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith

4
대부분의 경우 사전에 구체화되지 않으므로 행이 리턴되지 않으므로 WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X실행 계획을 확인하십시오. 때로는 스풀을 얻기 위해 계획해킹하는 것이 가능합니다 . 이에 대한 힌트를 요청 하는 연결 항목 이 있습니다.
Martin Smith

16

허용 대답은 하지만 그건 오해 할 수 - 여기의 "CTE는 성능을 위해 사용해서는 안됩니다"말했다. CTE와 임시 테이블의 맥락에서, 일부 doofus는 임시 테이블을 사용하는 데 오버 헤드가 거의 없거나 전혀 없다고 생각했기 때문에 저장된 proc 세트에서 정크 스왑을 제거했습니다. 프로세스 전체에서 합법적으로 재사용되는 CTE를 제외하고는 CTE에 로트를 넣었습니다 . 모든 지표에서 약 20 %의 성능을 얻었습니다. 그런 다음 재귀 처리를 구현하려는 모든 커서를 제거하도록 설정했습니다. 이것은 내가 가장 큰 이익을 보았던 곳이었다. 응답 시간을 10 배로 줄였습니다.

CTE와 임시 테이블은 사용 사례가 매우 다릅니다. 만병 통치약은 아니지만 CTE를 이해하고 올바르게 사용하면 코드 품질 / 유지 보수성 및 속도면에서 진정으로 뛰어난 개선이 이루어질 수 있다는 점을 강조하고 싶습니다. 내가 처리 했으므로 임시 테이블과 커서를 SQL 처리의 큰 악으로 본다. 나는 거의 모든 것에 대해 테이블 ​​변수와 CTE로 잘 얻을 수 있습니다. 내 코드는 더 깨끗하고 빠릅니다.


이제 공정하게합시다. 커서는 악입니다. 임시 테이블은 최악이다 작은 악마. :-) 당신이 본 것처럼 그것들을 같은 레벨에 놓는 것은 정말로 불공평합니다.
RDFozz

@RDFozz 맞습니다 . 우리 모두 아는 것처럼 9 개의 원이 있습니다. 임시 테이블을 2 위에 놓고 커서를 ... 7 일에 놓을 수 있습니까? ;)
ypercubeᵀᴹ

1
프로그래밍에서 '큰 악'이 무엇인지 아십니까? 사람들이 특정 기술이 악하다고 말합니다. 커서를위한 장소가 있습니다. 특정 시나리오에서 다른 기술보다 성능이 우수합니다. 여기에는 이 없습니다 . 작업에 적합한 도구를 사용하는 법을 배워야합니다. 현재하고있는 일을 측정하고 CTE, 임시 테이블 또는 커서가 악하다는 과대 광고를 믿지 마십시오. 측정-진실은 시나리오에 달려 있기 때문입니다.
데이브 힐 디치

@DaveHilditch 공정한 의견이지만 매우 많은 상황에서 커서가 올바른 솔루션이 아니므로 거의 마지막 수단으로 사용할 수있는 일반화라고 주장하는 것도 공정한 의견입니다.
Mel Padden

1
내 경험에 따르면 CURSOR 자체는 나쁘지 않습니다. CURSORS는 대부분의 프로그래밍 언어에서 대부분 일괄 적으로 생각해야하는 SQL과 달리 반복적으로 생각해야하기 때문에 개발자가 일반적으로 "잘못"사용합니다. 저는 이것이 직장에서 CURSOR가 아닌 다른 문제에서 벗어날 수있는 방법을 "보지"못하는 일반적인 실수라는 것을 알고 있습니다. @DaveHilditch는 완전히 옳습니다. 올바른 작업을위한 올바른 도구 만 있으면됩니다.
Philippe

14

CTE는 쿼리 내에서 반복적으로 호출 될 수 있으며 참조 될 때마다 평가됩니다.이 프로세스는 재귀적일 수 있습니다. CTE를 매개 변수화 할 수 있지만 한 번만 참조하면 하위 쿼리와 매우 유사하게 작동합니다.

임시 테이블은 물리적으로 유지되며 인덱싱 될 수 있습니다. 실제로 쿼리 옵티마이 저는 스풀 작업과 같이 장면 뒤에서 중간 조인 또는 하위 쿼리 결과를 유지할 수도 있으므로 CTE의 결과가 디스크에 지속적으로 유지되는 것은 아닙니다.

반면에 IIRC 테이블 변수는 항상 메모리 내 구조입니다.


4
CTE를 매개 변수화 할 수 있습니까? 어떻게? 또한 테이블 변수가 항상 메모리 내 구조 인 것은 아닙니다 . 관련 질문에 대한 Martin의 탁월한 답변 을 참조하십시오 .
Paul White

11

임시 테이블은 tempdb의 실제 객체이지만 cte는 복잡한 쿼리를 둘러싸는 일종의 래퍼 일뿐이므로 한 단계에서 조직 재귀 구문을 단순화합니다.


8

CTE를 사용하는 주요 이유는 row_number()다양한 Windows 기능과 같은 창 기능에 액세스하기위한 것입니다.

따라서 대부분의 실제 경우 다른 방법보다 그룹당 첫 번째 또는 마지막 행을 매우 효율적으로 빠르고 효율적으로 얻을 수 있습니다 .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

상관 된 하위 쿼리를 사용하거나 하위 쿼리를 사용하여 위와 유사한 쿼리를 실행할 수 있지만 CTE는 거의 모든 시나리오에서 더 빠릅니다.

또한 CTE는 코드를 단순화하는 데 실제로 도움이 될 수 있습니다. 쿼리를 더 많이 이해하고 더 많은 비즈니스 로직을 도입하여 옵티마이 저의 선택성을 높이기 때문에 성능이 향상 될 수 있습니다.

또한 비즈니스 로직을 이해하고 쿼리의 어느 부분을 먼저 실행해야하는지 파악하는 경우 CTE는 성능을 향상시킬 수 있습니다. 일반적으로 가장 선택적인 쿼리를 우선하여 다음 조인에서 인덱스를 사용하고 option(force order)쿼리를 추가 할 수있는 결과 집합으로 연결 합니다. 힌트

마지막으로 CTE는 기본적으로 tempdb를 사용하지 않으므로 사용을 통해 해당 병목 현상에 대한 경합을 줄입니다.

데이터를 여러 번 쿼리해야 할 경우 임시 테이블을 사용하거나 쿼리 를 측정 하고 임시 테이블에 삽입 한 다음 성능을 향상시키는 인덱스를 추가하여 쿼리를 발견 한 경우 임시 테이블을 사용해야합니다.


모든 좋은 포인트 ... +1
Mel Padden

6

CTE에 대해서는 약간의 부정이있는 것 같습니다.

CTE에 대한 나의 이해는 기본적으로 일종의 임시 견해라는 것입니다. SQL은 선언적 언어와 집합 기반 언어입니다. CTE는 세트를 선언하는 좋은 방법입니다! CTE를 색인 할 수없는 것은 실제로는 필요하지 않기 때문에 좋은 것입니다! 쿼리를 더 쉽게 읽고 쓸 수 있도록하는 일종의 구문 설탕입니다. 적절한 옵티마이 저는 기본 테이블의 인덱스를 사용하여 최상의 액세스 계획을 수행합니다. 이는 기본 테이블에 대한 인덱스 조언을 따라 CTE 쿼리 속도를 효과적으로 높일 수 있음을 의미합니다.

또한 집합을 CTE로 정의했다고해서 집합의 모든 행을 처리해야한다는 의미는 아닙니다. 쿼리에 따라 옵티마이 저는 "충분한"행을 처리하여 쿼리를 만족시킬 수 있습니다. 어쩌면 화면에 처음 20 정도만 필요할 수도 있습니다. 임시 테이블을 작성하면 실제로 모든 행을 읽거나 써야합니다!

이를 바탕으로 CTE는 SQL의 훌륭한 기능이며 쿼리를보다 쉽게 ​​읽을 수있는 곳이라면 어디에서나 사용할 수 있습니다. 모든 단일 레코드를 처리 해야하는 배치 프로세스의 임시 테이블에 대해서만 생각합니다. 그럼에도 불구하고 임시 테이블에서는 데이터베이스가 캐싱 및 인덱스를 처리하는 데 훨씬 더 어렵 기 때문에 실제로 권장하지 않습니다. 거래에 고유 한 PK 필드가있는 영구 테이블을 사용하는 것이 좋습니다.

내 경험이 주로 DB2에 관한 것임을 인정해야하므로 CTE의 작업이 두 제품 모두에서 비슷한 방식으로 가정합니다. CTE가 SQL 서버에서 열등한 경우 행복하게 정정 할 것입니다. ;)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.