Таблицы без первичного ключа

У меня есть несколько таблиц, единственными уникальными данными которых является столбец uniqueidentifier (Guid). Поскольку направляющие не являются последовательными (и они генерируются на стороне клиента, поэтому я не могу использовать newsequentialid ()), я создал не первичный некластеризованный индекс для этого поля идентификатора вместо того, чтобы давать таблицам кластеризованный первичный ключ.

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

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

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

8.08.2008 02:47:15
Так как вы делаете репликацию, ваши правильные личности - это то, что нужно избегать. Я бы сделал ваш GUID первичным ключом, но не кластеризованным, поскольку вы не можете использовать newsequentialid. Это поражает меня как ваш лучший курс. Если вы не сделаете его PK, а поместите в него уникальный индекс, рано или поздно это может привести к тому, что люди, которые поддерживают систему, не будут правильно понимать отношения FK, вводя ошибки.
HLGEM 3.11.2010 18:20:12
7 ОТВЕТОВ
РЕШЕНИЕ

При работе с индексами вы должны определить, для чего будет использоваться ваша таблица. Если вы в первую очередь вставляете 1000 строк в секунду и не выполняете никаких запросов, то кластеризованный индекс снижает производительность. Если вы выполняете 1000 запросов в секунду, отсутствие индекса приведет к очень низкой производительности. При настройке запросов / индексов лучше всего использовать анализатор плана запросов и SQL Profiler в SQL Server. Это покажет вам, где вы работаете с дорогостоящими сканированиями таблиц или другими блокировщиками производительности.

Что касается аргумента GUID vs ID, вы можете найти людей онлайн, которые клянутся обоими. Меня всегда учили использовать GUID, если у меня нет веских причин не делать этого. У Джеффа есть хороший пост, в котором рассказывается о причинах использования идентификаторов GUID: https://blog.codinghorror.com/primary-keys-ids-versus-guids/ .

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

[Редактировать] @Matt, после более подробного изучения дебатов по GUID / ID, я наткнулся на этот пост. Как я уже упоминал ранее, нет правильного или неправильного ответа. Это зависит от ваших конкретных потребностей реализации. Но вот несколько довольно веских причин использовать GUID в качестве первичного ключа:

Например, существует проблема, известная как «горячая точка», когда определенные страницы данных в таблице находятся в состоянии относительно высокой конкуренции за валюту. По сути, происходит то, что большая часть трафика в таблице (и, следовательно, блокировки на уровне страниц) происходит в небольшой области таблицы, ближе к концу. Новые записи всегда будут поступать в эту точку доступа, потому что IDENTITY - это генератор последовательных чисел. Эти вставки являются проблематичными, потому что они требуют исключительной блокировки страницы на странице, к которой они добавлены (точка доступа). Это эффективно сериализует все вставки в таблицу благодаря механизму блокировки страниц. NewID (), с другой стороны, не страдает от горячих точек. Значения, созданные с помощью функции NewID (), являются последовательными только для коротких пакетов вставок (когда функция вызывается очень быстро, например, во время многострочной вставки),

Кроме того, поскольку вставки распределяются случайным образом, вероятность разделения страниц значительно снижается. Хотя страница разделена здесь и там не так уж и плохо, эффекты быстро складываются. С IDENTITY, коэффициент заполнения страницы довольно бесполезен в качестве механизма настройки и может также быть установлен на 100% - строки никогда не будут вставлены ни на одну страницу, кроме последней. С помощью NewID () вы можете использовать Fill Factor в качестве инструмента повышения производительности. Вы можете установить коэффициент заполнения на уровень, который приблизительно соответствует ожидаемому росту объема между перестройками индекса, а затем запланировать перестройки в непиковые часы с помощью переиндексации dbcc. Это эффективно задерживает скачки производительности при разделении страниц до непикового времени.

Если вы даже думаете, что вам может потребоваться включить репликацию для рассматриваемой таблицы, то вы также можете сделать PK уникальным идентификатором и пометить поле guid как ROWGUIDCOL. Для репликации потребуется уникальное поле guid с этим атрибутом, и оно будет добавлено, если оно не существует. Если подходящее поле существует, то оно будет просто использовать то, что там.

Еще одним огромным преимуществом использования GUID для PK является тот факт, что значение действительно гарантированно уникально - не только среди всех значений, сгенерированных этим сервером, но и всех значений, сгенерированных всеми компьютерами - будь то ваш db-сервер, веб-сервер, сервер приложений или клиентский компьютер. Практически каждый современный язык имеет возможность генерировать действительный guid - в .NET вы можете использовать System.Guid.NewGuid. Это ОЧЕНЬ удобно, когда речь идет, в частности, о кешированных наборах основных данных. Вам не нужно использовать сумасшедшие схемы временных ключей, чтобы связать ваши записи вместе, прежде чем они будут зафиксированы. Вы просто выбираете совершенно правильный новый Guid из операционной системы для значения постоянного ключа каждой новой записи во время ее создания.

