Вопрос

До сих пор я использовал C # "Guid = Guid.NewGuid();" метод для генерации уникального идентификатора, который может быть сохранен в качестве поля ID в некоторых таблицах базы данных моего SQL Server с использованием Linq to SQL.Мне сообщили, что по соображениям индексации использование GUID - плохая идея и что вместо этого я должен использовать автоматически увеличивающийся Long .Ускорит ли использование long транзакции с моей базой данных?Если да, то как мне сгенерировать уникальные идентификаторы типа Long?

С уважением,

Это было полезно?

Решение

У обоих есть плюсы и минусы, это полностью зависит от того, как вы их используете, что имеет значение.

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

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

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

С точки зрения хранения, GUID занимает в два раза больше места, чем Long (8 байт против 16).Однако это зависит от общего размера вашей строки, будет ли 8 байт иметь заметное значение в том, сколько записей помещается в один лист, и, следовательно, количество листов, извлеченных с диска во время среднего запроса.

Другие советы

Значение long (big int в sql server) равно 8 байтам, а Guid - 16 байтам, так что вы вдвое уменьшаете количество байтов, которые sql server должен сравнивать при выполнении поиска.

Для генерации long используйте идентификатор (1,1) при создании поля в базе данных.

итак, либо используя create table, либо alter table:

Field_NAME BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1)

Смотрите комментарии для публикации Linq в sql

"Королева индексирования" - Ким Трипп - в основном, все это говорится в ее постах в блоге indexing:

По сути, ее лучшими практиками являются:оптимальным ключом кластеризации должно быть:

  • уникальный
  • маленький
  • стабильный (никогда не меняющийся)
  • постоянно растущий

Идентификаторы GUID нарушают "малый" и "постоянно увеличивающийся" и, таким образом, не являются оптимальными.

PLUS:все ваши ключи кластеризации будут добавлены к каждой отдельной записи в каждом отдельном некластеризованном индексе (в качестве средства поиска для фактического нахождения записи в базе данных), поэтому вы хотите сделать их как можно меньше (INT = 4 байта по сравнениюGUID = 16 байт).Если у вас сотни миллионов строк и несколько некластеризованных индексов, выбор INT или BIGINT вместо GUID может иметь существенное значение - даже просто с точки зрения пространства.

Марк

Используйте идентификаторы guid, когда вам нужно рассмотреть возможность импорта / экспорта в несколько баз данных.Идентификаторы Guid часто проще в использовании, чем столбцы, указывающие атрибут IDENTITY при работе с набором данных из нескольких дочерних связей.это связано с тем, что вы можете случайным образом генерировать идентификаторы guid в коде в отключенном от базы данных состоянии, а затем отправлять все изменения сразу.Когда идентификаторы guid сгенерированы правильно, их безумно трудно случайно дублировать.При работе со столбцами идентификаторов часто приходится выполнять первоначальную вставку родительской строки и запрашивать ее новый идентификатор перед добавлением дочерних данных.Затем вам необходимо обновить все дочерние записи с новым родительским идентификатором, прежде чем передавать их в базу данных.То же самое касается внуков и так далее по наследству.Это приводит к большому количеству работы, которая кажется ненужной и обыденной.Вы можете сделать что-то похожее на Guid, объединив случайные целые числа без спецификации идентификатора, но вероятность столкновения значительно возрастает по мере того, как вы со временем вставляете больше записей.(Guid.NewGuid() похож на случайный Int128 - который еще не существует).

Я использую Byte (TinyInt), Int16 (SmallInt), Int32 / UInt16 (Int), Int64 / UInt32 (BigInt) для небольших списков поиска, которые не изменяются, или данных, которые не реплицируются между несколькими базами данных.(Разрешения, Конфигурация приложения, названия цветов и т.д.)

Я полагаю, что индексация занимает столько же времени для запроса, независимо от того, используете ли вы guid или long.Обычно в индексируемых таблицах есть другие поля, размер которых в любом случае превышает 128 бит (например, имена пользователей в таблице user).Разница между идентификаторами Guid и целыми числами заключается в размере индекса в памяти, а также во времени заполнения и перестройки индексов.Большинство транзакций базы данных часто выполняется для чтения.Письменность минимальна.Сначала сосредоточьтесь на оптимизации чтения из базы данных, поскольку они обычно состоят из соединенных таблиц, которые не были оптимизированы должным образом, неправильной подкачки по страницам или отсутствующих индексов.

Как и во всем остальном, лучшее, что можно сделать, - это доказать свою точку зрения.создайте тестовую базу данных с двумя таблицами.Один с первичным ключом из целых чисел / длин, а другой с идентификатором guid.Заполните каждую из них N миллионами строк.Отслеживайте производительность каждого из них во время операций CRUD (создание, чтение, обновление, удаление).Вы можете обнаружить, что у него действительно есть снижение производительности, но незначительное.

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

Рассмотрите возможность создания последовательного GUID из .СЕТЕВОЕ приложение:

http://dotnet-snippets.de/dns/sequential-guid-SID998.aspx

Каковы улучшения производительности последовательного Guid по сравнению со стандартным Guid?

Вы можете обсуждать GUID или identity весь день.Я предпочитаю, чтобы база данных генерировала уникальное значение с идентификатором.При объединении данных из нескольких баз данных добавьте еще один столбец (для идентификации исходной базы данных, возможно, tinyint или smallint) и сформируйте составной первичный ключ.

Если вы используете идентификатор, обязательно выберите правильный тип данных, основываясь на количестве ожидаемых ключей, которые вы сгенерируете:

bigint - 8 Bytes - max positive value: 9,223,372,036,854,775,807  
int    - 4 Bytes - max positive value:             2,147,483,647

Примечание. "количество ожидаемых ключей" отличается от количества строк.Если вы в основном добавляете и сохраняете строки, вы можете обнаружить, что одного INT достаточно для более чем 2 миллиардов уникальных ключей.Держу пари, ваш стол не станет таким большим.Однако, если у вас таблица большого объема, в которую вы постоянно добавляете и удаляете строки, количество строк может быть небольшим, но вы будете быстро перебирать ключи.Вам следует произвести некоторые вычисления, чтобы увидеть, сколько времени потребуется для прохождения целых 2 миллиардов ключей.Если он не будет использовать их в ближайшее время, используйте INT, в противном случае удвоьте размер ключа и используйте BIGINT.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top