비 클러스터형 인덱스 누락 이미 클러스터형 인덱스의 일부


9

느리게 실행되는 쿼리를 디버깅 중이며 실행 계획에서 51.6648 Impact와 함께 비 클러스터형 인덱스가 제안됩니다. 그러나 비 클러스터형 인덱스에는 기본 키 (PK) 복합 클러스터형 인덱스에 이미있는 열만 포함됩니다.

인덱스의 열 순서 때문일 수 있습니까? 즉, 클러스터형 인덱스의 열이 가장 선택적인 순서가 아닌 순서로 정렬되지 않은 경우 클러스터되지 않은 인덱스가 성능을 향상시킬 가능성이 있습니까?

또한 비 클러스터형 인덱스에는 세 개의 PK 열 중 두 개만 포함되며 세 번째는 포함 열로 추가됩니다. 은 include비 클러스터형 인덱스의 사용이 더 최적의 수 또 다른 이유?

아래는 내가 작업하고있는 테이블 구조의 예입니다.

테이블

Retailers (
    RetailerID int PK, 
    name ...)

Retailer_Relation_Types (
    RelationType smallint PK, 
    Description nvarchar(50) ...)

Retailer_Relations (
    RetailerID int PK FK, 
    RelatedRetailerID int PK FK, 
    RelationType smallint PK FK, 
    CreatedOn datetime ...)

Retailer_Relations에는 다음과 같은 복합 PK 지수와 제안 된 지수가 있습니다.

CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX <NameOfIndex> 
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )

답변:


12

Retailer_Relations 테이블에는 다음과 같은 복합 PK 색인과 제안 된 색인이 있습니다.

누락 된 인덱스가 도움이되고 확실히 작동 할 수 있지만 누락 된 인덱스에 너무 많은 시간을 소비하지는 않지만 이러한 힌트는 실제 실행 계획이 아니라 예상 실행 계획에 생성됩니다.

보다 정확하게,이 색인 힌트는 계획에서 운영자가 사용하는 Query Bucks ™ 비용을 절감한다는 전제를 기반으로합니다. 옵티마이 저는 예상 비용을 계산하고 이에 따라 누락 된 인덱스 힌트를 추가합니다.

결과적으로 그들은 매우 틀릴 수 있습니다. 도움이 될지 확실하지 않은 경우 가장 좋은 방법은 전후 상황을 테스트하는 것입니다. SET STATISTICS IO, TIME ON;조회를 실행하기 전에 명령문을 추가하여이를 수행 할 수 있습니다.

또한 statisticsparser 를 사용하여 이러한 통계를보다 쉽게 ​​읽을 수 있습니다.

인덱스의 열 순서 때문일 수 있습니까?

맞습니다. 누락 된 인덱스를 만들면 쿼리의 선택성이 향상 될 수 있습니다 (예 : 쿼리가 다음과 같은 경우).

SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

또는 이와 같이 :

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

그 이유는 두 인덱스 모두 RetailerID를 검색 할 수 있고 그 부분은 변경되지 않기 때문입니다. 그러나 RelationType에 추가 필터 / 순서를 적용하면 어떻게됩니까? 두 번째 키 값이 아닌 세 번째 키 값으로 인해 클러스터형 인덱스의 모든 위치에 적용됩니다. 그리고 우리가 아는 것처럼 NCI의 두 번째 핵심 가치입니다.

좋습니다. 그러나 비 클러스터형 인덱스는 언제 또는 어떻게 쿼리를 개선합니까?

몇 가지 경우가 있습니다.

  • relationType이 많은 값을 필터링하면 잔여 I / O가 높아져 비 클러스터형 인덱스가 필요할 수 있습니다 (질의 # 1).
  • 두 열의 순서는 (편도) 발생하고 결과 집합이 큽니다 (질의 # 2).
  • @AaronBertrand가 언급했듯이 NCI와 비교 한 CI 크기 차이가 상당하면 NCI를 추가하면 혜택을 얻는 쿼리에서 읽는 페이지가 줄어 듭니다.

NCI 사이드 노트

참고로 CI 키 열은 모든 비 클러스터형 인덱스에 자동으로 포함되므로 NCI의 포함 목록에 키 열을 추가 할 필요는 없습니다.

클러스터형 인덱스가 동일하게 유지되는지 확실하지 않고 열이 항상 포함되도록하려는 경우이를 수행 할 수 있습니다.

쿼리 자체와 관련하여 PasteThePlan 을 통해 실행 계획을 추가 한 경우 쿼리 인덱싱 / 개선에 대한 추가 정보를 제공 할 수 있습니다.


테스팅

테이블 만들기 및 일부 행 추가

CREATE TABLE Retailer_Relations (
    RetailerID int , 
    RelatedRetailerID int , 
    RelationType smallint, 
    CreatedOn datetime,
    CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY])


    DECLARE @I Int = 1
    WHILE @I < 1000
    BEGIN
    INSERT INTO Retailer_Relations(RetailerID,RelatedRetailerID,RelationType,CreatedOn)
    VALUES(@I,@I,@I,GETDATE()
    )
    set @I += 1
    END

쿼리 # 1

    SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

인덱스없이 계획 여기에

검색을하는 동안 RetailerID를 검색합니다. 이후에 RelationType에서 잔여 I / O 술어를 발행합니다.

색인 추가

CREATE NONCLUSTERED INDEX IX_TEST
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )

잔차 술어가 사라지고 모든 열이 두 술어에서 탐색 술어에서 발생합니다.

실행 계획

두 번째 쿼리에서는 추가 된 인덱스 유용성이 훨씬 더 명확 해집니다.

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

정렬 연산자를 사용하여 인덱스없이 계획하십시오.

여기에 이미지 설명을 입력하십시오

인덱스를 사용하여 계획을 세웁니다. 인덱스를 사용하면 정렬 연산자가 제거됩니다.

여기에 이미지 설명을 입력하십시오


1
감사합니다 Randi, 나는 이것을 대답으로 표시 할 것입니다.하지만 누락 된 인덱스 제안이 예상 실행 계획을 기반으로한다고 말하고 싶습니까? SS2016의 실제 실행 계획에 표시된대로 요청합니다.
Fletch

1
나는 그것이 당신이 말하고 있는지 궁금해했습니다. 명확 해 주셔서 감사합니다.
Fletch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.