К сожалению, похоже, нет способа создать отрицательный фильтр для индекса, не прибегая к созданию материализованного представления. Если бы было возможно создать отрицательный фильтр, такой как тот, который вам нужен, оптимизатору запросов было бы довольно сложно «выбрать» индекс для использования, что резко увеличило бы время, необходимое для поиска хорошего плана.
В зависимости от шаблонов запросов для этой таблицы вы можете просто создать два индекса; один для менее чем 9 и один для более чем 14. Любой из этих индексов может быть выбран оптимизатором запросов для WHERE
таких простых предложений, какWHERE StatusID = 6
CREATE TABLE dbo.TestNegativeFilter
(
TestNegativeFilter INT NOT NULL
CONSTRAINT PK_TestNegativeFilter
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, StatusID INT NOT NULL
);
GO
CREATE INDEX IX_TestNagativeFilter_LessThan9
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID < 9);
CREATE INDEX IX_TestNagativeFilter_GreaterThan14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID > 14);
Еще один способ сделать это может быть:
CREATE INDEX IX_TestNegativeFilter_9_to_14
ON dbo.TestNegativeFilter(StatusID)
WHERE (StatusID IN (9, 10, 11, 12, 13, 14));
SELECT *
FROM dbo.TestNegativeFilter tnf
EXCEPT
SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID IN (9, 10, 11, 12, 13, 14);
Это использует индекс, отфильтрованный от 9 до 14, чтобы исключить строки.
На моем тестовом оборудовании простой индекс покрытия возвращает строки намного быстрее:
CREATE NONCLUSTERED INDEX IX_TestNegativeFilter_StatusID
ON dbo.TestNegativeFilter(StatusID)
INCLUDE (TestNegativeFilter);
SELECT *
FROM dbo.TestNegativeFilter tnf
WHERE tnf.StatusID NOT IN (9, 10, 11, 12, 13, 14);
В качестве альтернативы, используя вариант подхода, использованного в вашем собственном ответе :
CREATE INDEX [IX dbo.TestNegativeFilter StatusID not 9-14]
ON dbo.TestNegativeFilter (StatusID)
WHERE StatusID <> 9
AND StatusID <> 10
AND StatusID <> 11
AND StatusID <> 12
AND StatusID <> 13
AND StatusID <> 14;
Несмотря на то, что фильтр записывается как конъюнкции, он поддерживает запросы, написанные любым из следующих способов (первый из них несколько более эффективен):
StatusID NOT IN (9, 10, 11, 12, 13, 14)
StatusID < 9 OR StatusID > 14
StatusID NOT BETWEEN 9 AND 14