Sfortunatamente, non sembra esserci alcun modo per creare un filtro negativo per un indice, senza ricorrere alla creazione di una vista materializzata. Se fosse possibile creare un filtro negativo come quello che desideri, sarebbe molto difficile per la query-ottimizzatore di "raccogliere" l'indice per l'utilizzo, aumentando drasticamente il tempo necessario per trovare un buon piano.
A seconda dei modelli di query per questa tabella, è possibile semplicemente creare due indici; uno per meno di 9 e uno per maggiore di 14. Ognuno di questi indici può essere scelto da Query Optimizer per WHERE
clausole semplici comeWHERE 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);
Un altro modo per ottenere questo risultato potrebbe essere:
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);
Questo utilizza l'indice filtrato da 9 a 14 per escludere le righe.
Sul mio banco di prova, un semplice indice di copertura restituisce le righe di gran lunga il più veloce:
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);
In alternativa, usando una variazione dell'approccio usato nella tua risposta :
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;
Nonostante il filtro sia scritto come congiunzioni, supporta le query scritte in uno dei seguenti modi (il primo è leggermente più efficiente):
StatusID NOT IN (9, 10, 11, 12, 13, 14)
StatusID < 9 OR StatusID > 14
StatusID NOT BETWEEN 9 AND 14