Последовательный Guid и фрагментация

Я пытаюсь понять, как последовательный гид работает лучше, чем обычный гид.

Это потому, что при обычном guid для сортировки индекс использует последний байт guid? Поскольку это случайно, это вызовет много фрагментации и расщепление страницы, так как это часто будет перемещать данные на другую страницу, чтобы вставить новые данные?

Последовательный guid sine это последовательно, это вызовет намного меньше разбиений страницы и фрагментации?

Правильно ли мое понимание?

Если кто-то может пролить больше света на эту тему, я буду очень признателен.

Спасибо

РЕДАКТИРОВАТЬ:

Последовательный guid = NEWSEQUENTIALID(),

Обычный гид = NEWID()

3 ответа

Решение

Вы в значительной степени сказали все это в своем вопросе.

С помощью последовательного идентификатора GUID / первичного ключа новые строки будут добавляться вместе в конце таблицы, что упрощает работу SQL-сервера. Для сравнения, случайный первичный ключ означает, что новые записи могут быть вставлены в любое место таблицы - вероятность того, что последняя страница таблицы будет в кеше, весьма вероятна (если именно там происходят все операции чтения), однако вероятность случайная страница в середине таблицы, находящаяся в кеше, довольно мала, а это означает, что требуется дополнительный ввод-вывод.

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

Я полагаюсь на мудрость Кимберли Л. Триппа в этой теме:

Но GUID, который не является последовательным - как тот, у которого есть значения, сгенерированные в клиенте (с использованием.NET) ИЛИ сгенерированные функцией newid() (в SQL Server), может быть ужасно плохим выбором - прежде всего из-за фрагментации, которая он создается в базовой таблице, но также из-за его размера. Он неоправданно широк (он в 4 раза шире, чем основанная на int идентичность, что может дать вам 2 миллиарда (на самом деле, 4 миллиарда) уникальных строк). И, если вам нужно более 2 миллиардов, вы всегда можете использовать bigint (8-байтовое int) и получить 263-1 ряд.

Узнайте больше: http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx

Для визуализации всей картины можно использовать имя ostress. Например, вы можете создать две таблицы: одну с обычным GUID в качестве PK, другую с последовательным GUID:

-- normal one
CREATE TABLE dbo.YourTable(
   [id] [uniqueidentifier] NOT NULL,
   CONSTRAINT [PK_YourTable] PRIMARY KEY NONCLUSTERED (id)
);
-- sequential one
CREATE TABLE dbo.YourTableSeq(
   [id] [uniqueidentifier] NOT NULL CONSTRAINT [df_yourtable_id]  DEFAULT (newsequentialid()),
   CONSTRAINT [PK_YourTableSeq] PRIMARY KEY NONCLUSTERED (id)
);

Затем с помощью данного утилиты вы запускаете число вставок с выбором статистики о фрагментации индекса:

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTable VALUES (NEWID()); SELECT count(*) AS Cnt FROM dbo.YourTable; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTable';" -oE:\incoming\TMP\ -n1 -r10000

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTableSeq DEFAULT VALUES; SELECT count(*) AS Cnt FROM dbo.YourTableSeq; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTableSeq';" -oE:\incoming\TMP\ -n1 -r10000

Затем в файле E:\ Входящий \TMP\query.out вы найдете свою статистику. Мои результаты:

"Normal" GUID:
Records    AvgPageFragmentation     PageCounts           
---------------------------------------------- 
1000       87.5                     8                    
2000       93.75                    16                   
3000       96.15384615384616        26                   
4000       96.875                   32                   
5000       96.969696969696969       33                   
10000      98.571428571428584       70                   


Sequential GUID:
Records    AvgPageFragmentation     PageCounts           
---------------------------------------------- 
1000       83.333333333333343       6                    
2000       63.636363636363633       11                   
3000       41.17647058823529        17                   
4000       31.818181818181817       22                   
5000       25.0                     28                   
10000      12.727272727272727       55       

Как вы можете видеть при вставке последовательно сгенерированного GUID, индекс гораздо менее фрагментирован, поскольку операция вставки приводит к более редкому выделению страниц.

Другие вопросы по тегам