Некластерный индекс SQL Server никогда не отображается в плане выполнения - PullRequest
2 голосов
/ 09 февраля 2011

У меня есть таблица базы данных с именем tbl_event с некластеризованными индексами IDX_Event_Folder и IDX_Event_Time, определенными как:

CREATE NONCLUSTERED INDEX [IDX_Event_Folder] 
ON [dbo].[tbl_event]([nobjectid] ASC)

CREATE NONCLUSTERED INDEX [IDX_Event_Time] 
ON [dbo].[tbl_event]([tetime] ASC)

Я выполнил следующие простые запросы и сразу отобразил планы выполнения:

Запрос 1:

SELECT * 
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000
ORDER BY tetime

Execution Plan for Query 1

Запрос 2:

SELECT * 
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000

Execution Plan for Query 2

Мой вопрос: почему индекс nobjectid никогда не используется? Я ожидаю, что будет поиск или сканирование индекса, когда в предложении where этих операторов select указано nobjectid. Мое понимание этого анализа неверно?

Ответы [ 3 ]

3 голосов
/ 09 февраля 2011

почему индекс nobjectid никогда не указывается используется? Я ожидал бы там быть индекс поиска или сканирования, когда nobjectid указано в предложении where

Распространенное заблуждение!

Одно замечание: поскольку вы используете SELECT *, вам нужны все данные из таблицы. Таким образом, в конце концов, SQL Server должен вернуться к фактическим страницам данных и извлечь все значения.

Когда поиск по индексу происходит и обнаруживает попадание, в этом случае SQL Server должен выполнить поиск по закладке - довольно дорогая операция.

И поскольку эти операции довольно дороги, SQL Server будет стараться их избегать, если сможет - поэтому во многих случаях вместо этого будет использоваться сканирование таблицы, поскольку в конечном итоге это быстрее, чем поиск индекса nc, а затем выполнение поиск по закладкам.

Очков для проверки:

  • насколько избирательно является столбцом nobjectid? Этот здесь звучит как более или менее уникальный идентификатор - это было бы хорошо. Если у вас есть индекс для столбца, который будет не очень избирательным, то часто оптимизатор запросов будет его игнорировать (поскольку ему придется уже проверять слишком много строк, поэтому в конце сканирование таблицы будет быстрее)

  • сколько строк есть в таблице ?? Для небольших таблиц (менее нескольких тысяч строк) часто гораздо быстрее выполнить сканирование таблицы с самого начала

Кроме того, из вашего первого плана выполнения с «поиском кучи RID» я бы пришел к выводу, что у вас нет кластеризованного индекса в таблице - добавьте один сразу !! Отсутствие кластеризованного ключа (таким образом, имея heap вместо кластеризованной таблицы) также замедляет множество операций и снижает эффективность некластеризованного индекса.

Попробуйте добавить кластерный индекс в столбец «NUSE»:

  • узкая
  • уникальный
  • стабильный
  • постоянно увеличивается

INT IDENTITY является идеальным кандидатом - UNIQUEIDENTIFIER или очень широкий составной набор столбцов являются худшими. Читайте все о выборе правильного кластерного индекса в блоге Кимберли Триппа

2 голосов
/ 09 февраля 2011

Вы говорите в комментариях, что в таблице в настоящее время есть 18325170 строк, только около 30 из них имеют nobjectid = 1410000.

Даже если ваш IDX_Event_Folder индекс был отключен, я не могу поверить, что SQL Server выбрал бы этот план для такого количества строк, а толщина линии указывает, что он думает, что может иметь дело с 1 строкой, а не 18325170!

Plan

Так что я почти уверен, что у вас отключена статистика автоматического обновления? Если это так, вам нужно будет обновить статистику вручную (или предпочтительно включить эту опцию)

1 голос
/ 09 февраля 2011

Есть несколько пересекающихся вещей, происходящих

  • Ваш SELECT * означает «дай мне все столбцы». Оптимизатор решает, что вместо этого лучше сканировать таблицу.
  • Единственный полезный индекс - это временный индекс для заказа. Он делает это, затем сверлит в стол.
  • У вас нет кластеризованного индекса (поиск RID / кучи показывает это)
  • Отсутствие уникальности индекса nobjectid не поможет: это означает полное сканирование индекса. o зачем использовать индекс в сочетании с SELECT *?

Если у вас это было, то индекс будет использоваться (как скан)

SELECT nobjectid
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000

Или это, скорее всего, будет использоваться новый индекс

CREATE NONCLUSTERED INDEX [IDX_Co,bined] 
ON [dbo].[tbl_event]([nobjectid] ASC, tetime)

SELECT nobjectid, tetime
FROM tbl_event 
WHERE tbl_nobjectid = 1410000
ORDER BY tetime

Предлагаю вам прочитать эти статьи

Недостаток кластеризованного индекса также должен охватываться этими статьями

...