이것은 일반적으로 해결하기 어려운 문제이지만 옵티마이 저가 계획을 선택하도록 돕기 위해 할 수있는 몇 가지가 있습니다. 이 스크립트는 다음과 같이 설명하기 위해 알려진 의사 난수 분포로 10,000 개의 행이있는 테이블을 만듭니다.
CREATE TABLE dbo.SomeDateTable
(
Id INTEGER IDENTITY(1, 1) PRIMARY KEY NOT NULL,
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL
);
GO
SET STATISTICS XML OFF
SET NOCOUNT ON;
DECLARE
@i INTEGER = 1,
@s FLOAT = RAND(20120104),
@e FLOAT = RAND();
WHILE @i <= 10000
BEGIN
INSERT dbo.SomeDateTable
(
StartDate,
EndDate
)
VALUES
(
DATEADD(DAY, @s * 365, {d '2009-01-01'}),
DATEADD(DAY, @s * 365 + @e * 14, {d '2009-01-01'})
)
SELECT
@s = RAND(),
@e = RAND(),
@i += 1
END
첫 번째 질문은이 테이블을 인덱스하는 방법입니다. 하나의 옵션은 두 개의 인덱스를 제공하는 DATETIME최적화는 적어도에 추구 할 것인지 여부를 선택할 수 있도록, 열 StartDate또는 EndDate.
CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)
당연히, 모두에서 불평등 StartDate과 EndDate각 인덱스에 하나의 열이를 지원할 수있는 평균 예제 쿼리에서 추구하지만, 이것은 우리가 할 수있는 최선에 관한 것입니다. 각 인덱스의 두 번째 열을 INCLUDE키 가 아닌 두 번째 열로 만드는 것을 고려할 수 있지만 선행 열에서 동등 탐색을 수행하고 두 번째 열에서 불평등 탐색을 수행 할 수있는 다른 쿼리가있을 수 있습니다. 또한이 방법으로 더 나은 통계를 얻을 수 있습니다. 어쨌든...
DECLARE
@StartDateBegin DATETIME = {d '2009-08-01'},
@StartDateEnd DATETIME = {d '2009-10-15'},
@EndDateBegin DATETIME = {d '2009-08-05'},
@EndDateEnd DATETIME = {d '2009-10-22'}
SELECT
COUNT_BIG(*)
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
AND sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
이 쿼리는 변수를 사용하므로 일반적으로 옵티마이 저는 선택성 및 분포를 추측하여 카디널리티 추정값이 81 행으로 추정 됩니다. 실제로 쿼리는보다 복잡한 예에서 중요 할 수있는 불일치 인 2076 개의 행을 생성합니다.
SQL Server 2008 SP1 CU5 이상 (또는 R2 RTM CU1) 에서는 위 쿼리에 간단히 추가 하여 매개 변수 포함 최적화 를 활용하여 더 나은 추정치를 얻을 수 있습니다. 이로 인해 일괄 처리가 실행되기 직전에 컴파일이 수행되어 SQL Server에서 실제 매개 변수 값을 '보고'이를 최적화 할 수 있습니다. 이 변경으로 인해 예상이 468 행으로 향상됩니다 (이를 보려면 런타임 계획을 확인해야합니다). 이 추정치는 81 행보다 낫지 만 여전히 그다지 가깝지는 않습니다. 추적 플래그 2301에 의해 활성화 된 모델링 확장 은 경우에 따라 도움이 될 수 있지만이 쿼리에는 도움이되지 않습니다.OPTION (RECOMPILE)SELECT
문제는 두 범위 검색으로 한정된 행이 겹치는 부분입니다. 옵티마이 저의 원가 계산 및 카디널리티 추정 구성 요소에서 수행 된 단순화 가정 중 하나는 술어가 독립적이라는 것입니다 (둘 다 선택성이 50 % 인 경우 둘 다를 적용한 결과는 행의 50 % = 25 %의 50 %를 만족한다고 가정합니다) ). 이러한 종류의 상관 관계가 문제가되는 경우 여러 열 및 / 또는 필터링 된 통계를 사용하여 문제를 해결할 수 있습니다. 시작점과 끝 점이 알려지지 않은 두 개의 범위에서 이것은 비실용적이됩니다. 여기에서 때로는 더 나은 견적을 생성하는 형식으로 쿼리를 다시 작성해야합니다.
SELECT COUNT(*) FROM
(
SELECT
sdt.Id
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
INTERSECT
SELECT
sdt.Id
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
) AS intersected (id)
OPTION (RECOMPILE)
이 양식은 2110 행 (실제 대 2076)의 런타임 예상을 생성합니다. TF 2301을 설정하지 않은 경우, 고급 모델링 기술은 트릭을 통해보고 이전과 정확히 동일한 추정치를 생성합니다 (468 행).
어느 날 SQL Server는 간격을 기본적으로 지원할 수 있습니다. 이것이 우수한 통계 지원과 함께 제공되는 경우 개발자는 이와 같은 튜닝 쿼리 계획을 약간 덜 두려워 할 수 있습니다.