기본 키는 언제 비 클러스터형으로 선언해야합니까?


169

앞서 질문 한 다른 질문에 대한 테스트 데이터베이스를 만들면서 기본 키를 선언 할 수 있다는 사실을 기억했습니다. NONCLUSTERED

NONCLUSTERED기본 키가 아닌 기본 키를 언제 사용 CLUSTERED하시겠습니까?

미리 감사드립니다

답변:


187

문제는 'PK가 NC 여야하는시기'가 아니라 '클러스터형 인덱스의 올바른 키는 무엇입니까?'입니다.

대답은 실제로 데이터를 쿼리하는 방법에 달려 있습니다 . 클러스터형 인덱스는 다른 모든 인덱스에 비해 이점이 있습니다. 항상 모든 열을 포함하므로 항상 포함합니다. 따라서 클러스터형 인덱스를 활용할 수있는 쿼리는 예상 된 열 및 / 또는 조건자를 만족시키기 위해 조회를 사용할 필요가 없습니다.

퍼즐의 또 다른 조각은 인덱스를 어떻게 사용할 수 있습니까? 세 가지 일반적인 패턴이 있습니다.

  • 인덱스에서 단일 키 값을 찾을 때 프로브
  • 키 값 범위를 검색 할 때 범위 스캔
  • 인덱스가 중지 및 소팅 정렬없이 주문을 충족시킬 수있는 경우 요구 사항 별 주문

따라서 예상로드 (쿼리)를 분석하고 인덱스에서 이익을 얻는 특정 액세스 패턴을 사용하기 때문에 많은 수의 쿼리가 특정 인덱스를 사용한다는 것을 발견하면 해당 인덱스를 클러스터형 인덱스로 제안하는 것이 좋습니다.

또 다른 요인은 클러스터 된 인덱스 키가 모든 비 클러스터형 인덱스에서 사용되는 조회 키 이므로 넓은 클러스터형 인덱스 키는 리플 효과를 만들고 모든 비 클러스터형 인덱스와 넓은 인덱스는 더 많은 페이지, 더 많은 I / O를 의미합니다 더 많은 메모리, 더 적은 선량.

좋은 클러스터형 인덱스는 안정적 입니다. 클러스터 된 인덱스 키 값을 변경하면 행을 삭제하고 다시 삽입해야하기 때문에 엔터티 수명 동안 변경되지 않습니다.

그리고 좋은 클러스터형 인덱스는 페이지 분할 및 조각화를 피하기 위해 무작위로 (순서대로 삽입 된 각 키 값이 이전 값보다 큼) 순서대로 증가 FILLFACTOR합니다.

이제 좋은 클러스터형 인덱스 키가 무엇인지 알았으므로 기본 키 (데이터 모델링 논리 속성)가 요구 사항과 일치합니까? 그렇다면 PK를 클러스터링해야합니다. 그렇지 않은 경우 PK는 클러스터되지 않아야합니다.

예를 들어, 판매 사실 테이블을 고려하십시오. 각 항목에는 기본 키인 ID가 있습니다. 그러나 대부분의 쿼리는 날짜와 다른 날짜 사이의 데이터를 요구하므로 클러스터 된 최상의 인덱스 키는 ID가 아니라 판매 날짜가 됩니다. 기본 키와 다른 클러스터형 인덱스를 갖는 또 다른 예는 별개의 값이 매우 적은 키인 '카테고리'또는 '상태'와 같이 매우 낮은 선택성 키입니다. 예를 들어 , 가장 낮은 키로이 낮은 선택도 키를 가진 클러스터 된 인덱스 키를 갖는 것은 특정 '상태'의 모든 항목을 찾는 범위 스캔 때문에 종종 의미가 있습니다.(state, id)

