2009-10-23 4 views
3

다음 복합 클러스터 된 인덱스를 고려하십시오.SQL Server는 복합 클러스터 된 인덱스를 사용할 때 점프합니까?

CREATE UNIQUE CLUSTERED INDEX ix_mytable ON mytable(a, b) 

분명히 b에 대한 별도의 색인은 b의 특정 값을 더 빠르게 검색합니다.

하지만 b의 별도 인덱스가이 아닌 인 경우 컴포지트 인덱스는 여전히 테이블 스캔 대신 b에 대한 특정 값을 가진 튜플을 찾는 데 사용할 수 있습니다. a의 불연속 값 트리를 가로 지르고 b에 대한 로컬 검색을 수행하고 등의 다음 값으로 이동합니다.

SQL Server는 어떻게 작동합니까? (예를 들어 MSSQL이 여러 열이있는 인덱스에 대해 단일 해시 값을 사용하는 경우는 아닐 것입니다.)

그것은 복합 인덱스가 다른 이유로 인해 필요하고 가 충분히 작 으면 성능/공간 트레이드 오프가 b에 대한 별도의 색인을 가지고 있지 않을 수 있습니다.

(위의 UNIQUE 및 CLUSTERED 제약 조건은이 예제에서는 실제로 필요하지 않지만 b에 대한 별도의 인덱스를 포함하지 않는 b의 가장 빠른 검색을 나타냅니다. b - 이전의 단축키 제공 a의 각 루프, 후자는 조회에서 간접 지정을 한 단계 제거함).

답변

6

아니요, 'a'의 클러스터에는 점프가 없습니다. 인덱스는 가장 왼쪽 열이 지정된 경우에만 사용될 수 있습니다. 그렇지 않으면 전체 스캔을 사용해야합니다.

오라클에는 'Index Skip Scan' 연산자가 있습니다.

+0

"색인 건너 뛰기 스캔"은 내가 상상했던 방식과 같습니다. MSSQL이 할 수있을 때 MSSQL이 오라클보다 더 OOTB 친화적 인 RDBMS 인 경향이 있기 때문에 약간 실망했습니다. – richardtallent

+1

다음은 해당 Microsoft Connect 항목입니다. https://connect.microsoft.com/SQLServer/feedback/details/695044/implement-index-skip-scan 투표하십시오. – usr

+0

@usr - 연결 항목을 읽고 스택 오버플로 링크를 따라 가십시오. 재귀 CTE를 사용하여 가난한 사람의 버전을 수행 할 수 있습니다. [예제 구문은 여기에 있습니다.] (http://stackoverflow.com/questions/7753319/sql-server-pick-random-or-first-value-with-aggregation/7753492#7753492) –

0
USE AdventureWorks2008R2; 
-- Source: http://msftdbprodsamples.codeplex.com/releases/view/59211 
GO 

SET NOCOUNT ON; 
GO 

CREATE NONCLUSTERED INDEX IX_SalesOrderHeader_OrderDate_#_ShipDate_SubTotal 
ON [Sales].[SalesOrderHeader] ([OrderDate]) 
INCLUDE (ShipDate,SubTotal) 
-- WITH(DROP_EXISTING=ON); 
GO 

-- Test 1 
SET STATISTICS IO ON; 
SELECT COUNT(*) 
FROM Sales.SalesOrderHeader h -- Index Seek on IX_SalesOrderHeader_OrderDate_#_ShipDate_SubTotal 
WHERE h.OrderDate BETWEEN '2008-07-01T00:00:00.000' AND '2008-07-15T23:59:59.997'; 
SET STATISTICS IO OFF; 
GO 
-- End of Test 1 
-- Results: 
-- Table 'SalesOrderHeader'. Scan count 1, logical reads 5, physical reads 0 

DROP INDEX IX_SalesOrderHeader_OrderDate_#_ShipDate_SubTotal 
ON [Sales].[SalesOrderHeader] 
GO 
CREATE NONCLUSTERED INDEX [IX_SalesOrderHeader_ShipMethodID_OrderDate_#_ShipDate_SubTotal] 
ON Sales.SalesOrderHeader 
(
    ShipMethodID ASC, 
    OrderDate ASC 
) 
INCLUDE (ShipDate,SubTotal); 
GO 

-- Test 2 
SET STATISTICS IO ON; 
SELECT COUNT(*) 
FROM Sales.SalesOrderHeader h -- Index Scan on IX_SalesOrderHeader_ShipMethodID_OrderDate_#_ShipDate_SubTotal 
WHERE h.OrderDate BETWEEN '2008-07-01T00:00:00.000' AND '2008-07-15T23:59:59.997'; 
SET STATISTICS IO OFF; 
GO 
-- End of Test 2 
-- Results: 
-- Table 'SalesOrderHeader'. Scan count 1, logical reads 150, physical reads 0 

-- Test 3 
SET STATISTICS IO ON; 
SELECT COUNT(*) 
FROM Purchasing.ShipMethod sm 
INNER JOIN Sales.SalesOrderHeader h ON h.ShipMethodID=sm.ShipMethodID -- FK elimination + Index Scan on IX_SalesOrderHeader_ShipMethodID_OrderDate_#_ShipDate_SubTotal 
WHERE h.OrderDate BETWEEN '2008-07-01T00:00:00.000' AND '2008-07-15T23:59:59.997'; 
SET STATISTICS IO OFF; 
GO 
-- End of Test 3 
-- Results: 
-- Table 'SalesOrderHeader'. Scan count 1, logical reads 150, physical reads 0 

-- Test 4 
SET STATISTICS IO ON; 
SELECT MIN(sm.ShipMethodID) AS DummnyCol, -- To prevent FK elimination 
     COUNT(*) 
FROM Purchasing.ShipMethod sm 
INNER JOIN Sales.SalesOrderHeader h ON h.ShipMethodID=sm.ShipMethodID -- Index Seek on IX_SalesOrderHeader_ShipMethodID_OrderDate_#_ShipDate_SubTotal 
WHERE h.OrderDate BETWEEN '2008-07-01T00:00:00.000' AND '2008-07-15T23:59:59.997'; 
SET STATISTICS IO OFF; 
GO 
-- End of Test 4 
-- Results: 
-- Table 'SalesOrderHeader'. Scan count 5, logical reads 13, physical reads 0 
-- Table 'ShipMethod'. Scan count 1, logical reads 2, physical reads 0 

DROP INDEX [IX_SalesOrderHeader_ShipMethodID_OrderDate_#_ShipDate_SubTotal] 
ON Sales.SalesOrderHeader; 
GO 
SET NOCOUNT OFF; 
GO