Malheureusement, il semble qu'il n'y ait aucun moyen de créer un filtre négatif pour un index, sans recourir à la création d'une vue matérialisée. S'il était possible de créer un filtre négatif tel que celui que vous souhaitez, il serait assez difficile pour l'optimiseur de requêtes de "choisir" l'index à utiliser, augmentant considérablement le temps nécessaire pour trouver un bon plan.
Selon les modèles de requête pour cette table, vous pouvez simplement créer deux index; un pour moins de 9 et un pour plus de 14. L'un ou l'autre de ces index peut être choisi par l'optimiseur de requête pour des WHERE
clauses simples telles queWHERE 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);
Une autre façon d'y parvenir pourrait être:
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);
Cela utilise l'index filtré sur 9 à 14 pour exclure les lignes.
Sur mon banc d'essai, un simple indice de recouvrement renvoie les lignes de loin le plus rapide:
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);
Alternativement, en utilisant une variation de l'approche utilisée dans votre propre réponse :
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;
Bien que le filtre soit écrit sous forme de conjonctions, il prend en charge les requêtes écrites de l'une des manières suivantes (la première étant légèrement plus efficace):
StatusID NOT IN (9, 10, 11, 12, 13, 14)
StatusID < 9 OR StatusID > 14
StatusID NOT BETWEEN 9 AND 14