我正在创建一个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指定时,仍需要访问先前的通知。所以我希望最终会有非活跃的通知而不是活动通知。
添加或更改通知的情况相对较少。更常见的是:
对于第一种情况,我认为主键索引就足够了。 对于第二种情况,我正在考虑创建以下过滤索引:
CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject
ON [Notification] (IsActive, TriggerKey, ObjectId)
WHERE IsActive = 1
但是,当我在创建此索引之前和之后检查执行计划时,它似乎没有被使用。为什么?
由于在接受的答案中链接了the article,这里是索引的更正版本:
CREATE NONCLUSTERED INDEX IDX_Notification_ActiveTriggerObject
ON [Notification] (TriggerKey, ObjectId)
INCLUDE (IsActive, NotificationId, RecipientType)
WHERE IsActive = 1
答案 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置于索引的开始会导致选择性恕我直言。
请注意,上述所有内容仅供参考 - 我没有使用过滤索引的经验。