HEAP 테이블에 대한 유효한 사용 시나리오는 무엇입니까?


31

현재 레거시 시스템으로 일부 데이터 가져 오기를 수행 중이며이 시스템이 단일 클러스터형 인덱스를 사용하지 않는 것을 발견했습니다. 빠른 Google 검색에서 HEAP 테이블의 개념을 소개했지만 이제 클러스터 된 테이블보다 HEAP 테이블을 선호해야하는 사용 시나리오가 궁금합니다.

내가 이해하는 한 HEAP 테이블은 감사 테이블 및 / 또는 삽입이 선택보다 훨씬 자주 발생하는 경우에만 유용합니다. 유지 관리 할 클러스터형 인덱스가 없기 때문에 디스크 공간과 디스크 I / O를 절약 할 수 있으며 매우 드문 읽기로 인해 추가 조각화가 문제가되지 않습니다.


1
SQL Server에 대해 이야기하고 있습니까?
a_horse_with_no_name

예 @a_horse_with_no_name, 그 SRY 언급하는 것을 잊었다
marc.d

힙 테이블은 수백만 개의 행이있는 테이블에 적합합니다. 단점은 데이터가 물리적으로 분류되지 않기 때문에 많은 공간을 차지할 수 있다는 것입니다. 또한 인덱스에 의존하여 쿼리를 조정합니다. 성능 문제로 인해 클러스터형 인덱스를 전혀 사용하지 않는 곳에서 일했습니다. 클러스터 된 인덱스 선택이 잘못 되었기 때문에 힙 테이블 만 사용하면 걱정할 필요가 없습니다. 더 나은 솔루션은 엔터프라이즈 버전의 SQL Server를 사용하고 큰 테이블을 가로로 분할하는 것입니다. 그러나 ent가


답변:


22

유일하게 유효한 용도는

  • 가져 오기 / 내보내기 / ETL 프로세스에 사용되는 스테이징 테이블.
  • 다음을 사용하여 임시, 단기 및 임시 테이블 백업 SELECT * INTO..

스테이징 테이블은 일반적으로 사용 전 / 후에 상당히 평평하고 잘립니다.

클러스터 된 인덱스는 일반적으로 데이터 크기에 비해 크기가 작습니다. 데이터 인덱스 구조의 가장 낮은 수준입니다.

힙 테이블에도 문제가 있습니다. 적어도 이것들 :

참조


2
일반적으로 두 가지 별도의 작업에 힙을 사용합니다. 임시 테이블이 효과적으로 작동하기 위해 세트가 클 때 데이터를 임시로 저장하는 데 사용하는 ETL 스테이징 및 작업 테이블. 다음로드시 모두 잘립니다.
Zane

그런데 좋은 질문입니다.
Zane

1
약간의 조정-변경하기 전에 작은 테이블의 빠른 백업을 작성하기 위해 SELECT INTO를 수행하면 기본적으로 힙이 작성됩니다. 나는 그것이 유효한 사용이라고 말하고 싶지만 그것은 단지 nit-picking입니다. 작업이 완료된 것을 알 자마자 그 힙을 제거하고 싶습니다.
브렌트 오자르

@ 브렌트 오자 (BrentOzar) : 동의합니다. 내 대답의 정신은 "장기적이고 지속적인 테이블"이지만 업데이트하겠습니다
gbn

9

주요 고려 사항

힙에 대한 하나의 중요한 이점과 클러스터 테이블에 대한 하나의 장점, 그리고 어느 쪽이든 갈 수있는 세 번째 고려 사항이 있습니다.

  • 힙은 간접 계층을 저장합니다. 인덱스는 디스크 위치를 직접 (실제로는 아니지만 가능한 직접적으로) 가리키는 행 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에서 클러스터링되므로 팩트 테이블에 대한 병합 조인으로 미리 정렬됩니다.

클러스터링 인덱스를 사용하는 데는 몇 가지 이유가 있지만 이러한 이유 중 어느 것도 적용되지 않으면 오버 헤드가 가치가 없을 수 있습니다. 나는 클러스터 된 인덱스를 보편적으로 사용하는 사람들 뒤에는 "우리는 항상 이런 식으로 해왔으며" "최상의 방법"이라고 생각합니다. 함께 모두 시도 하여 데이터와 당신의 부하와 가장 적합한 참조하십시오.


5

"가져 오기 / 내보내기 / ETL 프로세스에 사용되는 테이블을 스테이징하는 데 유일하게 유효한 용도"라고 말하는 것이 가장 제한적이라고 생각합니다. 주어진 시스템의 예상 사용 사례를 취한 다음 힙 또는 인덱스 구성 테이블의 장점을 기반으로 선택해야합니다 (Oracle 용어이지만 잘 설명합니다).

우리의 창고는 하루에 15 억 개의 행을로드하며 읽기뿐만 아니라 동시 쓰기 및 처리를 지원해야합니다. 관계형 저장소는 OLAP 데이터베이스를 지원하므로 읽기는 주로 테이블 스캔 인 경향이 있습니다. 생성 된 보고서 및 다운 스트림 피드도 일반적으로 인덱스가 유용 할 정도로 선택성이 충분하지 않습니다. 이 시스템은 슬라이딩 데이터 창을 지원하므로 일단 테이블이로드되면 거의 다시 테이블에 쓰지 않으며 파티션 분할, 스위치 및 병합을위한 Sch-M 잠금과 읽기 등을위한 Sch-S 잠금을 요구하는 테이블 분할의 구현이 다소 열악한 경우 파티션 된 테이블도 있지만 시스템은 많은 테이블을 사용해야했습니다. 많은 테이블을 사용하면 데이터 세그먼트 화 및 정리주기가 쉬워지고 경합이 줄어 듭니다.

따라서 임의의 열에 인덱스 구성 테이블 (클러스터 테이블)의 오버 헤드가 추가되어 힙으로 bcp하고 OLAP 파티션을 처리하며 일부 테이블 스캔 쿼리를 수행 한 다음 3 일 후에 삭제됩니다. 그만한 가치가 없습니다. 우리의 경우에는 데이터가 큰 그리드 클러스터에서 돌아와서 데이터에 대한 순서가 없으므로 클러스터 된 인덱스가있는 테이블에 삽입하면 "핫 스팟"및 페이지 분할 등과 같은 다른 문제가 발생할 수 있습니다.

또한 페이지가 흩어져 있다는 주장은 다소 불분명합니다. 클러스터형 인덱스는 파일이 페이지 전체에 흩어져있을 수도 있습니다. 다시 인덱싱 한 후 (1000 페이지 이상 가정) 힙보다 낫지 만 다시 인덱싱해야했습니다.

스파 스 열과 압축을 사용하여 공간을 절약 할 수도 있습니다. 경우에 따라 클러스터 된 인덱스가있는 테이블에서 선택하는 것이 더 빠를 수는 있지만로드 및 유지 관리에 필요한 리소스를 사용하여이를 계산해야합니다.

[편집] 아마 파티션되지 않은 팩트 테이블 만 힙이라는 것을 분명히해야합니다. 분할 된 테이블과 차원 테이블에는 모두 효율적인 조회 등을 지원하기 위해 클러스터 된 인덱스가 있습니다. [Edit2] 25 억에서 15 억으로 수정되었습니다. 그 두 숫자는 서로 옆에 있습니다. 전화로 응답을 입력하면 어떻게됩니까?

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