25 тыс. Вставок в день, фрагментация на 99% по кластерному индексу GUID - PullRequest
4 голосов
/ 17 января 2012

У меня есть таблица с первичным ключом в виде кластерного поля GUID; Я генерирую GUID, используя NEWSEQUENTIALID() вместо NEWID. К сожалению, поскольку в этой таблице число операций вставки ~ 25k-100k в день, в течение нескольких часов (первичный: кластеризованный) индекс первичного ключа становится фрагментированным на 99%.

Изначально я использовал NEWID вместо генерации последовательных идентификаторов, но даже когда я заново создал таблицу и заново вставил все строки, используя NEWSEQUENTIALID (и указал, что это значение по умолчанию для столбца первичного ключа), я все еще вижу фрагментацию порядка 99% в течение нескольких часов. (В настоящее время в таблице около 1,3 миллиона записей.

Я думал о замене GUID целочисленным первичным ключом, но я не уверен, будет ли это работать; Кроме того, поскольку наша команда использует GUID для первичных ключей вместо целых чисел, я не думаю, что у меня будет достаточно бай-ина для этого.

Какие у меня есть варианты сохранить эту вещь дефрагментированной? Я использую SQL Server Express, поэтому у меня нет доступа к агенту SQL (и поэтому я не могу регулярно запускать план обслуживания для перестройки индекса).

Возможно, что я когда-нибудь в будущем разделю эту базу данных / таблицу (из-за объема данных), поэтому мне, вероятно, понадобятся GUID для объединения таблиц.

Также: я не могу использовать индексированное представление, потому что у меня есть внутренняя выборка, которую мне было бы трудно развернуть в объединении.

Ответы [ 3 ]

5 голосов
/ 17 января 2012

По моему личному опыту, использование GUID s в качестве ключа кластеризации может оказать существенное положительное влияние на вашу систему, особенно на фрагментацию индекса!

Мои новые INT IDENTITY индексы кластеризации практически не имеют фрагментации - даже после нескольких месяцев интенсивного ежедневного использования продукции.Определенно стоит того !!

Использование типа данных Guid в качестве ключа кластеризации в SQL Server является ужасно плохим выбором - в зависимости от того, как вы на это смотрите ...

См. Некоторые из работ Кимберли Триппа( Королева индексирования ) сообщение в блоге на эту тему:

и все остальное, что она опубликовала в блоге на тему кластеризации ключей ....

1 голос
/ 17 января 2012

Это ожидаемое поведение для индексов Guid с большим количеством вставок.Большую часть времени вы выбираете направляющие в качестве ключей only , потому что записи генерируются несколькими источниками, и вам нужно, чтобы отдельные источники не наступали друг другу на пальцы.Примером здесь могут быть автономные мобильные устройства.Работник в поле должен создать новую запись, когда он не подключен, и поэтому мобильное устройство может безопасно создать запись с помощью guid в качестве ключа.При последующем подключении к сети устройство может безопасно синхронизироваться с базой данных, не беспокоясь о каких-либо коллизиях клавиш.

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

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

0 голосов
/ 17 января 2012

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

Если вам нужно использовать направляющие, возможно, посмотрите на их генерацию с помощью кода и отправьте их в ваших операторах вставки, а не полагайтесь на базу данных, которая их генерирует.Используйте технику «расчесывания», чтобы использовать текущую временную метку как часть руководства, увеличивая наименее значимые цифры.


edit

.. или если вы не хотите создавать их в коде, вы можете сделать что-то подобное в базе данных

CAST(CAST(NEWSEQUENTIALID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)

в качестве значения по умолчанию, согласно этой модификациивышеуказанный запрос

...