2016-06-05 6 views
2

나는 이것에 나의 머리를 긁고있다.SQL Server 쿼리 최적화 프로그램이 때때로 클러스터 된 기본 키를 간과하는 경우가 있습니까?

나는 완전히 그것을 .... 날짜 필드에 인덱스에 찬성, 쿼리 실행 계획의 기본 키가 무시 클러스터 id있는 테이블 정수 기본 키과 SQL 최적화에 select count(id) 간단하게 실행? ??

실제 테이블 :

CREATE TABLE [dbo].[msgr](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [dt] [datetime2](3) NOT NULL CONSTRAINT [DF_msgr_dt] DEFAULT (sysdatetime()), 
    [uid] [int] NOT NULL, 
    [msg] [varchar](7000) NOT NULL CONSTRAINT [DF_msgr_msg] DEFAULT (''), 
    [type] [tinyint] NOT NULL, 
    [cid] [int] NOT NULL CONSTRAINT [DF_msgr_cid] DEFAULT ((0)), 
    [via] [tinyint] NOT NULL, 
    [msg_id] [bigint] NOT NULL, 
CONSTRAINT [PK_msgr] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

무슨 일이 그 이유가 될 수하세요?

+0

SQL Server는 성능면에서 보조 인덱스가 더 유용하다고 생각합니다. 아마도 클러스터 된 인덱스는 리프 수준에서 데이터 페이지를 읽어야하기 때문일 수 있습니다. –

+0

@GordonLinoff 그래서 걱정할 이유가 없나요? –

+2

클러스터되지 않은 인덱스 (필터링 된 레코드는 제외)의 레코드 수는 클러스터 된 인덱스의 레코드 수와 같습니다. 그런 다음 할당 된 페이지 수에 따라 * 가장 작은 * 색인을 사용하여 계산할 수 있으며 더 적은 IO를 소비하면서 정답을 얻을 수 있습니다. 이는 1) WHERE 절이없고 2) id가 클러스터 된 인덱스 키 (아마도 기본 키)이기 때문입니다. 'count (*)'도 동일한 최적화를 활용할 수 있습니다. –

답변

3

1), 여기에 핵심이 클러스터 테이블 (= 주요 데이터 구조 클러스터 된 인덱스가있는 테이블에 = 테이블 데이터를 저장하는 데이터 구조가 있다는 것입니다 = 클러스터 된 인덱스는 테이블입니다 자체) 클러스터되지 않은 모든 인덱스는 클러스터 된 인덱스의 키도 포함합니다. 이

CREATE [UNIQUE] NONCLUSTERED INDEX bla 
ON [dbo].[msgr] (uid) 

는 기본적으로

CREATE [UNIQUE] NONCLUSTERED INDEX bla 
ON [dbo].[msgr] (uid) 
INCLUDE (id) -- id = key of clustered index 

같은 일이 그래서, 같은 테이블, 리프 페이지에 비 클러스터형 인덱스에서 모든 레코드는 클러스터 된 인덱스의 키가 포함되어 있다는 것을 의미한다. 이렇게하면 모든 클러스터되지 않은 인덱스와 모든 리프 레코드 SQL Server 저장소에 주 데이터 구조에 대한 포인터가 생깁니다.

2) 이는 두 인덱스가 모두 id (키순 인덱스 키) 열을 포함하기 때문에 CI를 사용하면서 NCI를 사용하여 실행할 수 있음을 의미합니다. (id 열에 대한) IDENTITY 속성이 필수 열 (NOT NULL)을 의미하기 때문에이 주제에 대한 2 참고로

COUNT(id)COUNT(*)과 같은 것입니다. 또한 COUNT(msg_id) (필수 항목/ NOT NULL) 열은 COUNT(*)과 같습니다. 따라서 SELECT COUNT(msg_id) FROM dbo.msgr의 실행 계획은 동일한 NCI를 사용합니다 (예 : bla).

3) 비 클러스터형 인덱스는 클러스터형 인덱스보다 크기가 작습니다. 이는 또한 IO가 적다는 것을 의미합니다.> 성능 측면에서 볼 때 CI보다 NCI를 사용하는 것이 좋습니다.

나는 간단한 테스트 다음과 같습니다

