SQL Server에서 테이블 변수와 임시 테이블을 언제 사용해야합니까?


298

테이블 변수에서 자세한 내용을 배우고 있습니다. 임시 테이블은 항상 디스크에 있고 테이블 변수는 메모리에 있습니다. 즉, 테이블 변수는 임시 테이블보다 적은 IO 작업을 사용하기 때문에 테이블 변수의 성능이 임시 테이블보다 낫습니다.

그러나 때때로 메모리에 포함될 수없는 테이블 변수에 레코드가 너무 많으면 테이블 변수가 임시 테이블처럼 디스크에 저장됩니다.

그러나 나는 "너무 많은 기록"이 무엇인지 모른다. 10 만 레코드? 또는 1000,000 레코드? 사용중인 테이블 변수가 메모리에 있는지 디스크에 있는지 어떻게 알 수 있습니까? SQL Server 2005에는 테이블 변수의 스케일을 측정하거나 테이블 변수가 메모리에서 디스크에 배치 될 때 알려주는 기능이나 도구가 있습니까?


5
테이블 변수는 거의 항상 tempDB"메모리에"있다는 신화입니다. 또한 테이블 변수는 항상 쿼리 최적화 프로그램에 의해 정확히 한 행을 보유하는 것으로 간주됩니다. 더 많은 행이 있으면 실행 계획이 심각하게 잘못 될 수 있습니다.
marc_s


2
@marc_s-해당 문장에서 "거의"을 삭제할 수 있습니다. 그것은 항상 있습니다 tempdb(그러나 또한 완전히 기억에있을 수 있습니다)
Martin Smith

2
SQL 2014를 사용하면 메모리에 테이블 변수를 만들 수 있습니다.
paparazzo

답변:


362

귀하의 질문에 따르면 테이블 변수와 임시 테이블을 둘러싼 일반적인 오해에 굴복했습니다.

나는 DBA 사이트에 대한 광범위한 답변을 작성했습니다 에서 두 개체 유형의 차이점을 살펴보면서 . 이것은 또한 디스크 대 메모리에 대한 귀하의 질문을 해결합니다 (두 가지 행동에 큰 차이가 없었습니다).

테이블 변수와 로컬 임시 테이블의 사용시기에 관한 제목의 질문과 관련하여 항상 선택할 수있는 것은 아닙니다. 예를 들어 함수에서 테이블 변수 만 사용할 수 있으며 하위 범위의 테이블에 써야하는 경우 테이블 만 #temp수행됩니다 (테이블 값 매개 변수는 읽기 전용 액세스 허용 ).

