어떤 더 확대됨에있는, CTE
또는 Temporary Tables
?
어떤 더 확대됨에있는, 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
위 계획에서 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를 선호합니다.
CTE는 물리적 공간을 차지하지 않습니다. join을 사용할 수있는 결과 집합 일뿐입니다.
임시 테이블은 임시입니다. 인덱스를 생성하고 모든 변수를 정의해야하는 일반 테이블처럼 제한 할 수 있습니다.
세션 내에서만 임시 테이블의 범위. 예 : 두 개의 SQL 쿼리 창 열기
create table #temp(empid int,empname varchar)
insert into #temp
select 101,'xxx'
select * from #temp
첫 번째 창 에서이 쿼리를 실행 한 다음 두 번째 창에서 아래 쿼리를 실행하면 차이점을 찾을 수 있습니다.
select * from #temp
파티에 늦었지만 ...
내가 일하는 환경은 제약이 많으며 일부 공급 업체 제품을 지원하고보고와 같은 "부가가치"서비스를 제공합니다. 정책 및 계약 제한으로 인해 일반적으로 별도의 테이블 / 데이터 공간의 고급 스러움 및 / 또는 영구 코드 생성 기능이 허용되지 않습니다 [응용 프로그램에 따라 조금 더 나아집니다].
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에 대한 것입니다 (데이터 공간을 확보 할 때까지).
CTE의 우수한 성능을 현명하게 발견 한 한 가지 용도는 상대적으로 복잡한 쿼리를 각각 수백만 행이있는 몇 개의 테이블에 조인해야하는 곳이었습니다.
CTE를 사용하여 먼저 인덱스 열을 기반으로 하위 집합을 선택하여 이러한 테이블을 각각 몇 천 개의 관련 행으로 줄인 다음 CTE를 기본 쿼리에 연결했습니다. 이것은 내 쿼리의 런타임을 기하 급수적으로 줄였습니다.
CTE에 대한 결과가 캐시되지 않고 테이블 변수가 더 나은 선택 일 수는 있지만 실제로 시도해보고 위의 시나리오에 적합하다는 것을 알았습니다.
방금 CTE와 CTE가 아닌 (모든 유니온 인스턴스에 대해 쿼리가 입력 된) 둘 다 ~ 31 초가 걸렸습니다. CTE는 코드를 더 읽기 쉽게 만들었지 만 241 줄에서 130 줄로 줄였습니다. 반면 임시 테이블은 132 줄로 줄이고 5 초가 걸렸습니다. 농담이 없습니다. 이 테스트는 모두 캐시되었습니다. 쿼리는 모두 여러 번 실행되었습니다.
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