테이블 변수에 인덱스 생성


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.