힙을 통한 클러스터되지 않은 기본 키 가능성에 대한 마지막 참고 사항입니다 (즉, 클러스터 된 인덱스가 전혀 없음). 이는 유효한 시나리오 일 수 있습니다. 일반적인 이유는 대량 삽입 성능이 중요한 경우입니다. 힙은 클러스터 색인과 비교할 때 대량 삽입 처리량이 훨씬 우수하기 때문입니다.


1
여기서 "정지 및 이동 정렬없이 인덱스가 주문을 충족시킬 수있는 경우 요구 사항 별 주문"이란 무엇입니까?
Mike Sherrill 'Cat Recall'12

2
@RemusRusanu. +1 매우 유용한 답변. 예제에 관한 한 가지 질문 (state, id). 이 예에서는 "좋은 클러스터형 인덱스가 무작위로 생성되지 않습니다"라는 요구 사항이 충족되지 않습니까? 그렇다면 좋은 클러스터형 인덱스로 간주 할 수 있습니까?
Lijo

26

클러스터형 인덱스를 사용하는 기본 이유는 Wikipedia에 나와 있습니다 .

클러스터링은 데이터 블록을 인덱스와 일치하는 특정 구별 순서로 변경하여 행 데이터가 순서대로 저장됩니다. 따라서 지정된 데이터베이스 테이블에 하나의 클러스터형 인덱스 만 만들 수 있습니다. 군집 인덱스 전체 검색 속도를 크게 향상시킬 있지만 일반적으로 군집 색인과 동일하거나 반대 순서로 데이터에 순차적으로 액세스하는 경우 또는 항목 범위를 선택한 경우 에만 가능 합니다 .

내가 People 테이블을 가지고 있고이 사람들은 Country 열과 고유 한 기본 키를 가지고 있다고 가정하십시오. 인구 통계표이므로 이것이 내가 관심을 갖는 유일한 것입니다. 어떤 나라와 얼마나 많은 독특한 사람들이 그 나라에 묶여 있는지

따라서 국가 열에서만 SELECT WHERE 또는 ORDER BY를 선택할 가능성이 높습니다. 기본 키의 클러스터형 인덱스는 나에게 도움이되지 않습니다 .PK 로이 데이터에 액세스하지 않고이 다른 열로 액세스하고 있습니다. 테이블에 하나의 클러스터형 인덱스 만 가질 수 있으므로 PK를 클러스터형으로 선언하면 국가 별 클러스터형 인덱스를 사용할 수 없습니다.

또한 Clustered vs Nonclustered Indexes 에 대한 좋은 기사가 있는데 , 클러스터 된 인덱스가 SQL Server 6.5에서 삽입 성능 문제를 일으킨다는 사실이 밝혀졌습니다 (적어도 우리 대부분에게는 관련이 없을 것입니다).

IDENTITY 열에 클러스터형 인덱스를 넣으면 모든 삽입이 테이블의 마지막 페이지에서 발생하며 해당 ID는 각 IDENTITY 동안 잠 깁니다. 마지막 페이지를 원하는 5000 명의 사람들이 없다면 큰 문제는 아닙니다. 그런 다음 해당 페이지에 대한 많은 경합이 있습니다

이후 버전에서는 그렇지 않습니다.


3
FIY, SQL Server 6.5에 대해 언급했습니다 : dba.stackexchange.com/questions/1584/…
gbn

15

기본 키가의 키인 경우 키 UNIQUEIDENTIFIER를로 지정하십시오 NONCLUSTERED. 클러스터링을 만들면 모든 삽입물에 새 레코드를 올바른 위치에 삽입하기 위해 많은 레코드를 섞어 야합니다. 성능이 저하됩니다.


1
클러스터 키에 대한 UUID를 피하려고 시도하지만 위의 추론이 불완전 할 수 있다고 생각합니다. SQL Server가 행을 다시 섞어 올바른 위치에 삽입 할 필요는 없습니다 ( "낮은 값과 높은 값 사이"를 의미하는 경우). 1 조 행 테이블의 중간에 삽입을 고려하십시오. 추가 간접 지명이 필요합니다. 순차 UNIQUEIDENTIFIER유형도 존재하며 고유 키를 생성 할 가능성은 동일하지만 여전히 128 크기로 고통받습니다.
Charles Burns

