2013-11-18 4 views
8

У меня есть первичный ключ на столе (скажем, ContactID). SQL Server автоматически создает и поддерживает кластерный индекс в этом столбце. Когда я запускал Tuning Advisor (против трассировки производительности), он, по-видимому, рекомендовал другой INDEX в том же столбце - индекс NON CLUSTERED в столбце contactID. Как это поможет - поскольку в столбце уже есть кластеризованный индекс?некластеризованный индекс в столбце первичного ключа?

+1

ли какие-либо другие столбцы, включенные в новом индексе? Был ли новый индекс отсортирован так же, как и другой? – David

+1

Можете ли вы разместить сценарий для рекомендуемого индекса? – christiandev

ответ

3

Если консультант по настройке запроса рекомендует некластеризованный индекс первичного ключа, он также рекомендует кластеризованный индекс в другом столбце (или столбцах).

Первичный ключ - это ограничение, а не индекс. Предположения MS SQL Server заключаются в том, что первичный ключ также является основным способом получения данных из таблицы (через «где ContactID = 2» или соединение между таблицами на ContactID). Это предположение означает, что кластеризованный индекс также автоматически создается на столбцах, составляющих первичный ключ. Есть и другие причины такого поведения, но давайте сделаем это просто.

Теперь, если большинство запросов к таблице находятся в контактном имени (поле ContactFirstName) в чем-то вроде «Где ContactFirstName LIKE« Muh% », тогда SQL-сервер будет рекомендовать изменение кластерного индекса с ContactID на ContactFirstName, поскольку таблица может содержать только 1 кластеризованный индекс. Ограничение первичного ключа будет по-прежнему существовать (и предотвращать дублирование строк), но данные в таблице будут физически упорядочены по ContactFirstName.

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

+0

Это имеет смысл. Спасибо – user2736158

8

В особых обстоятельствах, таких как таблица, содержащая ContactID, большой и/или строки большие (то есть множество больших varchars), сканирование Clustered Index может быть очень интенсивным IO/памятью по сравнению с наличием ContactID как Кластерный индекс И как некластеризованный индекс.

Если запрос требует проверки таблицы, ContactID, и есть только кластерный индекс на ContactID, тогда вся строка данных считывается с диска. Однако, если у вас также есть индекс Non Clustered на ContactID, тогда только ContactID считывается с диска.

Это связано с тем, что кластеры vs Non Clustered хранятся на диске. Кластеризованные индексы сохраняются ContactID, но все данные строки также сохраняются вместе с ним. Скажем, каждая строка достаточно велика, чтобы занять одну страницу (8 КБ), а затем сканировать 100 000 000 строк требует 800 000 000 кбайт диска io.

Некластеризованный индекс хранит ContactID только в его строке. Предполагая, что ContactID имеет 8 байтов (bigint), 1000 строк индекса Non Clustered могут помещаться на одной странице (8 КБ). Теперь, сканируя 100 000 000 строк, ContactID, требуется только (100 000 000/1000 * 8) = 800 000 Кбайт диска io.

Если анализируемый запрос называется довольно часто, то 800 000 Кбайт по сравнению с 800 000 000 КБ является значительным.

Однако, как предложил Эвадман, советник по настройке рассматривает только конкретную рабочую нагрузку. В большинстве случаев дополнительный Non Clustered index будет просто дополнительной рабочей нагрузкой для вставок/удалений.

Реальный пример жизни, я работаю со столом, в котором много варчаров. Кластерный индекс - 5521 МБ. Существует несколько запросов, которые вызываются много раз в секунду, которые в конечном итоге выполняют частичное сканирование столбца кластерного индекса (позволяет называть его P_ID). Индекс без кластеров на P_ID равен 211 МБ (в 26 раз меньше, чем Clustered Idx).Это привело к значительному сокращению времени выполнения запросов, а также нагрузке на диск и память.

Bonus: запрос, чтобы выяснить, размер кластерных и не кластерных индексы

DECLARE @TableName VARCHAR(200) 
SET @TableName = 'NAME_OF_YOUR_TABLE' 

SELECT 
    OBJECT_NAME(i.OBJECT_ID) AS TableName, 
    i.name AS IndexName, 
    i.index_id AS IndexID, 
    8 * SUM(a.used_pages) AS 'Indexsize(KB)', 
    (8 * SUM(a.used_pages))/1024 AS 'Indexsize(MB)' 
FROM sys.indexes AS i 
JOIN sys.partitions AS p 
    ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id 
JOIN sys.allocation_units AS a 
    ON a.container_id = p.partition_id 
WHERE OBJECT_NAME(i.object_id) = @TableName 
GROUP BY i.OBJECT_ID,i.index_id,i.name 
ORDER BY OBJECT_NAME(i.OBJECT_ID),i.index_id 
+0

Спасибо.Это было полезно также. – user2736158

+0

Хороший пример. Некластеризованный индекс ContactID будет называться «индексом покрытия»; индекс имеет все данные, необходимые для выполнения запроса. ContactID звучит как инкрементное число, чтобы идентифицировать строку, поэтому она, скорее всего, не будет полезной для приложения сама по себе. Но если в другой таблице есть внешний ключ ContactID, это означает, что каждая вставка/обновление в другую таблицу также должна проверять, что ContactID существует. Поскольку в этом запросе потребуется только ContactID, индекс покрытия для ContactID удовлетворит его. Таким образом, пропустите полное сканирование большого кластерного индекса. – Evadman

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