Последовательный Guid и фрагментация - PullRequest
6 голосов
/ 10 августа 2010

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

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

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

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

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

Спасибо

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

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

Обычный guid = NEWID ()

Ответы [ 3 ]

9 голосов
/ 10 августа 2010

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

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

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

3 голосов
/ 10 августа 2010

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

Но 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#ixzz0wDK6cece

1 голос
/ 13 ноября 2015

Для визуализации всего изображения можно использовать util с именем ostress . Например. Вы можете создать две таблицы: одну с normal 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, индекс гораздо менее фрагментирован, поскольку операция вставки приводит к более редкому выделению страницы.

...