Кластеризованный против некластеризованного

98

Мои знания SQL на более низком уровне (Server 2008) ограничены, и теперь наши администраторы баз данных оспаривают их. Позвольте мне объяснить (я упомянул очевидные утверждения в надежде, что я прав, но если вы видите что-то не так, скажите мне) сценарий:

У нас есть стол, в котором хранятся «Судебные приказы» для людей. Когда я создал таблицу (Имя: CourtOrder), я создал ее так:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Затем я применил некластеризованный индекс к первичному ключу (для эффективности). Мои причины заключаются в том, что это уникальное поле (первичный ключ), и его следует индексировать, в основном для целей выбора, поскольку мы частоSelect from table where primary key = ...

Затем я применил КЛАСТЕРНЫЙ индекс для PersonId. Причина заключалась в том, чтобы сгруппировать заказы для конкретного человека физически, так как подавляющее большинство работы - это получение заказов для человека. Так,select from mytable where personId = ...

Меня сейчас на этом остановили. Мне сказали, что мы должны поместить кластерный индекс на первичный ключ, а нормальный индекс на personId. Мне это кажется очень странным. Во-первых, зачем помещать кластерный индекс в уникальный столбец? что это за кластеризация? Неужели это пустая трата кластерного индекса? Я бы подумал, что нормальный индекс будет использоваться для уникального столбца. Кроме того, кластеризация индекса означает, что мы не можем кластеризовать другой столбец (по одному на таблицу, верно?).

Причина, по которой мне сказали, что я совершил ошибку, состоит в том, что они считают, что кластеризованный индекс для PersonId замедлит вставку. При 5% -ном приросте скорости выбора мы бы получили 95% -ное снижение скорости при вставках и обновлениях. Это правильно и верно?

Они говорят, что, поскольку мы группируем personId, SQL Server должен переупорядочивать данные, когда мы вставляем или изменяем PersonId.

Тогда я спросил, почему в SQL должна быть концепция КЛАСТЕРИРОВАННОГО ИНДЕКСА, если он такой медленный? Это так медленно, как они говорят? Как мне настроить индексы для достижения оптимальной производительности? Я бы подумал, что SELECT используется больше, чем INSERT ... но они говорят, что у нас проблемы с блокировкой INSERTS ...

Надеюсь, кто-нибудь может мне помочь.

Крейг
источник

Ответы:

117

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

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

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

Адам Робинсон
источник
Спасибо, Адам. Итак, когда тогда будет полезен кластерный индекс? Я думал, что преимущество кластерного индекса заключается в том, чтобы сгруппировать данные для тех случаев, когда, например, большинство запросов относятся к PersonID ... чтобы данные были сгруппированы.
Craig
3
Он не физически отсортированы по PersonId. Он логически отсортирован PersonId, любое несоответствие между логическим и физическим порядком - это степень логической фрагментации.
Мартин Смит
1
@cdotlister Преимущество индекса в том, чтобы сортировать данные, а не группировать их (что подразумевает дублирование данных в индексе). Хотя различие может показаться семантическим, в случае кластерных индексов это не так. Если возможно, кластеризованный индекс должен быть на чем-то, что однозначно идентифицирует строку и (в идеале) также является наиболее часто запрашиваемым столбцом или набором столбцов. Вот почему обычно это первичный ключ.
Адам Робинсон
1
@CyberSluethOmega: я не знаю; Ваш вопрос не содержит достаточно информации, чтобы я мог принять решение. Хотел бы я кластеризованный индекс для набора столбцов, в котором строки будут часто добавляться или удаляться, кроме как в конце таблицы ? Нет. Но я не совсем уверен, почему вы спрашиваете об этом или почему голос против.
Адам Робинсон
1
@CyberSluethOmega: Интернет может делать комментарии оборонительными или холодными, если они не предназначены для этого. Вы утверждали, что я сказал, что мне не известно ни о каких обстоятельствах, при которых кластерный индекс мог бы быть чем-то другим, кроме первичного ключа, хотя на самом деле я ничего такого не сказал. В самом деле, что я сказал «это необычно ..., но не неслыханное», что означает , что я действительно знаю случаев , когда это делается.
Адам Робинсон
14

Я ни в коем случае не эксперт по SQL ... так что воспринимайте это как точку зрения разработчика, а не как точку зрения администратора баз данных ...