선택의 여지가있는 경우 몇 가지 제안 사항이 아래에 나와 있습니다 (가장 안정적인 방법은 특정 작업으로 두 가지를 모두 테스트하는 것임).

  1. 테이블 변수에서 작성할 수없는 인덱스가 필요한 경우 물론 #temporary테이블이 필요 합니다. 그러나 이에 대한 자세한 내용은 버전에 따라 다릅니다. SQL Server 2012 이하의 경우 테이블 변수에서 만들 수있는 유일한 인덱스는 UNIQUE또는PRIMARY KEY 제약 조건을 . SQL Server 2014에는에서 사용할 수있는 옵션의 하위 집합에 대한 인라인 인덱스 구문이 도입되었습니다 CREATE INDEX. 필터링 된 인덱스 조건을 허용하기 위해 확장되었습니다. 그러나 INCLUDE-d 컬럼 또는 columnstore 인덱스가있는 인덱스는 여전히 테이블 변수에서 작성할 수 없습니다.

  2. 테이블에서 많은 수의 행을 반복적으로 추가 및 삭제하려면 테이블을 사용 #temporary하십시오. 지원 TRUNCATE( DELETE대형 테이블 보다 효율적 ) 및 추가 인서트 다음에 오는 추가 인서트 TRUNCATEDELETE 여기에 설명 것처럼 있습니다 .

  3. 많은 수의 행을 삭제하거나 업데이트 할 경우 임시 테이블이 행 변수 공유를 사용할 수있는 경우 테이블 변수보다 훨씬 더 잘 수행 될 수 있습니다 (예를 들어 아래의 "행 세트 공유 효과"참조).
  4. 테이블을 사용하는 최적의 계획이 데이터에 따라 다를 경우 테이블을 사용 #temporary하십시오. 이는 통계에 따라 계획에 따라 데이터에 따라 동적으로 재 컴파일 될 수 있도록합니다 (저장 프로 시저 캐시 된 임시 테이블의 경우 재 컴파일 동작). 을 별도로 이해해야 함).
  5. 테이블을 사용하는 쿼리에 대한 최적 계획이 변경되지 않을 경우 통계 작성의 오버 헤드를 건너 뛰고 다시 컴파일하기 위해 테이블 ​​변수를 고려할 수 있습니다 (원하는 계획을 수정하는 데 힌트가 필요할 수 있음).
  6. 테이블에 삽입 된 데이터의 소스가 잠재적으로 비쌉니다 SELECT 명령문의 경우 테이블 변수를 사용하면 병렬 계획을 사용하여이 가능성을 차단할 수 있습니다.
  7. 외부 사용자 트랜잭션의 롤백에서 살아 남기 위해 테이블의 데이터가 필요한 경우 테이블 변수를 사용하십시오. 가능한 유스 케이스는 긴 SQL 배치에서 다른 단계의 진행 상황을 로깅하는 것일 수 있습니다.
  8. #temp사용자 트랜잭션 내 에서 테이블을 사용하는 경우 잠금은 테이블 변수보다 오래 지속될 수 있으며 (잠재적으로 트랜잭션 끝과 잠금 유형 및 분리 레벨에 따라 명령문 끝까지) 유지 될 수 있습니다 tempdb. 사용자 거래가 종료됩니다. 따라서 이것은 테이블 변수 사용을 선호 할 수 있습니다.
  9. 저장된 루틴 내에서 테이블 변수와 임시 테이블을 모두 캐시 할 수 있습니다. 캐시 된 테이블 변수에 대한 메타 데이터 유지 보수는 테이블에 대한 메타 데이터 유지 보수보다 적습니다 #temporary. Bob Ward는 tempdb프레젠테이션 에서 동시성이 높은 조건에서 시스템 테이블에 대한 추가 경합이 발생할 수 있다고 설명합니다. 또한 소량의 데이터를 처리 할 때 성능에 상당한 차이가 생길 수 있습니다 .

행 집합 공유의 효과

DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);

CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);

INSERT INTO @T 
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2

SET STATISTICS TIME ON

/*CPU time = 7016 ms,  elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;

/*CPU time = 6234 ms,  elapsed time = 7236 ms.*/
DELETE FROM @T

/* CPU time = 828 ms,  elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;

/*CPU time = 672 ms,  elapsed time = 980 ms.*/
DELETE FROM #T

DROP TABLE #T

2
마틴 스미스 자매 필자의 경우 Store 절차 내의 다른 쿼리에서 사용하기 위해 ID 값 집합을 저장하려고합니다. 그래서 당신은 무엇을 추천합니까?
Jeancarlo Fontalvo

@JeancarloFontalvo-기본 키가 켜져 id있고 사용 하는 테이블 변수가 적합 OPTION (RECOMPILE)할 것입니다.하지만 둘 다 테스트하십시오.
Martin Smith

메타 데이터 경합이 임시 테이블 및 테이블 변수 모두에 대해 동일합니까?
Syed Aqeel Ashiq

@Syed. 일반적으로 TV에는 적습니다. 사용자 트랜잭션 내부에있는 경우 잠금을 더 일찍 해제 할 수 있습니다. Bob Ward 링크도 참조하십시오.
Martin Smith

73

아주 적은 양의 데이터 (수천 바이트)의 경우 테이블 변수를 사용하십시오.

많은 데이터에 임시 테이블 을 사용하십시오.

이를 고려하는 또 다른 방법 : 인덱스, 자동화 된 통계 또는 SQL 옵티마이 저의 장점을 활용할 수 있다고 생각되면 데이터 세트가 테이블 변수에 비해 너무 클 수 있습니다.

내 예에서는 영구 테이블을 UPDATE / INSERT하기 전에 약 20 개의 행을 형식에 넣고 그룹으로 수정하고 싶었습니다. 따라서 테이블 변수가 완벽합니다.

