Автор: Paul Randal, Clustered or nonclustered index on a random GUID?
Увидел вопрос на форуме: если я вынужден использовать GUID и обязан иметь первичный ключ, должен ли я сделать первичный ключ кластерным или некластерным?
Тут я не собираюсь вдаваться в дискуссию о GUID против bigint в качестве идентификатора, или о случайном GUID против GUID, генерируемого NEWSEQUENTIALID(), так что, пожалуйста, не комментируйте эти вопросы, здесь они не актуальны. Я просто хочу ответить на вопрос: каким должен быть этот индекс?
С точки зрения механизма хранения (Storage Engine), мой ответ — некластерный. Вот три причины:
-
Если индекс кластерный, то ключ кластеризации имеет размер не менее 16 байт (размер GUID). Это не меняет размер записей кластерного индекса (поскольку столбец GUID в любом случае должен храниться в таблице, а кластерный индекс и есть таблица), но это меняет размер некластерных индексов. Все некластерные индексы таблицы должны включать ключи кластеризации, даже если они явно не являются частью ключей некластерного индекса (я напишу об этом отдельную статью). Это означает, что GUID присутствует также в каждой записи некластерного индекса. С этой точки зрения, лучше использовать меньший ключ кластеризации, а первичный ключ GUID сделать некластерным, чтобы он присутствовал только в одном некластерном индексе.
-
Случайные GUID, используемые как ключ высокого уровня, вызывают фрагментацию индекса. Их случайная природа означает, что точка вставки в индекс также случайна. Это вызывает расщепление страниц, которые приводят к фрагментации и являются дорогостоящими. Я немного касался этой темы в своей статье Насколько дороги расщепление страниц с точки зрения журнала транзакций?. Со случайным значением ключа трудно избежать разбиений страниц и фрагментации, хотя вы можете несколько отсрочить их с помощью
FILLFACTOR, но ценой использования дополнительного пространства. Сделав индекс GUID некластерным, вы можете отсрочить разбиения страниц ещё сильнее. Кластерный индекс — это таблица, поэтому записи в нём (как правило) больше, чем записи некластерного индекса. Это означает, что на 8-килобайтной странице помещается меньше записей кластерного индекса, чем некластерного. С меньшим количеством записей на странице можно выполнить меньше случайных вставок на страницу до того, как произойдёт разбиение. Таким образом, использование некластерного индекса для ключа GUID означает, что вы можете выполнять меньше дорогостоящих разбиений страниц. -
Учитывая, что независимо от типа индекса, создаваемого для ключа GUID, он будет подвержен фрагментации, вам, вероятно, потребуется периодически устранять фрагментацию в рамках плана обслуживания базы данных. Имеет смысл попытаться ограничить объём ресурсов, используемых операцией устранения фрагментации (например, ЦП, ввод-вывод, дисковое пространство, пространство в журнале транзакций), поэтому чем меньше фрагментированный индекс, тем лучше. Некластерный индекс для ключа GUID будет меньше, чем кластерный, поэтому если вы выберете ключ кластеризации, не вызывающий фрагментацию, и ограничите фрагментацию только некластерным индексом, вы сможете использовать меньше ресурсов при обслуживании базы данных.
И вот вам ответ. Уверен, некоторые из вас видели патологические случаи, опровергающие один из вышеперечисленных пунктов, но мои аргументы являются обобщениями. Возможно, я открыл ящик Пандоры, в таком случае с нетерпением жду комментариев!
P.S. Брент (Brent) написал отличный пост о юморе в блогах, ссылки на карикатуры, которые он включил, великолепны. Посмотрите здесь.

Комментариев нет:
Отправить комментарий