2010-11-05 2 views
1

Я создаю 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 
    ) 
) 

Каждый раз, когда уведомление получает изменилось, а не обновлять свои ценности, я хочу, чтобы создать новую, «Активный msgstr "уведомление и деактивация предыдущего. Но предыдущее уведомление должно быть доступно, если оно указано в NotificationId. Поэтому я ожидаю, что в конечном итоге будет гораздо больше неактивных уведомлений, чем активных.

Это будет относительно редкость для добавления или изменения уведомлений. Гораздо более распространенным будет:

  1. Запрос на внешней таблицы, которая соединяет с этой таблицей на основе NotificationId и
  2. Запрос на «Active» уведомлений с заданной TriggerKey и ObjectId

В первом случае я считаю, что индекс первичного ключа будет достаточным. Во втором случае, я имею в виду создание следующий отфильтрованный индекс:

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

Однако, когда я проверяю план выполнения до и после создания этого индекса, это, кажется, не привыкать. Зачем? alt text

Update

Благодаря the article связанным в общепринятом ответе, вот исправленная версия индекса: (? Большинства)

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

ответ

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 
+0

В этой статье мне все ясно. Спасибо! – StriplingWarrior

1

Если у вас есть много из 'активных' записей, то Вероятно, система оценки запросов не использует этот индекс, поскольку запрос должен возвращать все поля, доступ и сканирование кластеризованного ключа (самой таблицы). Попробуйте выбрать только поля, содержащиеся в индексе, - что-нибудь изменилось?

Если у вас мало активных записей (может быть, ниже 10-30% или около того, зависит от количества строк и многих других факторов), тогда было бы более эффективно использовать индекс для поиска RID и поиска их по кластерному индексу (Таблица).

Еще одна вещь, с которой я бы экспериментировал - объявить только отфильтрованный индекс только для полей (TriggerKey, ObjectId) (если этот фильтр можно создать таким образом). Помещение IsActive на начало индекса убивает избирательность ИМХО.

Обратите внимание, что все выше только предположения - у меня нет опыта с отфильтрованными индексами.

+0

Вы говорите, что SQL Server, вероятно, определяет его план выполнения на основе того, что он знает о текущих данных в таблице? – StriplingWarrior

+0

Да, конечно. Он вычисляет статистику распределения данных «на лету» (или нет - это настраивается, по умолчанию автоматически обновляет статистику) и широко использует эти данные. – Arvo