2011-05-12 2 views
3

표 정의 :이 쿼리가 적절한 인덱스를 사용하지 않는 이유는 무엇입니까?

CREATE TABLE [dbo].[AllErrors](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [DomainLogin] [nvarchar](50) NULL, 
    [ExceptionDate] [datetime] NULL, 
    [ExceptionDescr] [nvarchar](max) NULL, 
    [MarketName] [nvarchar](50) NULL, 
    [Version] [nvarchar](50) NULL, 
    CONSTRAINT [PK_AllErrors] PRIMARY KEY CLUSTERED ([ID] ASC) 
) 

-- Add an index on the date 
CREATE NONCLUSTERED INDEX [IX_ExceptionDate] ON [dbo].[AllErrors] ([ExceptionDate] ASC) 

내가이 쿼리 실행

declare @yesterday datetime 
select @yesterday = getdate() - 1 

SELECT * INTO #yst 
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1 

enter image description here

가이 코드는 사용하지 않는 내 IX_ExceptionDate (실행 계획에서 수집 참조). 기본 키 색인에서 클러스터 된 검사를 수행합니다.

SELECT * INTO #yst 
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1 
    AND ExceptionDate = ExceptionDate 

enter image description here

이 왜 그러나, 아래의 코드는 IX_ExceptionDate 인덱스를 사용합니까?

EDIT : Visual Execution Plan이 추가되었습니다.

EDIT : 아래 텍스트 실행 계획.

쿼리 1 :

