2009-10-23 3 views
3

Рассмотрим следующий композитный кластерный индекс:Удаляет ли SQL Server листья при использовании составного кластерного индекса?

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

Очевидно, что отдельный индекс б сделает поиск определенного значения б быстрее.

Однако, если отдельный индекс б является не используется, как мне кажется, что композитный индекс по-прежнему может быть использован для поиска кортежей с определенным значением для б вместо сканирования таблицы, по обхода дерева дискретных значений и сделать локальный поиск б, переход к следующему значению и т.д.

это как работает SQL Server? (Например, если MSSQL использует одно значение хэша для индексов с несколькими столбцами).

Это он, и составной индекс необходим уже по другим причинам, а число дискретных значений a достаточно мала, компромисс между производительностью и пространством может отвиснуть от наличия отдельного индекса для b.

(The UNIQUE и кластерное ограничение выше, на самом деле не требуются для этого примера, но они представляют собой самую быструю выборку б, которые не затрагивали отдельный индекс для б --the бывшего обеспечивая ярлык каждая петля a, последняя удаляет одну степень косвенности в поиске).

ответ

6

Нет, нет перескоков над кластерами 'a'. Индекс может использоваться только в том случае, если указан крайний левый столбец, в противном случае необходимо использовать полное сканирование.

У Oracle есть так называемый оператор 'Index Skip Scan'.

+0

«Пропустить сканирование индекса» - это именно тот метод, который я предвидел. Немного разочарован тем, что MSSQL не делает этого, когда это возможно, поскольку он, как правило, является более дружественной к OOTB RDBMS, чем Oracle. – richardtallent

+1

Ниже приведен соответствующий элемент Microsoft Connect: https://connect.microsoft.com/SQLServer/feedback/details/695044/implement-index-skip-scan. Проголосуйте за него. – usr

+0

@usr - Просто прочитайте свой элемент Connect и перейдите по ссылке обратно в Stack Overflow. Это можно сделать с использованием рекурсивного 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 

 Смежные вопросы

  • Нет связанных вопросов^_^