그러나 한 번에 수천 행을 백필하기 위해 SQL을 실행 중이며 임시 테이블 이 테이블 변수보다 훨씬 우수하다는 것을 분명히 말할 수 있습니다 .

이것은 비슷한 크기의 이유로 CTE가 관심사와 다른 점이 아닙니다. CTE의 데이터가 매우 작은 경우 CTE가 옵티마이 저가 제공하는 것보다 성능이 우수하거나 더 우수하다는 것을 알 수 있습니다. 그것은 당신을 아프게합니다.

내 이해는 주로 http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/를 기반으로 합니다.


테이크 아웃은 테이블 변수가 작은 데이터 세트에는 적합하지만 더 큰 데이터 세트에는 임시 테이블을 사용합니다. 수천 행의 쿼리가 있습니다. 테이블 변수에서 임시 테이블로 전환하면 쿼리 시간이 40 초에서 5 초로 줄어 듭니다.
liang

42

마이크로 소프트 는 여기서 말한다

테이블 변수에는 분산 통계가 없으며 재 컴파일을 트리거하지 않습니다. 따라서 대부분의 경우 옵티마이 저는 테이블 변수에 행이 없다는 가정하에 쿼리 계획을 작성합니다. 따라서 많은 수의 행 (100 개 이상)이 필요한 경우 테이블 변수 사용에주의해야합니다. 이 경우 임시 테이블이 더 나은 솔루션 일 수 있습니다.


14

나는 Abacus에 전적으로 동의합니다 (죄송합니다-의견이 충분하지 않습니다).

또한, 반드시 내려 오지 않는 명심 얼마나 많은 당신이 가진 기록하지만, 크기 레코드의.

예를 들어, 각각 50 개의 열이있는 1,000 개의 레코드와 5 개의 열이있는 100,000 개의 레코드 간의 성능 차이를 고려 했습니까?

마지막으로, 필요한 것보다 더 많은 데이터를 쿼리 / 저장하고 있습니까? 다음은 SQL 최적화 전략에 대한 유용한 정보 입니다. 특히 데이터를 모두 사용하지 않는 경우 당기는 데이터의 양을 제한하십시오 (일부 SQL 프로그래머는 게으르고 작은 하위 집합 만 사용하더라도 모든 것을 선택합니다). SQL 쿼리 분석기가 가장 친한 친구가 될 수 있음을 잊지 마십시오.


4

변수 테이블 은 현재 세션에서만 사용할 수 있습니다. 예를 들어, EXEC현재 저장 프로 시저 내에서 다른 저장 프로 시저 가 필요한 경우 테이블을 전달해야합니다. Table Valued Parameter물론 이는 성능에 영향을 미치며 임시 테이블 에서는이 작업 만 수행 할 수 있습니다. 임시 테이블 이름 전달

임시 테이블을 테스트하려면

  • 개방형 관리 스튜디오 쿼리 편집기
  • 임시 테이블 만들기
  • 다른 쿼리 편집기 창을 엽니 다
  • 이 표에서 선택 "사용 가능"

변수 테이블을 테스트하려면 다음을 수행하십시오.

  • 개방형 관리 스튜디오 쿼리 편집기
  • 변수 테이블 만들기
  • 다른 쿼리 편집기 창을 엽니 다
  • 이 표에서 "사용할 수 없음"을 선택하십시오.

내가 경험 한 다른 것 : 스키마에 GRANT테이블을 만들 수 있는 권한 이 없으면 변수 테이블을 사용하십시오.


3

선언 된 테이블에 데이터를 작성 declare @tb하고 다른 테이블과 조인 한 후 임시 테이블에 비해 응답 시간 tempdb .. # tb이 훨씬 빠릅니다.

나는 그들에 가입하면 @tb 시간이 달리 결과를 반환하기 위해 더 이상 #tm , 반환은 거의 순간입니다.

10,000 개의 행 조인 및 5 개의 다른 테이블과 조인하여 테스트를 수행했습니다.


이 수치를 얻기 위해 실행 한 테스트를 게시 할 수 있습니까?
댄 데프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.