Какой некластеризованный индекс мне следует использовать? - PullRequest
1 голос
/ 23 мая 2010

Здесь я изучаю некластеризованные индексы в SQL Server Management Studio.

Я создал таблицу с более чем 1 миллионом записей. Эта таблица имеет первичный ключ.

CREATE TABLE [dbo].[Customers](
    [CustomerId] [int] IDENTITY(1,1) NOT NULL,
    [CustomerName] [varchar](100) NOT NULL,
    [Deleted] [bit] NOT NULL,
    [Active] [bit] NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
    [CustomerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

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

SELECT CustomerName FROM Customers

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

I/O cost = 3.45646
Operator cost = 4.57715

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

1) Первый некластеризованный индекс

CREATE NONCLUSTERED INDEX [IX_CustomerID_CustomerName] ON [dbo].[Customers] 
(
    [CustomerId] ASC,
    [CustomerName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Повторное выполнение таблицы выбора по клиентам, план выполнения показывает мне:

I/O cost = 2.79942
Operator cost = 3.92001

Кажется, лучше. Теперь я удалил только что созданный некластеризованный индекс, чтобы создать новый:

2) Первый некластеризованный индекс

CREATE NONCLUSTERED INDEX [IX_CustomerIDIncludeCustomerName] ON [dbo].[Customers] 
(
    [CustomerId] ASC
)
INCLUDE ( [CustomerName]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF,  
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF,   
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

С этим новым некластеризованным индексом я снова выполнил оператор select, и план выполнения показывает мне тот же результат:

I/O cost = 2.79942
Operator cost = 3.92001

Итак, какой некластеризованный индекс мне следует использовать? Почему затраты одинаковы для плана выполнения операций ввода-вывода и оператора? Я делаю что-то не так или это ожидается?

спасибо

Ответы [ 3 ]

2 голосов
/ 23 мая 2010

Это связано с тем, что "CustomerName" * * * во втором индексе * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

*1004*.вы - они покрыты индексами с первым столбцом индекса, НЕ совпадающим с предложением WHERE.

Это означает, что запрос в обоих случаях будет сканировать индекс, но НЕ касаться таблицы.

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

1 голос
/ 23 мая 2010

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

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

SELECT *
FROM Customers
WHERE CustomerName = 'Marcus Adams'

Затем добавьте индекс в столбец CustomerName и повторите попытку.

Вам также понадобится достаточно строк в таблице, чтобы система баз данных фактически использовала индекс, и достаточно, чтобы вы заметили разницу между сканированием строк и использованием индекса.

0 голосов
/ 23 мая 2010

Ни один из ваших двух некластерных индексов не имеет большого смысла, на самом деле.

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

Вопрос в следующем: как выбрать те строки, которые вы хотите отобразить? Какие столбцы будут отображаться в предложении WHERE?

Если вы найдете здесь образец (например, вы всегда выбираете, например, City), то некластеризованный индекс, соответствующий вашим потребностям, будет

CREATE NONCLUSTERED INDEX [IX_Customer_City] ON [dbo].[Customers] 
(
    [City] ASC
)
INCLUDE ( [CustomerName]) 

Таким образом, вы предоставляете SQL Server метод, позволяющий легко находить строки, соответствующие заданному городу, и в том числе столбец, который вы хотите вернуть (CustomerName), позволяет SQL Server получать необходимую информацию непосредственно со страницы индекса. (делая его так называемым covering index - он покрывает ваш запрос, например возвращает всю необходимую информацию) - вам не нужно делать «поиск по закладкам», например получить всю строку данных Customer с реальных страниц данных (найти ее через CustomerId, который также находится в некластеризованном индексе, поскольку это ключ кластеризации).

...