| --table 삽입 (OBJECT :.. ([#의 YST), SET ([#의 YST [ID] = [Expr1006] [#의 YST] DomainLogin = [MarketStats]. [dbo]. [AllErrors]. [DomainLogin], [# yst]. [ExceptionDate] = [MarketStats]. [dbo]. [AllErrors]. [ExceptionDate], [# yst]. [ ExceptionDescr] [MarketStats]. [AllErrors]. [ExceptionDescr], [# yst]. [MarketName] = [MarketStats]. [dbo]. [AllErrors]. [MarketName], [# yst]. [ [버전] = [MarketStats]. [dbo]. [AllErrors]. [버전])) -- Top (ROWCOUNT est 0) | - Compute 스칼라 (DEFINE : ([Expr1006] = setidentity ([MarketStats]). (클러스터 된 인덱스 스캔 (OBJECT : ([MarketStats]). [AllErrors]. [AllErrors]. [PK_AllErrors]) : ([MarketStats]. [dbo]. [AllErrors]. [ExceptionDate]> = [@ 어제] 그리고 [MarketStats]. [dbo]. [AllErrors]. ([# : | :))

쿼리 2 --table 삽입 (OBJECT

[ExceptionDate] <는 = [@ 어제] + ': 00 : 00.000 1900년 1월 2일 00' yst]. [# yst]. [ID] = [Expr1006], [# yst]. [DomainLogin] = [MarketStats]. [dbo]. [AllErrors]. [DomainLogin], [# yst]. [ExceptionDate] = [MarketStats]. [dbo]. [AllErrors]. [ExceptionDate], [# yst]. [ExceptionDescr] = [MarketStats]. [dbo]. [AllErrors]. [ExceptionDescr], [# yst]. [MarketName] = [MarketStats]. [dbo]. [AllErrors]. [MarketName], [# yst]. [Version] = [MarketStats]. [dbo]. [AllErrors]. [Version ]]) | - Top (ROWCOUNT est 0) | - Compute Scalar (DEFINE : ([Expr1006] = setidentity ([MarketStats]. [dbo]. [AllErrors]. [- (Inner Join, Outer References : ([MarketStats]. [dbo]. [AllErrors]. [ID], [Expr1008]) 선입 선출 된 루프와 함께 최적화 됨 ([MarketStats]. [dbo]. [AllErrors]. [IX_ExceptionDate]) SEEK : ([MarketStats]. [dbo]. [AllErrors]. [ExceptionDate]> = [@ 어제] [MarketStats]. [dbo]. [AllErrors]. [ExceptionDate] < = [@ 어제] + '1900-01-02 00 : 00 : 00.000'), 어디서 : ([MarketStats]. [dbo]. [AllErrors]. [ExceptionDate] = [MarketStats]. [dbo]. [AllErrors]. [ExceptionDate]) ORDERED FORWARD) | - 클러스터 된 인덱스 찾기 (OBJECT : ([MarketStats]. [dbo]. [AllErrors]). [PK_AllErrors]) SEEK : ([MarketStats]. [dbo]. [AllErrors]. [ID] = [MarketStats]. [AllErrors].[ID]) LOOKUP ORDERED FORWARD)

+0

실행 계획을 게시 할 수 있습니까? – Lamak

+0

당신은 계획을 게시 할 수 있습니까? 나는 클러스터 된 인덱스 스캔 (OBJECT : ([aspnetdb]. [dbo]. [AllErrors]. [PK_AllErrors]), WHERE : ([aspnetdb]. [ dbo]. [AllErrors]. [ExceptionDate] = [@ yesterday] AND [aspnetdb]. [dbo]. [AllErrors]. [ExceptionDate] <= [@ 어제] + '1900-01-02 00 : 00 : 00.000 '[)])' – SQLMenace

+0

'| - 클러스터 된 인덱스 스캔 (OBJECT : ([aspnetdb]. [dbo]. [AllErrors]. [PK_AllErrors]), ([aspnetdb]. [dbo]. [AllErrors]. [ExceptionDate ] [= 어제] AND [aspnetdb]. [dbo]. [AllErrors]. [ExceptionDate] <= [@ 어제] + '1900-01-02 00 : 00 : 00.000'AND [aspnetdb]. [dbo] . [AllErrors]. [ExceptionDate] = [aspnetdb]. [dbo]. [AllErrors]. [ExceptionDate])) ' – SQLMenace

답변

6

그것은 모르는 인한 참조 어떤 변수의 값이 될 것입니다 쿼리. 시도해보십시오 OPTION (RECOMPILE).

쿼리에 AND 절을 추가하면 (논리적으로는 더 이상 선택 적이 지 않음), 옵티마이 저가 더 큰 선택성을 가진 쿼리를 추정하여 오히려 원하는 계획을 세운 것으로 추정해야합니다.

당신은 비교 연산자의 종류에 따라 달라 추론에 다시 떨어지는 ExceptionDate = ExceptionDate없는 버전이 88234.8 행으로 추정하고 8823.48

와 버전 일반적으로 사용 가능한 통계 SQL 서버의 부재에 있다는 의견에 말 술어

예를 들어 > 술어가 30 %의 행을 리턴하고 = 술어가 10 %의 행을 리턴한다고 가정하므로 첫 x 째 추정 결과에 직접 적용하는 것처럼 보입니다. 흥미 롭다는 사실은 equals가 여기에있는 컬럼 자체를 상대로한다는 사실을 고려하지 않았습니다!

c.f. Best Practices for Managing Statistics - Avoid use of local variables in queries

5

간단한 대답 : "SELECT *"로 인해 쿼리가 클러스터형 인덱스에 도달했습니다. 키 조회 작업은 클러스터형 인덱스 스캔보다 훨씬 비용이 많이 듭니다. 이 컴파일 할 때

는 다른 쿼리 계획이

declare @yesterday datetime 
select @yesterday = getdate() - 1 

SELECT * INTO dbo.#yst 
from AllErrors WITH (INDEX = IX_ExceptionDate) 
where ExceptionDate between @yesterday and @yesterday + 1 

declare @yesterday datetime 
select @yesterday = getdate() - 1 

SELECT * INTO dbo.#yst 
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1 

declare @yesterday datetime 
select @yesterday = getdate() - 1 

SELECT ExceptionDate INTO dbo.#yst 
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1 
+0

테이블에서 모든 데이터가 필요한 경우. 일단 적절한 양의 행을 얻으면 모든 비용은 삽입에 있어야합니다. – SRoderick

+0

좋은 생각인데도 결과는 같았습니다. (사실 ExceptionDate뿐 아니라 테이블의 모든 열이 필요합니다). – AngryHacker

+1

*을 사용하는 것이 좋습니다. IMHO. 명시 적으로 필드를 열거하는 것이 더 좋습니다. –

관련 문제