SET STATISTICS IO ON; 
GO 

SELECT COUNT(id) 
FROM dbo.[dbo].[msgr] WITH(INDEX=[bla]) -- It forces usage of NCI 
GO 

SELECT COUNT(id) 
FROM dbo.[dbo].[msgr] WITH(INDEX=[PK_msgr]) -- It forces usage of CI 
GO 

SET STATISTICS IO OFF; 
GO 

을 다음 STATISTICS IO 다른 LIO (논리 IO)를 보여줍니다 msgr 테이블에서 많은 양의 데이터가있는 경우, 적은 LIO와 NCI 쿼리을 위해.

+0

이제 '통계 입출력'출력을 확인해 보겠습니다. 흥미로운 점을 제기 했으므로 데이터의 양이 늘어남에 따라 select 쿼리를 변경해야합니다.나는이 점을 결코 생각하지 못했습니다. –

+0

아니요. 요점은 행 수가 적 으면 {no diff | LIO 측면에서 CI와 NCI 실행 계획 사이의 차이점을 설명합니다. –

1

SQL Server는 인덱스의 인덱스를 통해 계산됩니다. 데이터에 갈 필요가 없습니다. SQL Server는 모든 포인터를 계산하여 그 개수를 얻기 위해 인덱스를 선택했습니다.

2

SQL Server에는 매우 좋은 최적화 도구가 있습니다. 클러스터되지 않은 인덱스를 선택하는 경우이 방법이 가장 좋습니다. 이것은 나의 설명이다.

색인은 보조 트리와 같은 데이터 구조의 키 및 구분 값 목록을 저장합니다. 비 클러스터형 인덱스의 경우 인덱스의 잎은 레코드 식별자 (레코드에 대한 포인터)입니다.

클러스터 된 인덱스에는 leaves가 없습니다. 데이터 페이지 자체는 나뭇잎입니다. 따라서 클러스터 된 인덱스를 사용하여 레코드 수를 계산하려면 모든 데이터 페이지를 읽어야합니다. 솔직하게 말해서 데이터 페이지를 읽는 것을 피하는 방법이 있다고 생각할 수도 있지만 데이터 페이지를 읽는 것이 필요할 수도 있습니다.

어쨌든 클러스터되지 않은 인덱스는 계산에 필요한 모든 정보가 인덱스에 있기 때문에 원본 데이터 페이지를 읽을 필요가 없습니다.

+0

이 설명을 주셔서 감사합니다.하지만이 부분을 따르지는 않습니다. "계산에 필요한 모든 정보가 비 클러스터형 인덱스에 있습니다." 어떻게 그렇게? –

+0

@CharlesOkwuagwu. . . 인덱스에는 유효한 레코드에 대한 포인터가 포함되어 있기 때문입니다. 카운트를하기 위해 실제 데이터 내부를 피크 할 필요가 없습니다. –

+0

클러스터되지 않은 인덱스의 경우 인덱스의 나머지 부분은 레코드 식별자 (레코드에 대한 포인터)입니다. 알았다! 감사! –

1

id를 클러스터 된 정수 기본 키로 사용하는 테이블에서 간단한 select count (id)로 실행되며 SQL Optimizer는 쿼리 실행 계획의 기본 키를 완전히 무시하고 날짜 필드의 인덱스를 사용합니다. ... ???

SQL 서버가이 계획을 선택 할 때마다 비용을 기반으로 optmizer,, 그것은 적당한 양으로 계획을 2.Choosing 계정

쿼리의

1.Total 비용
에 두 가지 일을합니다 시간.

것은 SQL 서버 쿼리 최적화 프로그램은

지금 계정으로 무엇보다도 고려 .. cache.So에는 항상 디스크에서 읽을 관련이있다가 가정 얼마나 많은 페이지입니다 인식하지 못합니다. .

ID가 기본 키이고이 늘 널 수 (COUNT (ID) null 값을 제외)을 더한이 큰 인덱스를 모두 스캔하는 데 필요한 스캔하기 때문에 SQL은 좁은 가능한 인덱스를 스캔 할 생각했을 수도

, 대신 널이 아닌 다른 색인을 스캔 할 수도 있습니다.제 생각에는