2013-07-25 4 views
12

В нашей базе данных у нас есть эта таблица с 200.000 строкПочему SQL Server не использует мой индекс?

CREATE TABLE dbo.UserTask (
    UserTask_ID int NOT NULL IDENTITY (1, 1), 
    UserTask_SequenceNumber int NOT NULL DEFAULT 0, 
    UserTask_IdEntitat uniqueidentifier NOT NULL, 
    UserTask_Subject varchar(100) NOT NULL, 
    UserTask_Description varchar(500) NOT NULL, 
      ..... 
      ..... 
    CONSTRAINT [PK_UserTask] PRIMARY KEY CLUSTERED 
    (
     [UserTask_ID] ASC 
    ) ON [PRIMARY] 
) ON [PRIMARY] 

Я создал индекс по UserTask_IdEntitat колонке с

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat ON dbo.UserTask 
(
    UserTask_IDEntitat 
) 

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

SELECT UserTask_ID 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

Но Если мы добавим еще одну колонку в Select список, то индекс не используется

SELECT UserTask_ID, UserTask_SequenceNumber, UserTask_IDEntitat, ....., UserTask_Subject 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

Почему добавление столбца отличается от первичного ключа делает, что план выполнения SQL-сервера не использует индекс на столбце UserTask_IDEntitat?

По этой ссылке http://bytes.com/topic/sql-server/answers/144592-sqlsever-not-using-index кажется, что количество раз, когда отфильтрованное значение повторяется в столбце, может сделать, что индекс не используется, но я попытался выполнить запрос с повторяющимся значением @IdEntitat 60 000 раз и другие, которые повторяются только 175 раз, и результаты те же, индекс на столбце IDEntitat игнорируется.

Это сходит с ума!

Благодарим за помощь.

+3

Если вы на подходящей версии, и это общий запрос, вы можете посмотреть в 'ВКЛЮЧИТЬ 'ing' _SequenceNumber' в индексе. –

+0

... и 'LastSendSystemDateTime' тоже, я думаю. (Чтобы помочь «заказать по»). –

ответ

32

OK - до тех пор, как вы выбираете только столбец, который находится в индексе, или что-то из ключа кластеризации (обычно, это первичный ключ), то индекс будет поскольку SQL Server может найти всю необходимую ему информацию (столбец UserTask_IDEntitat и кластерный столбец (индексы)) на уровне листа структуры навигации индекса. Таким образом, он может вернуть данные, необходимые для этого запроса SELECT, непосредственно на страницах уровня листа индекса.

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

Так для каждой строки он находит в вашем некластеризованном индексе, он должен принять значение индекса кластеризации, поиск кластерного индекса, чтобы найти фактическую страницу данных на уровне листьев этого кластерного индекса, и затем выберите тот столбец, который вы хотите.

Закладки поиска отлично подходят для небольшого количества ударов - они абсолютно разрушительны для производительности, если вы выбираете тысячи строк. В этом случае оптимизатор запросов SQL Server правильно использует кластерное сканирование вместо этого - поскольку в кластерном индексе на уровне листа он имеет все строки, доступные прямо сейчас.

Итак: если у вас есть индекс по UserTask_IDEntitat и иногда требуется второй столбец UserTask_SequenceNumber тоже - тогда вы могли бы включить этот столбец в этом некластеризованном индекс твоего:

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat 
ON dbo.UserTask(UserTask_IDEntitat) 
INCLUDE(UserTask_SequenceNumber) 

С этим, что дополнительные столбец присутствует только на уровне листа только этого некластеризованного индекса (он не может использоваться в предложении WHERE - он не является частью структуры навигации индекса!) - и ваш второй SELECT может быть снова удовлетворен из листа -уровневые узлы некластеризованного индекса -> нет ex нужны задумчивые закладки для поиска -> ваш индекс будет использоваться снова.

Короче говоря: если ваш некластеризованный индекс не высоко селективным (например, возвращает 1% от ваших строк или меньше), и если ваш некластеризованном индекс не является покрытия индекс (индекс, который содержит все столбцы, необходимые для удовлетворения определенного запроса), то изменения довольно высоки, что SQL Server будет NOT использовать ваш некластеризованный индекс.

Для получения дополнительной информации:

+0

Спасибо за подробный ответ и ваши полезные ссылки, что мне действительно нужно в производственных запросах, - это не только возврат UserTask_SequenceNumber, мне нужно вернуть все столбцы (второй запрос был плохим), в этом случае нет любая облегченная оптимизация, нет? SqlServer делает наиболее эффективный способ. –

+2

@MarcCals: если вам нужны ** все ** столбцы, то в большинстве случаев индексы не будут действительно помогать, так как кластерное сканирование индекса обычно более эффективно, чем тысячи тысяч поисков по закладкам –

Смежные вопросы