테이블 변수에 인덱스 생성


190

SQL Server 2000에서 테이블 변수에 대한 인덱스를 만들 수 있습니까?

DECLARE @TEMPTABLE TABLE (
     [ID] [int] NOT NULL PRIMARY KEY
    ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL 
)

에 색인을 만들 수 있습니까 Name?


3
두 종류의 임시 테이블을 생성하는 데 비용이 발생합니다. 그리고 인덱스가 필요한 데이터가 너무 많으면 실제 테이블을 사용하는 것이 좋습니다. 거래에 안전하도록 설정 한 경우 spid 또는 사용자 ID별로 필터링 한 다음 마지막에 정리하십시오. 실제 테이블 v 임시 테이블에는 모두 기복이 있지만 성능에 문제가있는 경우 실제 테이블로 시도하십시오.
u07ch

임시 테이블 'IS'는 실제 테이블이며 완료되면 사라집니다. 실제 차이점 (자동으로 사라지는 것 제외)은 TempDB에 있다는 것입니다. 인덱스 및 제약 조건과 관련하여 실제로는 엄청납니다. 코드의 다른 실행뿐만 아니라 인스턴스의 다른 데이터베이스에서 실행되는 코드와도 이름 충돌로 끝날 수 있기 때문입니다.
bielawski

@bielawski 이것은 임시 테이블이 아닌 테이블 변수입니다. 테이블 변수는 명시 적으로 명명 된 제약 조건을 허용하지 않으며 시스템 생성 이름은 고유해야합니다. 2014 년부터 명명 된 인덱스를 허용하지만 인덱스는 객체가 아닌 객체 내에서 고유하게 명명되어야하기 때문에 문제가되지 않습니다.
Martin Smith

내 요지는 2 배였다. 1) 트랜잭션 얽힘을 피하기 위해 변수를 사용하는 것 외에 임시 테이블과 테이블 변수 사이에는 실질적인 차이가 없습니다. 그러나 V-2000에는 제약 조건, 색인 ...을 변수에 추가하기위한 구문이 없습니다. 2) 대신에, 인덱스 테이블 등이라는 부속물은 임시 테이블을 사용하여 주어진 하나 정적 이름을 사용하는 경우 동일 SP의 동시 실행 사본 충돌! 아래의 메커니즘은 이러한 정확한 상황에서 명명 된 인덱스 충돌로 인한 SP 실패를 추적했기 때문에 명시 적으로 개발되었습니다. 그들은 고유해야합니다.
bielawski

1
@bielawski- 인덱스 이름이 객체간에 고유 할 필요는 없습니다. 구속 조건 이름 만 있습니다. 이것은 테스트하기가 쉽지 않습니다. 그냥 실행CREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Martin Smith

답변:


363

이 질문에는 SQL Server 2000이라는 태그가 붙어 있지만 최신 버전으로 개발하는 사람들의 이익을 위해 먼저 해결하겠습니다.

SQL Server 2014

아래에 설명 된 제약 조건 기반 인덱스를 추가하는 방법 외에도 SQL Server 2014에서 고유하지 않은 인덱스를 테이블 변수 선언에서 인라인 구문으로 직접 지정할 수 있습니다.

이에 대한 예제 구문은 다음과 같습니다.

/*SQL Server 2014+ compatible inline index syntax*/
DECLARE @T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
       INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);

포함 된 열이 포함 된 필터링 된 인덱스 및 인덱스는 현재이 구문으로 선언 할 수 없지만 SQL Server 2016에서는 이를 조금 더 완화합니다. CTP 3.1부터는 테이블 변수에 대해 필터링 된 인덱스를 선언 할 수 있습니다. RTM까지 수 있습니다 포함 컬럼도 허용되는 경우가 있지만, 현재 위치는이 때문이다 "가능성으로 인해 자원 제약에 SQL16로하지 않습니다"

/*SQL Server 2016 allows filtered indexes*/
DECLARE @T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)

SQL Server 2000-2012

이름에 색인을 만들 수 있습니까?

짧은 대답 : 그렇습니다.

DECLARE @TEMPTABLE TABLE (
  [ID]   [INT] NOT NULL PRIMARY KEY,
  [Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
  UNIQUE NONCLUSTERED ([Name], [ID]) 
  ) 

자세한 답변은 다음과 같습니다.

SQL Server의 기존 테이블은 클러스터형 인덱스를 갖거나 으로 구성 될 수 있습니다.

클러스터 된 인덱스는 중복 키 값을 허용하지 않도록 고유 한 것으로 선언하거나 기본값을 고유하지 않은 것으로 지정할 수 있습니다. 고유하지 않은 경우 SQL Server는 자동으로 고유 키를 중복 키에 추가하여 고유 키를 만듭니다.

비 클러스터형 인덱스도 고유하게 명시 적으로 선언 할 수 있습니다. 그렇지 않으면 고유하지 않은 경우 SQL Server 는 행 로케이터 (클러스터형 인덱스 키 또는 힙에 대한 RID )를 모든 인덱스 키 (중복이 아닌)에 추가하여 다시 고유성을 보장합니다.

SQL Server 2000-2012에서 테이블 변수에 대한 인덱스는 UNIQUE또는 PRIMARY KEY제약 조건을 만들어 내재적으로 만 만들 수 있습니다 . 이 제약 조건 유형의 차이점은 기본 키가 Null을 허용하지 않는 열에 있어야한다는 것입니다. 고유 제한 조건에 참여하는 열은 널 입력 가능할 수 있습니다. ( NULLs가 있는 상태에서 SQL Server의 고유 제약 조건 구현은 SQL 표준에 지정된 고유 제약 조건 이 아닙니다). 또한 테이블에는 하나의 기본 키만 있지만 여러 개의 고유 제한 조건이있을 수 있습니다.

이러한 논리적 제약 조건은 물리적으로 고유 한 인덱스로 구현됩니다. 명시 적으로 지정하지 않으면 PRIMARY KEY클러스터형 인덱스가되고 클러스터되지 않은 고유 제약 조건이되지만 제약 조건 선언 을 지정 CLUSTERED하거나 NONCLUSTERED명시 적으로 지정하여이 동작을 재정의 할 수 있습니다 (예제 구문).

DECLARE @T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)

