GUID кластеризованный PK быстрее, чем BIGINT и INT Identity PK в SQL Server 2012 Express?

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

Я запускаю сценарий длиной 65000 строк, который создает целую кучу таблиц (включая мои таблицы) и хранимых процедур (примерно половина времени, потраченного на них), затем продолжает вставлять в мои таблицы около 40000 записей, а затем обновляет около 20000 из этих записей.

На моей 8-ядерной машине AMD 3,5 ГГц это занимает 1:15.

Удивительно, но если я изменю эти 5 таблиц таким образом, что - Добавлю БОЛЬШОЙ первичный суррогатный ключ идентификации (запросы по-прежнему соединяются с использованием GUID) - Понижу предыдущий кластеризованный первичный ключ GUID до уникального столбца

то он работает в 3:00 минут!

Изменение его с BIGINT на INT занимает примерно 1:30!

Как возможно, что кластерный ПК GUID работает значительно быстрее, чем автоматически увеличивающийся INT, и намного быстрее, чем автоинкрементируемый кластерный ПК BIGINT?

ПРИМЕЧАНИЕ. Сами значения GUID генерируются в коде, а не в базе данных.

Посмотрите этот упрощенный тестовый скрипт, демонстрирующий, что я имею в виду.

http://pastebin.com/ux5wUJgC


person Herman Schoenfeld    schedule 21.05.2013    source источник
comment
Можете ли вы предоставить простой исполняемый скрипт, воспроизводящий эти характеристики на вашем компьютере?   -  person Martin Smith    schedule 21.05.2013
comment
@MartinSmith: да, проверьте pastebin.com/G6BszR66 Явно кластеризованный guid pk выигрывает.   -  person Herman Schoenfeld    schedule 21.05.2013
comment
Ах да. Не очень удивительно. В случаях int/bigint нужно поддерживать два индекса, а не один. И у некластеризованного Guid будут точно такие же проблемы с фрагментацией, как и у кластеризованного Guid.   -  person Martin Smith    schedule 21.05.2013
comment
@MartinSmith: еще медленнее с двумя индексами в каждом .. также тестировалось на предприятии sql server 2008, еще медленнее ... ну ладно   -  person Herman Schoenfeld    schedule 22.05.2013
comment
Вставка и обновление менее 100 000 записей займет у вас не более минуты. Это очень, очень долго. Ссылки внешнего ключа между таблицами также не должны влиять на производительность. Вы должны открыть новый вопрос StackOverflow с содержимым ваших sprocs и схемы таблицы. Там происходит что-то странное, и вы не должны этого делать: To make it efficient, I've dropped foreign-keys between the tables.   -  person tommy_o    schedule 23.05.2013


Ответы (2)


Используя ваши тестовые случаи, это ожидается. Первый тест увеличивает только таблицу с одним полем. Два других строят два столбца и два индекса.

Вот более подходящий тест. Все три теста имеют поле GUID и поле INT (или BIGINT). Все поля проиндексированы. Тестовая таблица с PK на INT с некластеризованным индексом на UID на моем сервере быстрее на 2 секунды.

Вот мой тестовый код: http://pastebin.com/MFTA3Da1

person tommy_o    schedule 21.05.2013
comment
Я также добавил WITH (FILLFACTOR = 90) к индексам GUID. Это поможет избежать дробления индекса по мере роста индекса. - person tommy_o; 21.05.2013
comment
Кластерный PK GUID все еще быстрее на 3 секунды по сравнению с INT IDENTITY в моем тесте после добавления 2 указанных вами индексов - pastebin. com/ux5wUJgC . Похоже, что люди, атакующие первичные ключи guid, понятия не имели. Ну что ж, теперь нужно откатить кучу изменений, чтобы использовать прямые GUID pk. - person Herman Schoenfeld; 22.05.2013
comment
Если вы удалите обработку транзакций, создадите таблицы перед тестом и выполните его, на моем сервере все будет наоборот (SQL Server 2008 R2 Enterprise, 16 ядер и т. д. и т. д.). - person tommy_o; 22.05.2013
comment
разница мизерная. Дело в том, что кластеризованные ключи GUID сами по себе лучше или на одном уровне с производительностью кластерного удостоверения + некластеризованного индекса GUID. - person Herman Schoenfeld; 23.05.2013

После долгих испытаний оказалось, что использование guid pk быстрее, чем суррогатный ключ int и естественный ключ guid.

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

В двух словах - если вам нужно идентифицировать записи с помощью guid, то их ключ должен быть guid!

person Herman Schoenfeld    schedule 22.05.2013
comment
Вы неправильно понимаете проблемы, связанные с фрагментацией индекса в кластерном первичном ключе GUID. Есть 2 проблемы: во-первых, GUID почти случайный, поэтому без фактора заполнения B-дерево индекса будет постоянно разделяться. Это очень плохо, но его можно в значительной степени преодолеть за счет высокого коэффициента заполнения. Вторая проблема заключается в том, что каждый другой индекс в вашей таблице также должен сохранять этот 16-байтовый указатель на PK вместо 4-байтового типа данных INT. Если все, что вы делаете, это сохраняете таблицу с GUID и только тестируете скорость вставки, тогда просто PK GUID с fill. - person tommy_o; 22.05.2013
comment
Этот пост в блоге дает хороший обзор плюсов и минусов кластеризованных PK в GUID для всех, кто заинтересован: blogs.msdn.com/b/dbrowne/archive/2012/06/26/ - person tommy_o; 22.05.2013
comment
@tommy_o: Это не я неправильно понимаю вашу точку зрения, это сам SQL Server. Я провел БОЛЬШИЕ тесты на 2008/2012 и заметил, что FILLFACTOR не оказывает влияния на 0%. В этом блоге предлагается сделать GUID некластеризованным ключом, но это означает, что мне нужен дополнительный кластеризованный ключ идентификации, который замедляет работу в 2 раза. Было бы полезно, если бы вы могли подтвердить свои утверждения некоторыми (воспроизводимыми) доказательствами. Я потратил 2 дня на настройку базы данных только для того, чтобы восстановить ее обратно. - person Herman Schoenfeld; 23.05.2013
comment
@tommy_o: я также менял тесты с включенным PAD_INDEX и не имел никакого влияния. - person Herman Schoenfeld; 23.05.2013
comment
Блог Microsoft отлично объясняет это. Ваши тесты недостаточно велики для одного, и ваши тестовые GUID должны быть сгенерированы в нескольких источниках, чтобы он мог быть вставлен в середину B-дерева. - person tommy_o; 23.05.2013
comment
Для тех, кто задается вопросом, почему GUID оказывается быстрее, потому что наличие 1 медленного ключа guid все еще быстрее, чем наличие 1 быстрого автоинкремента pk и 1 медленного уникального столбца guid. Так что, если ваши записи ДОЛЖНЫ содержать руководство, то нет смысла не использовать его в качестве ПК. Если вам не нужен guid, то автоинкремент - лучший выбор, но в реальном мире guid находится в db, потому что в большинстве случаев он присущ модели данных (я полагаю) - person Herman Schoenfeld; 28.09.2013