I’m creating a Notification table, with the following specification:
CREATE TABLE [Notification] (
[NotificationId] [int] NOT NULL IDENTITY (1, 1),
[IsActive] [bit] NOT NULL,
[TriggerKey] [nvarchar](50) NOT NULL,
[ObjectId] [int] NOT NULL,
[RecipientType] [tinyint] NOT NULL,
CONSTRAINT PK_Notification PRIMARY KEY CLUSTERED
(
[NotificationId] ASC
)
)
Every time a notification gets changed, rather than updating its values, I want to create a new, "Active" notification and deactivate the previous one. But the previous notification needs to still be accessible when specified by NotificationId. So I expect to eventually have far more inactive notifications than active ones.
It will be relatively uncommon for Notifications to be added or changed. Far more common will be:
- A query on an external table that joins with this table based on the NotificationId, and
- A query for "Active" notifications with a given TriggerKey and ObjectId
For the first case, I figure the primary key index will suffice.
For the second case, I am thinking of creating the following filtered index:
CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject
ON [Notification] (IsActive, TriggerKey, ObjectId)
WHERE IsActive = 1
However, when I check the execution plan before and after creating this index, it appears to not be getting used. Why?

Update
Thanks to the article linked in the accepted answer, here’s the corrected version of the index:
CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject
ON [Notification] (TriggerKey, ObjectId)
INCLUDE (IsActive, NotificationId, RecipientType)
WHERE IsActive = 1
SELECT *means the index won’t usually be used.Your index satisfies only the WHERE clause, not the SELECT clause, so SQL Server decides the index is no use for this query. In other words, it isn’t covering
This will most likely use the index
If you changed the index to this, then it covers all columns. SELECT * may use it now