위의 결과로 SQL Server 2000-2012의 테이블 변수에 대해 다음과 같은 인덱스가 암시 적으로 생성 될 수 있습니다.

+-------------------------------------+-------------------------------------+
|             Index Type              | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index              | Yes                                 |
| Nonunique Clustered Index           |                                     |
| Unique NCI on a heap                | Yes                                 |
| Non Unique NCI on a heap            |                                     |
| Unique NCI on a clustered index     | Yes                                 |
| Non Unique NCI on a clustered index | Yes                                 |
+-------------------------------------+-------------------------------------+

마지막 것은 약간의 설명이 필요합니다. 이 답변의 시작 부분에있는 테이블 변수 정의에서 고유 하지 않은 비 클러스터형 인덱스 켜기 Name고유 인덱스를 통해 시뮬레이트됩니다 Name,Id(SQL Server는 클러스터 된 인덱스 키를 비 고유 NCI 키에 자동으로 추가 함을 기억하십시오).

고유하지 않은 클러스터형 인덱스는 IDENTITY고유 식별자로 작동 할 열을 수동으로 추가하여 얻을 수도 있습니다 .

DECLARE @T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)

그러나 이것은 고유하지 않은 클러스터형 인덱스가 SQL Server에서 실제로 어떻게 구현되는지에 대한 정확한 시뮬레이션이 아닙니다. 이는 모든 행에 "Uniqueifier"를 추가하기 때문입니다. 그것을 필요로하는 사람들 만이 아닙니다.


1
참고 : 2000-2012 솔루션은 텍스트 열 <= 900 바이트 인 경우에만 작동합니다. 즉. varchar (900), nvarchar (450)
Andre Figueiredo

1
@AndreFigueiredo 그렇습니다. 해당 버전의 영구 테이블에서도 인덱스 키의 최대 크기입니다.
Martin Smith

1
SQL 2014 답변이 Azure에서 잘 작동한다는 것을 알고 싶었습니다. 고마워 마틴!
Jaxidian

13

성능 관점에서 변수를 선호하는 @temp 테이블과 #temp 테이블 간에는 차이가 없음을 이해해야합니다. 그것들은 같은 장소 (tempdb)에 상주하며 같은 방식으로 구현됩니다. 모든 차이점은 추가 기능에 나타납니다. 이 놀랍도록 완벽한 글을 참조하십시오 : /dba/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

테이블 또는 스칼라 함수와 같이 임시 테이블을 사용할 수없는 경우가 있지만 v2016 이전의 대부분의 다른 경우 (필터링 된 인덱스도 테이블 변수에 추가 할 수있는 경우)에는 #temp 테이블을 사용하면됩니다.

tempdb에서 명명 된 인덱스 (또는 제약 조건)를 사용하는 데 따른 단점은 이름이 충돌 할 수 있다는 것입니다. 이론적으로 다른 프로 시저뿐만 아니라 #temp 테이블의 복사본에 동일한 인덱스를 넣으려고하는 프로 시저 자체의 다른 인스턴스를 사용하면 매우 쉽습니다.

이름 충돌을 피하기 위해 일반적으로 다음과 같이 작동합니다.

declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (@cmd);

이렇게하면 동일한 프로 시저를 동시에 실행하더라도 이름이 항상 고유하게됩니다.


varchar (40) 뒤에 하나의 누락 된 괄호가 있습니다.
Tejasvi Hegde

1
명명 된 인덱스에는 문제가 없습니다. 인덱스는 테이블 내에서 고유하게 명명되어야합니다. 문제는 명명 된 제약 조건에 있으며 가장 좋은 해결책은 일반적으로 임시 테이블에서 명명하지 않는 것입니다. 명명 된 제약 조건은 임시 테이블 객체 캐싱을 방지합니다.
Martin Smith

1
특정 버전에서만 적용되어야합니다 (모든 버전에서 적용되는 경우). 동시 실행 중에 명명 된 인덱스의 충돌로 인한 sp 오류를 추적했기 때문에이 해결 방법을 구체적으로 찾아야했습니다.
bielawski

@bielawski 2016을 사용하고 있습니까? 임시 테이블의 명명 된 인덱스가 동시 환경에 대한 위험인지 궁금합니다.
Elaskanator

1
@Elaskanator 그렇습니다. 로드시 SQL 메타 데이터 테이블에서 경합을 발견하여 색인 이름을 제거하면 문제점이 해결되었습니다. 이것은 SQL 2016 년이었다
댄 데프

0

Table 변수에 큰 데이터가 있으면 table variable (@table) 대신 temp table (#table)을 만듭니다 .table 변수는 삽입 후 인덱스를 만들 수 없습니다.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. 고유 한 클러스터형 인덱스로 테이블 만들기

  2. Temp "#Table"테이블에 데이터 삽입

  3. 비 클러스터형 인덱스를 만듭니다.

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);

불필요한 정렬을 피하기 위해 insert 문 다음에 인덱스 생성
Boopathi.Indotnet

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