Infelizmente, parece não haver maneira de criar um filtro negativo para um índice, sem recorrer à criação de uma exibição materializada. Se fosse possível criar um filtro negativo como o desejado, seria muito difícil para o otimizador de consultas "escolher" o índice para uso, aumentando drasticamente o tempo necessário para encontrar um bom plano.
Dependendo dos padrões de consulta para esta tabela, você pode simplesmente criar dois índices; um para menos de 9 e um para maior que 14. Qualquer um desses índices pode ser escolhido pelo otimizador de consulta para WHERE
cláusulas simples comoWHERE 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);
Outra maneira de conseguir isso pode ser:
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);
Isso usa o índice filtrado de 9 a 14 para excluir linhas.
No meu equipamento de teste, um índice de cobertura simples retorna as linhas de longe o mais rápido:
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);
Como alternativa, use uma variação da abordagem usada em sua própria resposta :
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;
Apesar de o filtro ser gravado como conjunção, ele suporta consultas gravadas de qualquer uma das seguintes maneiras (a primeira sendo um pouco mais eficiente):
StatusID NOT IN (9, 10, 11, 12, 13, 14)
StatusID < 9 OR StatusID > 14
StatusID NOT BETWEEN 9 AND 14