답변:
문제는 'PK가 NC 여야하는시기'가 아니라 '클러스터형 인덱스의 올바른 키는 무엇입니까?'입니다.
대답은 실제로 데이터를 쿼리하는 방법에 달려 있습니다 . 클러스터형 인덱스는 다른 모든 인덱스에 비해 이점이 있습니다. 항상 모든 열을 포함하므로 항상 포함합니다. 따라서 클러스터형 인덱스를 활용할 수있는 쿼리는 예상 된 열 및 / 또는 조건자를 만족시키기 위해 조회를 사용할 필요가 없습니다.
퍼즐의 또 다른 조각은 인덱스를 어떻게 사용할 수 있습니까? 세 가지 일반적인 패턴이 있습니다.
따라서 예상로드 (쿼리)를 분석하고 인덱스에서 이익을 얻는 특정 액세스 패턴을 사용하기 때문에 많은 수의 쿼리가 특정 인덱스를 사용한다는 것을 발견하면 해당 인덱스를 클러스터형 인덱스로 제안하는 것이 좋습니다.
또 다른 요인은 클러스터 된 인덱스 키가 모든 비 클러스터형 인덱스에서 사용되는 조회 키 이므로 넓은 클러스터형 인덱스 키는 리플 효과를 만들고 모든 비 클러스터형 인덱스와 넓은 인덱스는 더 많은 페이지, 더 많은 I / O를 의미합니다 더 많은 메모리, 더 적은 선량.
좋은 클러스터형 인덱스는 안정적 입니다. 클러스터 된 인덱스 키 값을 변경하면 행을 삭제하고 다시 삽입해야하기 때문에 엔터티 수명 동안 변경되지 않습니다.
그리고 좋은 클러스터형 인덱스는 페이지 분할 및 조각화를 피하기 위해 무작위로 (순서대로 삽입 된 각 키 값이 이전 값보다 큼) 순서대로 증가 FILLFACTOR
합니다.
이제 좋은 클러스터형 인덱스 키가 무엇인지 알았으므로 기본 키 (데이터 모델링 논리 속성)가 요구 사항과 일치합니까? 그렇다면 PK를 클러스터링해야합니다. 그렇지 않은 경우 PK는 클러스터되지 않아야합니다.
예를 들어, 판매 사실 테이블을 고려하십시오. 각 항목에는 기본 키인 ID가 있습니다. 그러나 대부분의 쿼리는 날짜와 다른 날짜 사이의 데이터를 요구하므로 클러스터 된 최상의 인덱스 키는 ID가 아니라 판매 날짜가 됩니다. 기본 키와 다른 클러스터형 인덱스를 갖는 또 다른 예는 별개의 값이 매우 적은 키인 '카테고리'또는 '상태'와 같이 매우 낮은 선택성 키입니다. 예를 들어 , 가장 낮은 키로이 낮은 선택도 키를 가진 클러스터 된 인덱스 키를 갖는 것은 특정 '상태'의 모든 항목을 찾는 범위 스캔 때문에 종종 의미가 있습니다.(state, id)
힙을 통한 클러스터되지 않은 기본 키 가능성에 대한 마지막 참고 사항입니다 (즉, 클러스터 된 인덱스가 전혀 없음). 이는 유효한 시나리오 일 수 있습니다. 일반적인 이유는 대량 삽입 성능이 중요한 경우입니다. 힙은 클러스터 색인과 비교할 때 대량 삽입 처리량이 훨씬 우수하기 때문입니다.
(state, id)
. 이 예에서는 "좋은 클러스터형 인덱스가 무작위로 생성되지 않습니다"라는 요구 사항이 충족되지 않습니까? 그렇다면 좋은 클러스터형 인덱스로 간주 할 수 있습니까?
클러스터형 인덱스를 사용하는 기본 이유는 Wikipedia에 나와 있습니다 .
클러스터링은 데이터 블록을 인덱스와 일치하는 특정 구별 순서로 변경하여 행 데이터가 순서대로 저장됩니다. 따라서 지정된 데이터베이스 테이블에 하나의 클러스터형 인덱스 만 만들 수 있습니다. 군집 인덱스 는 전체 검색 속도를 크게 향상시킬 수 있지만 일반적으로 군집 색인과 동일하거나 반대 순서로 데이터에 순차적으로 액세스하는 경우 또는 항목 범위를 선택한 경우 에만 가능 합니다 .
내가 People 테이블을 가지고 있고이 사람들은 Country 열과 고유 한 기본 키를 가지고 있다고 가정하십시오. 인구 통계표이므로 이것이 내가 관심을 갖는 유일한 것입니다. 어떤 나라와 얼마나 많은 독특한 사람들이 그 나라에 묶여 있는지
따라서 국가 열에서만 SELECT WHERE 또는 ORDER BY를 선택할 가능성이 높습니다. 기본 키의 클러스터형 인덱스는 나에게 도움이되지 않습니다 .PK 로이 데이터에 액세스하지 않고이 다른 열로 액세스하고 있습니다. 테이블에 하나의 클러스터형 인덱스 만 가질 수 있으므로 PK를 클러스터형으로 선언하면 국가 별 클러스터형 인덱스를 사용할 수 없습니다.
또한 Clustered vs Nonclustered Indexes 에 대한 좋은 기사가 있는데 , 클러스터 된 인덱스가 SQL Server 6.5에서 삽입 성능 문제를 일으킨다는 사실이 밝혀졌습니다 (적어도 우리 대부분에게는 관련이 없을 것입니다).
IDENTITY 열에 클러스터형 인덱스를 넣으면 모든 삽입이 테이블의 마지막 페이지에서 발생하며 해당 ID는 각 IDENTITY 동안 잠 깁니다. 마지막 페이지를 원하는 5000 명의 사람들이 없다면 큰 문제는 아닙니다. 그런 다음 해당 페이지에 대한 많은 경합이 있습니다
이후 버전에서는 그렇지 않습니다.
기본 키가의 키인 경우 키 UNIQUEIDENTIFIER
를로 지정하십시오 NONCLUSTERED
. 클러스터링을 만들면 모든 삽입물에 새 레코드를 올바른 위치에 삽입하기 위해 많은 레코드를 섞어 야합니다. 성능이 저하됩니다.
UNIQUEIDENTIFIER
유형도 존재하며 고유 키를 생성 할 가능성은 동일하지만 여전히 128 크기로 고통받습니다.
매우 일반적인 예 :
Customer
테이블 CustomerID
로CLUSTERED PRIMARY KEY
OrderID (PK), CustomerID, OrderDate
및 다른 열이있는 주문 테이블OrderPositions
와 OrderPositionID (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
테이블에 적용됩니다 . 일반적으로 대부분의 쿼리는 특정 순서에 대한 모든 위치를 나열하므로 OrderPositionID
as NONCLUSTERED
및 UNIQUE CLUSTERED INDEX
on을 사용하여 PK를 작성해야합니다 OrderId, OrderPositionID
.
BTW : Customer
테이블이 PK에 의해 클러스터링되는 것이 옳 습니다 ( CustomerID
"Top-Level-Table"이기 때문에 일반적인 응용 프로그램에서는 대부분 CustomerID에 의해 쿼리됩니다).
예를 들어 같은 순수 조회 테이블 Genders
또는 InvoiceTypes
또는 PaymentType
(당신이 일반적으로 그들에 가입 것이기 때문에 그 PK에 의해 클러스터해야 테이블의 또 다른 예이다 GenderId
, InvoiceTypeId
또는 PaymentTypeId
).
클러스터 된 인덱스가 일부 성능 측정을 사용하여 클러스터 된 PK보다 전체 시스템에 더 유리한 것으로 간주되는 경우 테이블에는 하나의 클러스터형 인덱스 만있을 수 있습니다.
성능 측정의 예는 단일 쿼리 시간 (속도), 테이블에 대한 총 쿼리 시간의 통합 (효율) 및 클러스터 된 (크기)와 비슷한 성능을 달성하기 위해 매우 많은 비 클러스터형 인덱스에 많은 포함 열을 추가해야 함 ).
이는 일반적으로 고유하지 않은 인덱스를 사용하여 데이터를 검색하거나, 널을 포함하거나 (PK에서 허용되지 않음) PK가 2 차 이유 (예 : 복제 또는 감사 추적 레코드 식별)로 추가 된 경우에 발생할 수 있습니다.