주요 고려 사항
힙에 대한 하나의 중요한 이점과 클러스터 테이블에 대한 하나의 장점, 그리고 어느 쪽이든 갈 수있는 세 번째 고려 사항이 있습니다.
힙은 간접 계층을 저장합니다. 인덱스는 디스크 위치를 직접 (실제로는 아니지만 가능한 직접적으로) 가리키는 행 ID를 포함합니다. 따라서 힙에 대한 인덱스 탐색은 클러스터 된 테이블에 대한 비 클러스터형 인덱스 탐색의 약 절반이 소요됩니다.
클러스터 된 인덱스는 그 자체로 (거의) 사용 가능한 인덱스 덕분에 정렬됩니다. 클러스터링 인덱스는 데이터의 물리적 순서에 반영되므로 실제 데이터 자체에서 상대적으로 적은 공간을 차지하므로 물론 저장해야합니다. 물리적으로 정렬되어 있기 때문에이 인덱스에 대한 범위 스캔은 시작점을 찾은 다음 끝점으로 매우 효율적으로 압축 될 수 있습니다.
힙의 인덱스는 RID (64 비트)를 참조합니다. 언급 한 바와 같이, 클러스터 된 테이블의 비 클러스터형 인덱스는 클러스터링 키를 참조합니다. 클러스터링 키는 더 작거나 (32 비트 INT
), 동일 BIGINT
하거나 ( 64 비트 ) 또는 더 클 수 있습니다 (48 비트 DATETIME2()
+ 32 비트 INT
, 또는 128 비트 GUID). 분명히 더 넓은 참조는 더 크고 비싼 지수를 만듭니다.
공간 요구 사항
이 두 테이블로
CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)
CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)
... 각각 8.7M 레코드로 채워졌으며 필요한 공간은 두 데이터 모두에 150MB였습니다. 클러스터 테이블 인덱스의 경우 120MB, 비 클러스터 테이블 인덱스의 경우 310MB. 이는 클러스터 된 인덱스가 RID보다 좁고 클러스터링 인덱스가 대부분 "공짜"임을 반영합니다. 에 고유 인덱스가 없으면 ID2
필요한 인덱스 공간이 클러스터되지 않은 테이블의 경우 155MB (예상 절반)이지만 클러스터 된 PK의 경우 150KB 에 불과합니다.
따라서 32 비트 인덱스 (공칭 적으로 총 64 비트)가있는 클러스터 된 테이블에서 32 비트 필드의 비 클러스터형 인덱스는 120MB를 사용하는 반면 64 비트가있는 힙의 32 비트 필드 인덱스는 RID (총 96 비트, 명목상)는 155MB를 차지했으며, 64 비트에서 96 비트 키로의 순진한 예상보다 50 % 증가한 것보다 약간 작지만, 실제로는 크기의 효과적인 차이를 줄이는 오버 헤드가 있습니다.
두 테이블을 채우고 인덱스를 만들려면 각 테이블에 대해 동일한 시간이 걸렸습니다. 스캔이나 검색과 관련된 간단한 테스트를 수행 한 결과, 테이블간에 중요한 성능 차이가 발견되지 않았는데, 이는 gbn이 유용하게 연계한 Microsoft 백서와 일치합니다. 상기 논문은 고도의 동시 액세스에 대해 상당한 차이를 보인다; 왜 그런 일이 일어 났는지 잘 모르겠습니다. 대량 OLTP 시스템을 사용하는 사람보다 더 많은 경험을 가진 사람이 우리에게 말할 수 있기를 바랍니다.
~ 40 바이트의 임의 가변 길이 데이터를 추가해도이 동등성은 변경되지 않았습니다. 일 교체 INT
하거나 넓은 UUID를 함께의를하지 않았다 (각 테이블은 동일한 범위에 대해 둔화되었다). 마일리지는 다를 수 있지만 대부분의 경우 인덱스를 사용할 수 있는지 여부 는 어떤 종류보다 중요합니다.
산산조각
테이블이 힙이거나 인덱스가 클러스터형 인덱스가 아니기 때문에 비 클러스터형 인덱스에 대해 범위 스캔을 수행하려면 인덱스를 스캔 한 다음 각 히트에 대해 테이블을 검색해야합니다. 이것은 매우 비쌀 수 있으므로 때로는 테이블을 스캔하는 것이 더 저렴합니다. 그러나 커버링 인덱스를 사용하여이 문제를 해결할 수 있습니다. 테이블을 클러스터했는지 여부에 관계없이 적용됩니다.
@gbn이 지적했듯이 힙을 압축하는 간단한 방법은 없습니다. 그러나 테이블이 시간이 지남에 따라 점차 증가하는 경우 (일반적인 경우) 삭제로 인해 사용 가능한 공간이 새 데이터로 채워 지므로 낭비가 거의 없습니다.
내가 본 몇 가지 힙 대 클러스터 테이블 토론 인덱스가없는 힙이 항상 테이블 스캔이 필요하다는 점에서 인덱스가없는 힙이 클러스터 테이블보다 열등하다는 호기심 많은 밀짚 꾼 논쟁을합니다. 이것은 사실이지만,보다 의미있는 비교는 "큰 인덱스 화 된 클러스터 테이블"대 "큰 인덱스 화 된 힙"입니다. 테이블이 매우 작거나 항상 테이블 스캔을 수행하려는 경우 클러스터링 여부에 관계없이 중요하지 않습니다.
클러스터 된 테이블의 각 인덱스는 클러스터링 인덱스를 참조하므로 사실상 모든 인덱스를 포함합니다. 인덱스 열과 클러스터 열을 참조하는 쿼리는 테이블 조회없이 인덱스 스캔을 수행 할 수 있습니다. 클러스터링 인덱스가 가상 키인 경우 일반적으로 가치가 없지만 어쨌든 검색해야하는 비즈니스 키인 경우 좋은 기능입니다.
TL; DR
저는 OLTP 전문가가 아닌 데이터웨어 하우징 전문가입니다. 사실 테이블의 경우 거의 항상 필드에서 클러스터링 인덱스를 사용하는데 주로 범위 스캔 (대개 날짜 필드)이 필요할 수 있습니다. 차원 테이블의 경우 PK에서 클러스터링되므로 팩트 테이블에 대한 병합 조인으로 미리 정렬됩니다.
클러스터링 인덱스를 사용하는 데는 몇 가지 이유가 있지만 이러한 이유 중 어느 것도 적용되지 않으면 오버 헤드가 가치가 없을 수 있습니다. 나는 클러스터 된 인덱스를 보편적으로 사용하는 사람들 뒤에는 "우리는 항상 이런 식으로 해왔으며" "최상의 방법"이라고 생각합니다. 함께 모두 시도 하여 데이터와 당신의 부하와 가장 적합한 참조하십시오.