需要帮助Filtered Index

时间:2010-11-05 19:17:50

标签: database sql-server-2008

我正在创建一个Notification表,其中包含以下规范:

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
    )
)

每次更改通知,而不是更新其值时,我想创建一个新的“活动”通知并停用前一个通知。但是,当NotificationId指定时,仍需要访问先前的通知。所以我希望最终会有非活跃的通知而不是活动通知。

添加或更改通知的情况相对较少。更常见的是:

  1. 对基于NotificationId和
  2. 与此表连接的外部表的查询
  3. 使用给定的TriggerKey和ObjectId
  4. 查询“活动”通知

    对于第一种情况,我认为主键索引就足够了。 对于第二种情况,我正在考虑创建以下过滤索引:

    CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject 
    ON [Notification] (IsActive, TriggerKey, ObjectId)
    WHERE IsActive = 1
    

    但是,当我在创建此索引之前和之后检查执行计划时,它似乎没有被使用。为什么? alt text

    更新

    由于在接受的答案中链接了the article,这里是索引的更正版本:

    CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject 
    ON [Notification] (TriggerKey, ObjectId)
    INCLUDE (IsActive, NotificationId, RecipientType)
    WHERE IsActive = 1
    

2 个答案:

答案 0 :(得分:2)

SELECT *表示通常不会使用索引。

您的索引只满足WHERE子句,而不满足SELECT子句,因此SQL Server决定索引对此查询没有用处。换句话说,它不是covering

这很可能会使用索引

SELECT IsActive, TriggerKey, ObjectId
FROM [Notification]
WHERE IsActive = 1 AND ObjectId = 2 AND TriggerKey = 'test'

如果您将索引更改为此,则它将涵盖所有列。 SELECT *现在可以使用它

CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject 
ON [Notification] (IsActive, TriggerKey, ObjectId)
INCLUDE (RecipientType, NotificationId)
WHERE IsActive = 1

答案 1 :(得分:1)

如果你有很多(大多数?)'活动'记录,那么查询估计器可​​能不会使用该索引 - 因为查询需要返回所有字段,无论如何都需要访问和扫描聚簇密钥(表本身)。尝试仅选择索引中包含的字段 - 是否有任何更改?

如果您的“活动”记录很少(可能低于10-30%左右,取决于行数和许多其他因素),那么使用索引查找RID并在聚簇索引上搜索它们会更有效(表)。

我将尝试另一件事 - 仅在字段(TriggerKey,ObjectId)上声明过滤索引(如果过滤索引可以这种方式创建)。将IsActive置于索引的开始会导致选择性恕我直言。

请注意,上述所有内容仅供参考 - 我没有使用过滤索引的经验。