3

考虑以下复合聚集索引:

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

显然, b上的单独索引将使搜索 b 的特定值更快

但是,如果不使用b上的单独索引,在我看来,复合索引仍然可以用于查找具有特定b值的元组,而不是表扫描,方法是遍历a的离散值树并执行a 本地搜索b,跳转到 a 的下一个值等等。

SQL Server 是这样工作的吗?(例如,如果 MSSQL 对具有多列的索引使用单个哈希值,则不会。)

确实如此,并且由于其他原因已经需要复合索引,并且 a 的离散值的数量足够小,性能/空间权衡可能会偏离为b设置单独的索引。

(上面的 UNIQUE 和 CLUSTERED 约束对于这个例子来说并不是真正需要的,但它们代表了 b 的最快检索,涉及b的单独索引——前者为 a 的每个循环提供快捷方式后者删除查找中的一级间接性)。

4

2 回答 2

6

不,没有跳过一簇“a”。只有指定了最左边的列才能使用索引,否则需要使用全扫描。

Oracle 有所谓的“索引跳过扫描”运算符。

于 2009-10-23T21:14:58.550 回答
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
于 2013-07-11T15:15:14.757 回答