2009-10-23 36 views
3

考慮下面的複合物聚集索引:當使用複合聚集索引時,SQL Server會跳轉嗎?

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

顯然,在b一個單獨的索引將搜索的b快一個特定的值。

然而,如果上b一個單獨的索引是使用,似乎對我來說,綜合指數仍然可以用來找到元組與b代替表掃描的特定值,由遍歷一個離散值的樹,做b本地搜索,跳轉到一個下一個值,等

這是SQL Server如何工作的? (例如,如果MSSQL對多列索引使用單個散列值,則不會這樣。)

它是,並且由於其他原因已經需要組合索引,並且離散值的數量爲一個是足夠小,性能/空間的權衡可能擺脫對b具有單獨的索引。

(唯一的和集羣的約束上面是不是真的需要這個例子,但他們代表的b最快的檢索不涉及對b --the前者提供了一個快捷方式的單獨的索引每個循環的a,後者在查找中刪除一個間接程度)。

回答

6

不,沒有跳過'a'的集羣。只有在指定最左邊的列時才能使用索引,否則需要使用完整掃描。

Oracle擁有所謂的'Index Skip Scan'運算符。

+0

「索引跳過掃描」正是我所設想的那種方法。有點失望,MSSQL不能做到這一點,因爲它往往是一個比ORB更友好的RDBMS。 – richardtallent 2009-10-24 12:14:09

+1

以下是相應的Microsoft Connect項目:https://connect.microsoft.com/SQLServer/feedback/details/695044/implement-index-skip-scan請爲此投票。 – usr 2011-10-15 14:29:20

+0

@usr - 只要閱讀你的連接項,然後把你的鏈接回到堆棧溢出。使用遞歸CTE可以做一個窮人的版本。 [示例語法在這裏](http://stackoverflow.com/questions/7753319/sql-server-pick-random-or-first-value-with-aggregation/7753492#7753492) – 2011-10-15 20:42:52

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