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

У меня есть приложение, которое использует GUID в качестве основного ключа почти во всех таблицах, и я прочитал, что есть проблемы с производительностью при использовании GUID в качестве основного ключа. Честно говоря, я не видел никаких проблем, но я собираюсь запустить новое приложение, и я все еще хочу использовать GUID в качестве основных ключей, но я подумывал использовать Composite Primary Key (GUID и, возможно, другое поле.)

Я использую GUID, потому что они удобны и удобны в управлении, когда у вас есть разные среды, такие как базы данных "production", "test" и "dev", а также для данных миграции между базами данных.

Я буду использовать Entity Framework 4.3, и я хочу назначить Guid в коде приложения, прежде чем вставлять его в базу данных. (т.е. я не хочу, чтобы SQL генерировал Guid).

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

Ответ 1

GUID могут показаться естественным выбором для вашего основного ключа - и, если вы действительно должны, вы, вероятно, можете поспорить, чтобы использовать его для ПЕРВИЧНОГО КЛЮЧА таблицы. То, что я настоятельно рекомендовал не делать, использует столбец GUID как ключ кластеризации, который SQL Server делает по умолчанию, если только вы не указали это не так.

Вам действительно нужно оставить две проблемы:

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

  • ключ кластеризации (столбец или столбцы, определяющие "кластеризованный индекс" в таблице) - это связанная с физическим хранением вещь, а здесь небольшая, все возрастающий тип данных - ваш лучший выбор - INT или BIGINT как ваш вариант по умолчанию.

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

Как Кимберли Трипп - Королева Индексации - и другие заявили много раз - a GUID, поскольку ключ кластеризации isn ' t из-за его случайности, это приведет к массивной фрагментации страниц и индексов и, как правило, к плохой производительности.

Да, я знаю - там newsequentialid() в SQL Server 2005 и выше - но даже это не является поистине и полностью последовательным и, следовательно, также страдает от тех же проблем, что и GUID - чуть менее заметно.

Тогда возникает еще одна проблема: ключ кластеризации в таблице будет добавлен к каждой записи и для каждого некластеризованного индекса в вашей таблице, поэтому вы действительно хотите убедиться, что это как можно меньше, Как правило, INT с 2 + миллиардами строк должно быть достаточным для подавляющего большинства таблиц и по сравнению с GUID в качестве ключа кластеризации вы можете сэкономить сотни мегабайт памяти на диске и в памяти сервера.

Быстрый расчет - используя INT vs. GUID в качестве основного и кластеризованного ключа:

  • Базовая таблица с 1'000'000 строк (3,8 МБ против 15,26 МБ)
  • 6 некластеризованных индексов (22,89 МБ против 91,55 МБ).

ВСЕГО: 25 МБ против 106 МБ - и это только на одной таблице!

Еще немного еды для размышлений - отличный материал от Кимберли Триппа - прочитайте его, прочитайте снова, переваривайте! Это действительно SQL Server индексирование евангелия.

PS: конечно, если вы имеете дело с несколькими сотнями или несколькими тысячами строк - большинство из этих аргументов на самом деле не окажут большого влияния на вас. Однако: если вы попадаете в десятки или сотни тысяч строк или начинаете считать миллионы - , то эти точки становятся очень важными и очень важными для понимания.

Обновление:, если вы хотите, чтобы ваш столбец PKGUID был вашим основным ключом (но не ключом кластеризации) и другим столбцом MYINT (INT IDENTITY) в качестве ключа кластеризации - используйте это:

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

В принципе: вам просто нужно явно указать PRIMARY KEY ограничение, что оно NONCLUSTERED (иначе оно было создано как кластеризованный индекс по умолчанию), - и затем вы создаете второй индекс, который определен как CLUSTERED

Это будет работать - и это действительный вариант, если у вас есть существующая система, которая должна быть "перепроектирована" для производительности. Для новой системы, если вы начинаете с нуля, и у вас нет сценария репликации, я всегда выбираю ID INT IDENTITY(1,1) как мой кластерный первичный ключ - гораздо эффективнее всего!

Ответ 2

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

Это мои настройки для использования GUID:

  1. PK = GUID. Идентификаторы GUID индексируются аналогично строкам, поэтому для таблиц с высокими строками (более 50 миллионов записей) может потребоваться разбиение таблиц или другие методы повышения производительности. SQL Server становится чрезвычайно эффективным, поэтому проблемы с производительностью становятся все менее и менее применимыми.

  2. PK Guid является некластеризованным индексом. Никогда не кластеризируйте индекс GUID, если это не NewSequentialID. Но даже тогда перезагрузка сервера приведет к серьезным перебоям в заказе.

  3. Добавьте ClusterID Int к каждой таблице. Это ваш КЛАСТЕРНЫЙ индекс... который заказывает ваш стол.

  4. Объединение по ClusterID (int) более эффективно, но я работаю с 20-30 миллионами таблиц записей, поэтому объединение по GUID не оказывает заметного влияния на производительность. Если вы хотите максимальной производительности, используйте концепцию ClusterID в качестве основного ключа и присоединитесь к ClusterID.

Вот моя таблица электронной почты...

CREATE TABLE [Core].[Email] (
    [EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,        
    [EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,        
    [CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,      
    [ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NonCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)

Ответ 3

В настоящее время я разрабатываю веб-приложение с EF Core, и вот шаблон, который я использую:

Все мои классы (таблицы) и int PK и FK. У меня есть дополнительный столбец с типом Guid (сгенерированный конструктором С#) с некластеризованным индексом на нем.

Все соединения таблицы внутри EF управляются с помощью ключей int, а весь доступ извне (контроллеры) выполняется с помощью Guids.

Это решение позволяет не отображать int-ключи на URL-адресах, но сохранить модель в порядке и быстро.

Ответ 4

Если вы используете GUID в качестве первичного ключа и создаете кластерный индекс, я предлагаю использовать значение по умолчанию для него NEWSEQUENTIALID()

Ответ 5

Эта ссылка говорит, что это лучше, чем я мог, и помогал в принятии решений. Я обычно выбираю int в качестве первичного ключа, если у меня нет конкретной необходимости, и я также позволю SQL-серверу автоматически генерировать/поддерживать это поле, если у меня нет определенной причины. В действительности, проблемы производительности должны определяться на основе вашего конкретного приложения. Здесь много факторов, включая, но не ограничиваясь ожидаемым размером db, правильной индексацией, эффективными запросами и т.д. Хотя люди могут не согласиться, я думаю, что во многих сценариях вы не заметите разницы с любым вариантом, и вы должны выбрать то, что более подходит для вашего приложения, и что позволяет вам развиваться легче, быстрее и эффективнее (если вы никогда не завершаете приложение какая разница делает остальные:).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

P.S. Я не уверен, почему вы будете использовать Composite PK или какую выгоду вы поверите, что даст вам.

Ответ 6

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

Ответ 7

В большинстве случаев его не следует использовать в качестве первичного ключа для таблицы, поскольку он действительно снижает производительность базы данных. полезные ссылки, касающиеся влияния GUID на производительность и в качестве первичного ключа.

  1. https://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/
  2. https://www.sqlskills.com/blogs/kimberly/guids-as-primary-keys-andor-the-clustering-key/