Для таблицы со столбцом идентификаторов следует ли создавать кластерный или некластеризованный индекс PK / уникальный для столбца идентификаторов?
Причина в том, что для запросов будут созданы другие индексы. Запрос, который использует некластеризованный индекс (в куче) и возвращает столбцы, которые не охватываются индексом, будет использовать менее логический ввод-вывод (LIO), поскольку нет дополнительных шагов поиска в b-дереве кластерного индекса?
create table T (
Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
B ....
C ....
....)
create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries
-- Common query is query on A, B, C, ....
select A, B
from T
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)
select A, B, C
from T
where B between @a and @a+5
....
Кластерный PK в столбце идентификаторов хорош, потому что:
Монотонно увеличивается, поэтому при вставке страницы не разбиваются. Говорят, что массовая вставка может быть такой же быстрой, как и в кучной (некластеризованной) таблице.
Это узко
Тем не менее, будут ли запросы в вопросе выполняться быстрее без настройки кластеризации?
** Обновление: ** Что если Id
FK других таблиц и он будет объединен в некоторых запросах?
Ответы:
По умолчанию ПК кластеризован, и в большинстве случаев это нормально. Однако, какой вопрос следует задать:
PK и Clustered index являются двумя отличиями:
Теперь у нас 2 вопроса:
Это зависит от того, как:
Во-первых, вам нужен кластерный индекс? При массовой вставке более эффективно хранить неупорядоченные данные в HEAP (по сравнению с упорядоченными данными в кластере). Он использует RID (идентификатор строки, 8 байт) для уникальной идентификации строк и сохранения их на страницах.
Кластерный индекс не должен быть случайным значением. Данные на уровне листа будут сохранены и упорядочены по ключу индекса. Поэтому он должен постоянно расти, чтобы избежать фрагментации или разбиения страницы. Если это не может быть достигнуто PK, вы должны рассмотреть другой ключ в качестве кластеризованного кандидата. Кластерный индекс для одинаковых столбцов, последовательный идентификатор GUID или даже что-то вроде даты вставки - это хорошо с последовательной точки зрения, поскольку все строки будут добавлены на последнюю конечную страницу. С другой стороны, хотя уникальный идентификатор может быть полезен для вашего бизнеса в качестве PK, их не следует кластеризовывать (они упорядочены / сгенерированы случайным образом).
Если после некоторого анализа данных и запросов вы обнаружите, что для получения данных в основном используете один и тот же индекс, прежде чем выполнять поиск ключа в кластеризованном PK, вы можете рассматривать его как кластерный индекс, хотя он может не однозначно идентифицировать ваши данные.
Ключ кластеризованного индекса состоит из всех столбцов, которые вы хотите проиндексировать. Столбец uniquefier (4 байта) добавляется, если на него нет уникального ограничения (инкрементное значение для дубликатов, в противном случае - ноль). Этот ключ индекса будет сохранен один раз для каждой строки на уровне листьев всех ваших некластеризованных индексов. Некоторые из них также будут храниться несколько раз на промежуточных уровнях (ветвях) между корнем и уровнем листьев дерева индексов (B-дерево). Если ключ слишком большой, все некластеризованные индексы станут больше, потребуется больше памяти и больше ввода-вывода, процессора, памяти, ... Если у вас есть PK на имя + дата рождения + страна, весьма вероятно, что этот ключ не хороший кандидат. Он слишком велик для кластерного индекса. Уникальный идентификатор с использованием NEWSEQUENTIALID () обычно не считается узким ключом (16 байт), хотя он является последовательным.
Затем, когда вы выяснили, как уникально идентифицировать строки в вашей таблице, вы можете добавить PK. Если вы думаете, что не будете использовать его в своем запросе, не создавайте его кластеризованно. Вы все еще можете создать другой некластеризованный индекс, если вам когда-нибудь понадобится запросить его. Обратите внимание, что ПК автоматически создаст уникальный индекс.
Некластеризованные индексы всегда будут содержать кластеризованный ключ. Однако, если индексированные столбцы (+ ключевые столбцы) покрывают, не будет никакого ключевого поиска в кластеризованном индексе. Не забывайте, что вы можете также добавить «Включить» и «Где» в некластеризованный индекс. (использовать его мудро)
Кластерный индекс должен быть уникальным и как можно более узким Кластерный индекс не должен изменяться со временем и должен добавляться постепенно.
Теперь пришло время написать некоторый SQL, который создаст таблицу, кластерные и некластеризованные индексы и ограничения.
Это все теоретически, потому что мы не знаем вашу модель данных и используемые типы данных (A и B).
источник
Если вы спрашиваете, должен ли стандарт по умолчанию для первичного ключа в столбце идентификаторов (в частности) быть некластеризованным, я бы сказал, что нет. Большинству таблиц выгодно иметь кластеризованный индекс, поэтому, в целом, кластеризация по умолчанию для ограничения первичного ключа может быть полезной, особенно для новых пользователей SQL Server.
Как и в случае практически любого другого варианта, всегда есть разные обстоятельства, когда один из них предпочтительнее другого, но опытный администратор базы данных должен знать о настройках по умолчанию и иметь возможность переопределять их, когда это необходимо. Также см. Соответствующие вопросы и ответы. Когда первичный ключ должен быть объявлен некластеризованным? ,
Да, но с оговорками.
Поиск RID действительно более эффективен, чем поиск по ключу. Даже если все требуемые страницы находятся в памяти (весьма вероятно, для верхних уровней индекса), с навигацией по B-дереву кластерного индекса связаны затраты ЦП. Как следствие, SQL Server обычно может выполнять гораздо больше запросов RID, чем поиск ключей на единицу процессорного времени.
Предостережения
Вышеупомянутое не часто будет определяющим фактором при принятии решения, структурировать ли таблицу как кучу или нет. Было бы непрактично избегать поисков (с использованием покрывающих индексов), а количество поисков должно быть достаточно большим, чтобы оказывать измеримое (и важное) влияние на производительность, учитывая аппаратную среду и рабочую нагрузку.
В этом ответе не очень практично охватывать все аспекты дебатов "куча против кластерного индекса", но я скажу, что есть относительно немного веских причин, чтобы предпочесть структурировать таблицу как кучу в целом. Для меня выбор типа конструкции, предложенной в этом вопросе, потребует очень тщательного анализа перед внедрением и должен соответствовать высокой планке. Общие аргументы о «масштабируемости» не будут достаточными.
Что касается обновления вопроса о объединениях, оценка влияния потери кластеризованного индекса на планы выполнения будет составной частью анализа, упомянутого выше. Если используются объединения с вложенными циклами, очень удобно иметь кластеризованный индекс на ключе объединения, поскольку все столбцы в строке сразу доступны без поиска.
Мой собственный опыт показывает, что наличие уникальных кластеризованных индексов в столбцах идентификаторов очень полезно, и все вещи учитываются. Я обнаружил, что кучи проблематичны с точки зрения управления пространством, и я должен также упомянуть, что для работы некоторых функций SQL Server требуется уникальный кластеризованный индекс.
источник
На самом деле вам не нужно создавать кластерный индекс или первичный ключ, так как уникальные индексы и неуникальные индексы могут справиться с работой. SQL Server поддерживает кластеризованный индекс начиная с версии не ниже 1.1, но первичный ключ был просто «концепцией», которую программисты применяли, определяя уникальный индекс.
Но кажется, что и первичные ключи, и кластерные индексы являются ценными понятиями в большинстве баз данных.
Давайте посмотрим на документацию по SQL Server, чтобы увидеть частичное описание некоторых параметров индексации, как показано ниже.
Кластерный индекс: https://msdn.microsoft.com/en-us/library/ms190457.aspx
Первичный ключ: https://msdn.microsoft.com/en-us/library/ms190457.aspx
Таблица может содержать только одно ограничение PRIMARY KEY.
Все столбцы, определенные в ограничении PRIMARY KEY, должны быть определены как NOT NULL.
Первичный ключ может быть создан как кластеризованный индекс (по умолчанию, если нет кластерного индекса) или некластеризованный индекс.
Уникальный индекс: https://msdn.microsoft.com/en-us/library/ms187019.aspx
При создании ограничения UNIQUE создается уникальный некластеризованный индекс для принудительного применения ограничения UNIQUE по умолчанию.
Вы можете указать UNIQUE Clustered Index, если кластерный индекс еще не существует для таблицы.
Это означает, что ваш вопрос о кластерных индексах и первичных ключах действительно связан с некоторыми из следующих проблем. Обратите внимание, что не для каждой таблицы используется один и тот же план индексации.
Когда я получу выгоду от того, что первичный ключ отделен от кластерного индекса?
Возможно, когда Кластерный Индекс Широкий (например, 5 столбцов текстовой информации, но Первичный Ключ маленький (INT или BIGINT), как вы, кажется, описываете.
Стоит ли делать первичный ключ одним кластерным индексом?
Если у вас есть маленький первичный ключ (INT или BIGINT), и это кластерный индекс, накладные расходы на столбцы кластера относительно невелики. Хотя Кластерный первичный ключ в этом случае также будет присутствовать в каждом индексе этой таблицы, это меньшая цена, чем широкий кластер, рассмотренный выше.
Этот кластеризованный индекс первичного ключа обычно не предлагает простой способ последовательного выбора множества строк.
Теперь, когда вы создали кластерный первичный ключ, как насчет тех других столбцов, которые вы когда-то планировали включить в кластерный индекс ?
Создайте уникальный (или неуникальный) индекс, необходимый для индексации широкого критерия поиска по столбцам C1, C2, C3, C4, C5. Значения в этом «Имитационном кластеризованном» индексе могут служить более быстрым путем поиска для этих 5 столбцов. Если существует неиндексированный столбец или два, которые также регулярно выбираются, они могут быть включены в индекс с помощью
INCLUDE (Doctor_Name, Diagnosis_Synopsis)
.Хотя я нахожу простые кластерные индексы и первичные ключи полезными, есть несколько веских причин для размышления, использовать ли их в таблице или в базе данных.
Вам нужен кластерный индекс вообще?
Если вы создаете индексы (уникальные индексы и неуникальные индексы) и определяете первичный ключ без использования кластерного индекса, вы можете обнаружить, что более узкие индексы предоставляют вам то, что вам нужно для ваших запросов.
В кластерных индексах и первичных ключах есть несколько полезных вариантов поведения, но помните, что на самом деле именно индексы имеют наибольшее значение. Разработайте стратегию индексирования с учетом реалий вашего приложения. Возможно,
OneBigTable
необходимо иметь стратегию индексации, отличную от той, которую вы используете для большинства таблиц.Без кластерного индекса ваши данные будут храниться в виде кучи с идентификатором строки (RID), который вообще не является хорошим механизмом поиска. Но, как упоминалось ранее, вы можете создавать уникальные и неуникальные индексы для обработки ваших запросов.
Что теперь приводит вас к рассмотрению кучи:
Кучи и индексы: https://msdn.microsoft.com/en-us/library/hh213609.aspx
Но если у вас также есть «горячие точки» в большом наборе данных, вы также можете посмотреть на другой тип индекса:
Отфильтрованный индекс: https://msdn.microsoft.com/en-us/library/cc280372.aspx
Хорошо спроектированный отфильтрованный индекс повышает производительность запросов и качество плана выполнения, поскольку он меньше некластерного индекса полной таблицы и имеет отфильтрованную статистику. Отфильтрованная статистика является более точной, чем статистика полной таблицы, поскольку она охватывает только строки в отфильтрованном индексе .
Отфильтрованные индексы имеют ряд ограничений, которые указаны в ссылке на отфильтрованные индексы.
Однако, если вам интересно подумать об этой возможности вообще пропустить Первичные ключи и Кластерные индексы, вы можете прочитать пост Маркуса Винанда, связанный ниже. Он демонстрирует свои причины с некоторыми примерами кода, чтобы предположить, что иногда было бы неплохо отказаться от использования этих функций.
http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key
Но в конечном итоге все возвращается к пониманию вашего приложения и разработке кода, таблиц, индексов и т. Д. В соответствии с выполняемой работой.
источник
Пара моментов для рассмотрения.
Хотя индекс (кластеризованный или нет) для монотонно увеличивающегося значения сохраняет разделы страниц во время массовых вставок, он создает новую горячую точку в хвостовой части индекса. Хотя это может и не быть проблемой с массовой вставкой одного потока, это определенно увеличит конкуренцию многопоточному приложению, вставляющему новые кортежи с высокой скоростью, так как потоки будут постоянно конкурировать за доступ к последней странице индекса.
Кластеризация таблицы на основе суррогатного (идентификационного) ПК редко бывает полезна. Такой первичный ключ чаще всего используется для доступа к отдельным кортежам по одному или для сканирования всего индекса на предмет соединений. В любом случае не имеет значения, является ли индекс кластеризованным или нет (может быть, за исключением объединений слиянием, но как часто они бывают?)
Я думаю, что вы больше всего выиграете от кластерного индекса, который охватывает запросы, запрашивающие сканирование диапазона ключей, и дополнительные предикаты, ссылающиеся на другие столбцы.
источник