7

매우 일반적인 예 :

  • Customer테이블 CustomerIDCLUSTERED PRIMARY KEY
  • OrderID (PK), CustomerID, OrderDate및 다른 열이있는 주문 테이블
  • OrderPositionsOrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • 주문 테이블을 색인해야합니다

물론 "의존"은 거의 항상 정답이지만, 대부분의 응용 프로그램 (BI- 보고서가 아님)은 고객 기반으로 작동합니다 (예 : 고객 278으로 웹 사이트에 로그인하여 "내 주문"또는 직원은 고객 4569에 대한 모든 주문을 나열하거나 송장 루틴에서 고객에 대한 모든 주문을 요약합니다 (137).

이 경우 테이블을 클러스터링하는 것이별로 의미가 없습니다 OrderID. 예, SELECT ... WHERE OrderId = ?주문 세부 정보를 나열하는 쿼리가 있지만 이는 일반적으로 짧고 저렴한 (3 회 읽기) 인덱스 검색입니다.

반면에을 기준으로 Order테이블을 클러스터링 CustomerID하려면 테이블을 쿼리 할 때마다 여러 키 조회를 수행 할 필요가 없습니다 CustomerId = ?.

CLUSTERED INDEX항상해야한다 UNIQUE, 그렇지 않으면 SQL Server는 눈에 보이지 않는 (= 사용할 수없는) INT 컬럼을 추가, UNIQUIFIER그리고 그 다음 어떤 (삽입 순서에 따라) 임의의 물건을 실제 (사용 가능) 데이터를 추가하는 것이 훨씬 더 나을 - uniquiness을 보장하기 위해.

고객이 둘 이상의 주문을 (희망적으로) 배치 할 것이기 때문에, ( OrderID또는 보통 주문하는 OrderDate경우 ) 날짜 (날짜 시간 인 경우-고객이 하루에 한 주문으로 제한됨)를 추가해야합니다. CLUSTERED INDEX과 함께 결국 :

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

동일한 규칙이 OrderPositions테이블에 적용됩니다 . 일반적으로 대부분의 쿼리는 특정 순서에 대한 모든 위치를 나열하므로 OrderPositionIDas NONCLUSTEREDUNIQUE CLUSTERED INDEXon을 사용하여 PK를 작성해야합니다 OrderId, OrderPositionID.

BTW : Customer테이블이 PK에 의해 클러스터링되는 것이 옳 습니다 ( CustomerID"Top-Level-Table"이기 때문에 일반적인 응용 프로그램에서는 대부분 CustomerID에 의해 쿼리됩니다).

예를 들어 같은 순수 조회 테이블 Genders또는 InvoiceTypes또는 PaymentType(당신이 일반적으로 그들에 가입 것이기 때문에 그 PK에 의해 클러스터해야 테이블의 또 다른 예이다 GenderId, InvoiceTypeId또는 PaymentTypeId).


2

클러스터 된 인덱스가 일부 성능 측정을 사용하여 클러스터 된 PK보다 전체 시스템에 더 유리한 것으로 간주되는 경우 테이블에는 하나의 클러스터형 인덱스 만있을 수 있습니다.

성능 측정의 예는 단일 쿼리 시간 (속도), 테이블에 대한 총 쿼리 시간의 통합 (효율) 및 클러스터 된 (크기)와 비슷한 성능을 달성하기 위해 매우 많은 비 클러스터형 인덱스에 많은 포함 열을 추가해야 함 ).

이는 일반적으로 고유하지 않은 인덱스를 사용하여 데이터를 검색하거나, 널을 포함하거나 (PK에서 허용되지 않음) PK가 2 차 이유 (예 : 복제 또는 감사 추적 레코드 식별)로 추가 된 경우에 발생할 수 있습니다.

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