http://forums.asp.net/t/264350.aspx

33
21.10.2018 06:16:54
Захватывающий. Я посмотрю на опцию «разбиение страниц и перестроение индекса», если производительность становится проблемой. Спасибо за это.
Matt Hamilton 8.08.2008 06:30:42
Прочитайте GUID Кимберли Триппа как Первичный и / или ключ кластеризации, а дисковое пространство дешево - это НЕ главное! и еще много ее превосходных постов в блоге - она ясно показывает, насколько плоха идея кластеризованного ключа в столбце GUID. Кроме того - горячие точки - это миф, который давно развенчан - больше не проблема в любое время после SQL Server 6.5 ....
marc_s 4.09.2011 21:08:33

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

0
8.08.2008 03:00:36

Первичный ключ служит трем целям:

  • указывает на то, что столбцы должны быть уникальными
  • указывает на то, что столбцы должны быть ненулевыми
  • задокументировать намерение, что это уникальный идентификатор строки

Первые два можно указать разными способами, как вы уже сделали.

Третья причина хороша:

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

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

7
8.08.2008 03:04:55
Определенно не очень хорошая идея иметь столбец guid в качестве первичного ключа, потому что первичные ключи кластеризованы, а guids случайны. Это означает, что каждый раз, когда вы вставляете новую строку, ваша таблица по существу реструктурируется на диске. Люди обычно советуют, чтобы первичные ключи были последовательными, постоянно растущими типами, чтобы каждая новая строка была прикреплена к концу таблицы.
Matt Hamilton 8.08.2008 03:16:17
@MattHamilton re "... не очень хорошая идея иметь столбец guid в качестве первичного ключа, потому что первичные ключи кластеризованы, а guid являются случайными", чтобы преодолеть это, вы можете использовать функцию "newsequentialid ()" в SQL 2005/2008 редактировать: нашел нужный пост CodingHorror, в котором говорится об этом ;-)
Leon Bambrick 22.08.2008 04:44:53
Первичный ключ по умолчанию поддерживается кластеризованным индексом, но его можно удалить (кластеризованный индекс).
Andrei Rînea 28.09.2008 18:57:48

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

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

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

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

0
8.08.2008 06:25:50

Просто прыгаю, потому что Мэтт немного меня травил.

Необходимо понимать, что хотя кластерный индекс по умолчанию помещается в первичный ключ таблицы, эти две концепции являются отдельными и должны рассматриваться отдельно. CIX указывает способ хранения данных и обращения к ним в NCIX, в то время как PK обеспечивает уникальность каждой строки, чтобы удовлетворить ЛОГИЧЕСКИЕ требования таблицы.

Таблица без CIX - это просто куча. Стол без ПК часто считается «не столом». Лучше всего разбираться в понятиях PK и CIX по отдельности, чтобы принимать разумные решения при проектировании баз данных.

обкрадывать

7
5.08.2009 04:51:00

Никто не ответил на актуальный вопрос: каковы плюсы / минусы таблицы с NO PK, NOR и CLUSTERED. На мой взгляд, если вы оптимизируете для более быстрых вставок (особенно для инкрементальной массовой вставки, например, когда вы загружаете данные в непустую таблицу), такая таблица: без кластеризованного индекса, без ограничений, без внешних ключей, без значений по умолчанию и НЕТ Первичный ключ, в базе данных с простой моделью восстановления, является лучшим. Теперь, если вы когда-нибудь захотите запросить эту таблицу (а не сканировать ее полностью), вы можете добавить некластеризованные неуникальные индексы по мере необходимости, но сведите их к минимуму.

3
19.03.2010 18:17:12
На самом деле, это неправильно - как ясно показывает Кимберли Трипп (Королева индексирования): хороший кластерный индекс увеличит производительность INSERT! sqlskills.com/BLOGS/KIMBERLY/post/...
marc_s 4.09.2011 21:05:23
Я бы не назвал это отчетливым показом :) Она говорит об общих принципах, не подкрепляя свое заявление чем-то, ну, а я говорю об очень специфическом сценарии, с которым я столкнулся в своей практике: массовые вставки потенциально сотен миллионы записей в непустую таблицу, которая затем никогда не обновляется и не доступна в режиме произвольного чтения, а только сканируется полностью. Я полагаю, что в игре может быть больше факторов, чем индексов. Всегда проверяйте ваши оптимизации детей.
zvolkov 5.09.2011 19:45:14

Так как вы делаете репликацию, ваши правильные личности - это то, что нужно избегать. Я бы сделал ваш GUID первичным ключом, но не кластеризованным, поскольку вы не можете использовать newsequentialid. Это поражает меня как ваш лучший курс. Если вы не сделаете его PK, а поместите в него уникальный индекс, рано или поздно это может привести к тому, что люди, которые поддерживают систему, не будут правильно понимать отношения FK, вводя ошибки.

0
3.11.2010 18:20:12