Вставки в кластеризованные (физически упорядоченные) индексы, которые не находятся в последовательном порядке, вызывают дополнительную работу для вставок / обновлений. Кроме того, если у вас одновременно выполняется много вставок, и все они происходят в одном месте, возникает конфликт. Ваша конкретная производительность зависит от ваших данных и способа доступа к ним. Общее практическое правило - построить кластерный индекс на основе наиболее уникального узкого значения в таблице (обычно PK).

Я предполагаю, что ваш PersonId не изменится, поэтому обновления здесь не применяются. Но рассмотрим снимок нескольких строк с PersonId 1 2 3 3 4 5 6 7 8 8

Теперь вставьте 20 новых строк для PersonId из 3. Во-первых, поскольку это не уникальный ключ, сервер добавляет несколько дополнительных байтов к вашему значению (за кулисами), чтобы сделать его уникальным (что также добавляет дополнительное пространство), а затем местоположение, где они должны быть изменены. Сравните это со вставкой автоматически увеличивающегося PK, где вставки происходят в конце. Нетехническое объяснение, скорее всего, сводится к следующему: меньше работы по «перетасовке листьев», если она естественным образом увеличивает значения в конце таблицы по сравнению с переделкой местоположения существующих элементов в этом месте при вставке ваших элементов.

Теперь, если у вас возникли проблемы со вставками, вы, вероятно, вставляете сразу несколько одинаковых (или похожих) значений PersonId, что вызывает эту дополнительную работу в разных местах по всей таблице, и фрагментация вас убивает. Обратной стороной переключения на кластеризацию PK в вашем случае является то, что сегодня у вас возникли проблемы со вставкой на PersonIds, которые различаются по значению, разбросанному по всей таблице, если вы переключите свой кластеризованный индекс на PK, и все вставки теперь происходят в одном местоположение, то ваша проблема может усугубиться из-за повышенной концентрации конфликтов. (С другой стороны, если ваши вставки сегодня не разбросаны повсюду, а все обычно сгруппированы в схожих областях, то ваша проблема, вероятно, упростится, если переключить кластерный индекс с PersonId на ПК, потому что вы минимизируете фрагментация.)

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

В любом случае удачи!

Дариан Миллер
источник
5

Некоторые авторы предлагают не «тратить зря» CIна identityстолбец, если есть альтернатива, которая принесет пользу запросам диапазона.

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

  1. Может использоваться для часто используемых запросов.
  2. Обеспечивают высокую степень уникальности.
  3. Может использоваться в запросах диапазона.

Ваша CourtOrderIDколонка встречается 2. Ваша PersonIdвстречает 1и 3. Поскольку большинство строк все uniqueifierравно будут добавлены, вы можете просто объявить его уникальным и использовать, PersonId,CourtOrderIDпоскольку он будет той же ширины, но будет более полезен, поскольку ключ кластеризованного индекса добавляется ко всем NCI в качестве локатора строк, и это позволит их, чтобы охватить больше запросов.

Основная проблема с использованием PersonId,CourtOrderIDв качестве CI заключается в том, что, скорее всего, последует логическая фрагментация (и это особенно влияет на запросы диапазона, которым вы пытаетесь помочь), поэтому вам нужно будет отслеживать коэффициент заполнения и уровни фрагментации и чаще выполнять обслуживание индекса.

Мартин Смит
источник
3

Это объясняется по следующей ссылке: https://msdn.microsoft.com/en-us/ms190457.aspx

Кластеризованный

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

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

Некластеризованный

  • Некластеризованные индексы имеют структуру, отдельную от строк данных. Некластеризованный индекс содержит значения ключей некластеризованного индекса, и каждая запись значения ключа имеет указатель на строку данных, содержащую значение ключа .

  • Указатель из строки индекса в некластеризованном индексе на строку данных называется локатором строки. Структура локатора строк зависит от того, хранятся ли страницы данных в куче или в кластерной таблице. Для кучи локатор строки - это указатель на строку. Для кластеризованной таблицы указателем строки является ключ кластеризованного индекса.

  • Вы можете добавить неключевые столбцы на конечный уровень некластеризованного индекса, чтобы обойти существующие ограничения ключа индекса, 900 байт и 16 ключевых столбцов, и выполнить полностью покрытые, индексированные запросы.

user2191454
источник
-3

Некоторая база данных с некоторыми неприятными выборами присоединяется к хранимой процедуре - только разница - это индекс

ИНДЕКСЫ - кластеризованные против некластеризованных

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
источник