Я читал Clustered
и Non Clustered Indexes
.
Clustered Index
- Он содержит страницы данных. Это означает, что полная информация о строке будет присутствовать в столбце кластерного индекса.
Non Clustered Index
- Он содержит только информацию о Локаторе строк в форме столбца Кластерный индекс (если имеется) или Идентификатор файла + Номер страницы + Общее количество строк на странице. Это означает, что механизм запросов должен предпринять дополнительный шаг, чтобы найти фактические данные.
Запрос - Как я могу проверить разницу в производительности с помощью практического примера , как мы знаем , что таблица может иметь только один , Clustered Index
и обеспечивает sorting
на Clustered Index Column
и Non Clustered Index
не обеспечивает sorting
и может поддерживать 999 Non Clustered Indexes
в SQL Server 2008
и 249 в SQL Server 2005
.
Ответы:
Очень хороший вопрос, поскольку это такая важная концепция. Это большая тема, и то, что я собираюсь показать вам, является упрощением, чтобы вы могли понять основные концепции.
Во-первых, когда вы видите таблицу кластеризованного индекса . На сервере SQL, если таблица не содержит кластеризованный индекс, это куча. Создание кластеризованного индекса в таблице фактически превращает таблицу в структуру типа b-дерева. Ваш кластерный индекс - это ваша таблица, она не отделена от таблицы
Вы когда-нибудь задумывались, почему у вас может быть только один кластерный индекс? Ну, если бы у нас было два кластеризованных индекса, нам понадобилось бы две копии таблицы. В конце концов, он содержит данные.
Я попытаюсь объяснить это на простом примере.
НОТА: Я создал таблицу в этом примере и заполнил ее более чем 3 миллионами случайных записей. Затем запустил фактические запросы и вставил планы выполнения здесь.
Что вам действительно нужно понять, так это обозначение O или эффективность работы . Предположим, у вас есть следующая таблица.
Итак, здесь у нас есть базовая таблица с кластеризованным ключом на CustomerID (первичный ключ кластеризован по умолчанию). Таким образом, таблица организована / упорядочена на основе первичного ключа CustomerID. Промежуточные уровни будут содержать значения CustomerID. Страницы данных будут содержать всю строку, таким образом, это строка таблицы.
Мы также создадим некластеризованный индекс в поле CustomerName. Следующий код сделает это.
Таким образом, в этом индексе вы найдете на страницах данных / узлах конечного уровня указатель на промежуточные уровни в кластерном индексе. Индекс расположен / упорядочен вокруг поля CustomerName. Таким образом, промежуточный уровень содержит значения CustomerName, а конечный уровень будет содержать указатель (эти значения указателя фактически являются значениями первичного ключа или столбца CustomerID).
Правильно, если мы выполним следующий запрос:
SQL, вероятно, будет читать кластерный индекс с помощью операции поиска. Операция поиска - это бинарный поиск, который намного эффективнее сканирования, который является последовательным поиском. Таким образом, в приведенном выше примере индекс читается и с помощью бинарного поиска SQL может удалить данные, которые не соответствуют критериям, которые мы ищем. Смотрите прикрепленный снимок экрана для плана запроса.
Таким образом, число операций или обозначение O для операции поиска выглядит следующим образом:
Так что это две операции. Однако, если мы выполнили следующий запрос:
SQL теперь будет использовать некластеризованный индекс для CustomerName для поиска. Однако, поскольку это некластеризованный индекс, он не содержит все данные в строке.
Таким образом, SQL выполнит поиск на промежуточных уровнях, чтобы найти соответствующие записи, а затем выполнит поиск, используя возвращенные значения, чтобы выполнить другой поиск по кластерному индексу (или таблице), чтобы получить фактические данные. Это звучит странно, я знаю, но читаю, и все станет ясно.
Поскольку наш некластеризованный индекс содержит только поле CustomerName (значения индексированных полей, хранящиеся в промежуточных узлах) и указатель на данные, которые являются CustomerID, в индексе нет записи CustomerSurname. Имя CustomerSurname должно быть получено из кластерного индекса или таблицы.
При выполнении этого запроса я получаю следующий план выполнения:
На снимке экрана выше вы можете заметить две важные вещи
Почему SQL снова предлагает индекс для CustomerName? Хорошо, поскольку индекс содержит только CustomerID и SQL CustomerName все еще должен найти CustomerSurname из таблицы / кластерных индексов.
Если бы мы создали индекс и включили столбец CustomerSurname в индекс SQL, он мог бы удовлетворить весь запрос, просто прочитав некластеризованный индекс. Вот почему SQL предлагает мне изменить свой некластеризованный индекс.
Здесь вы можете увидеть дополнительную операцию, которую должен выполнить SQL, чтобы получить столбец CustomerSurname из кластерного ключа.
Таким образом, количество операций выглядит следующим образом:
Это 4 операции, чтобы получить значения. Вдвое больше операций, необходимых для чтения кластерного индекса. Показывает, что ваш кластеризованный индекс - ваш самый мощный индекс, поскольку он содержит все данные.
Так что просто уточнить один последний момент. Почему я говорю, что указатель в некластеризованном индексе является значением первичного ключа? Чтобы продемонстрировать, что узлы конечного уровня некластеризованного индекса содержат значение первичного ключа, я изменяю свой запрос на:
В этом запросе SQL может читать CustomerID из некластеризованного индекса. Для этого не нужно искать кластерный индекс. Это вы можете увидеть по плану выполнения, который выглядит следующим образом.
Обратите внимание на разницу между этим запросом и предыдущим запросом. Там нет поиска. SQL может найти все данные в некластеризованном индексе
Надеюсь, вы начнете понимать, что кластерный индекс - это таблица, а некластеризованные индексы не содержат всех данных. Индексирование ускорит выборку из-за того, что двоичный поиск может быть выполнен, но только кластерные индексы содержат все данные. Таким образом, поиск по некластеризованному индексу почти всегда приводит к загрузке значений из кластеризованного индекса. Эти дополнительные операции делают некластеризованные индексы менее эффективными, чем кластеризованный индекс.
Надеюсь, это прояснит ситуацию. Если что-то не имеет смысла, пожалуйста, оставьте комментарий, и я постараюсь уточнить. Здесь уже довольно поздно, и мой мозг чувствует себя крошечным. Время для красного быка.
источник
«Это означает, что механизм запросов должен сделать дополнительный шаг, чтобы найти фактические данные».
Не обязательно - если индекс охватывает данный запрос, не нужно совершать никаких поездок на страницы данных. Кроме того, с включенными столбцами, дополнительные столбцы могут быть добавлены к некластерному индексу, чтобы охватить его без изменения размера ключа.
Таким образом, окончательный ответ - это зависит (от гораздо большего количества информации, чем вы можете охватить в одном вопросе) - вам нужно понимать все возможности индексов, и план выполнения для данного запроса может отличаться от ваших ожиданий.
Общее практическое правило, которое у меня есть, состоит в том, что таблица всегда имеет кластеризованный индекс (и обычно на идентификаторе или последовательном GUID), но некластеризованные индексы добавляются для повышения производительности. Но всегда есть исключения - у таблиц кучи есть место, у более широких кластерных индексов есть место. Кажется, что избыточные индексы, которые уже для размещения большего количества строк на странице, имеют место. и т. д.
И я не стал бы беспокоиться о допустимых пределах для различных индексов - это почти наверняка не войдет в игру во многих реальных примерах.
источник
there are always exceptions
- слишком много людей опускают это и думают, что каждый кластерный индекс должен бытьint identity
несмотря ни на что.