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

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

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

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

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

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

HLGEM 03.11.2010 21:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
41
1
35 816
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

Ответ принят как подходящий

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

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

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

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

For example, there is an issue known as a "hotspot", where certain pages of data in a table are under relatively high currency contention. Basically, what happens is most of the traffic on a table (and hence page-level locks) occurs on a small area of the table, towards the end. New records will always go to this hotspot, because IDENTITY is a sequential number generator. These inserts are troublesome because they require Exlusive page lock on the page they are added to (the hotspot). This effectively serializes all inserts to a table thanks to the page locking mechanism. NewID() on the other hand does not suffer from hotspots. Values generated using the NewID() function are only sequential for short bursts of inserts (where the function is being called very quickly, such as during a multi-row insert), which causes the inserted rows to spread randomly throughout the table's data pages instead of all at the end - thus eliminating a hotspot from inserts.

Also, because the inserts are randomly distributed, the chance of page splits is greatly reduced. While a page split here and there isnt too bad, the effects do add up quickly. With IDENTITY, page Fill Factor is pretty useless as a tuning mechanism and might as well be set to 100% - rows will never be inserted in any page but the last one. With NewID(), you can actually make use of Fill Factor as a performance-enabling tool. You can set Fill Factor to a level that approximates estimated volume growth between index rebuilds, and then schedule the rebuilds during off-peak hours using dbcc reindex. This effectively delays the performance hits of page splits until off-peak times.

If you even think you might need to enable replication for the table in question - then you might as well make the PK a uniqueidentifier and flag the guid field as ROWGUIDCOL. Replication will require a uniquely valued guid field with this attribute, and it will add one if none exists. If a suitable field exists, then it will just use the one thats there.

Yet another huge benefit for using GUIDs for PKs is the fact that the value is indeed guaranteed unique - not just among all values generated by this server, but all values generated by all computers - whether it be your db server, web server, app server, or client machine. Pretty much every modern language has the capability of generating a valid guid now - in .NET you can use System.Guid.NewGuid. This is VERY handy when dealing with cached master-detail datasets in particular. You dont have to employ crazy temporary keying schemes just to relate your records together before they are committed. You just fetch a perfectly valid new Guid from the operating system for each new record's permanent key value at the time the record is created.

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

Прочтите GUID в качестве первичного ключа и / или ключа кластеризации и Место на диске дешевое - в этом суть НЕТ! Кимберли Трипп и многие другие ее прекрасные сообщения в блоге - она ​​четко показывает, насколько плоха идея ключа кластеризации в столбце GUID. Кроме того, горячие точки - это миф, который давно развенчан - больше не проблема после SQL Server 6.5 ....

marc_s 05.09.2011 01:08

Очаровательный. Я рассмотрю вариант «разделения страниц и перестроения индекса», если производительность станет проблемой. Спасибо за это.

Matt Hamilton 08.08.2008 10:30

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

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

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

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

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

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

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

Matt Hamilton 08.08.2008 07:16

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

Andrei Rînea 28.09.2008 22:57

@MattHamilton re "... не рекомендуется использовать столбец guid в качестве первичного ключа, потому что первичные ключи сгруппированы, а идентификаторы случайны", чтобы преодолеть это, вы можете использовать функцию "newsequentialid ()" в SQL 2005/2008 edit: нашел необходимый Сообщение CodingHorror, который говорит об этом ;-)

Leon Bambrick 22.08.2008 08:44

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

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

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

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

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

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

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

Роб

Никто не ответил на актуальный вопрос: каковы плюсы / минусы таблицы с NO PK ИЛИ КЛАСТЕРИРОВАННЫМ индексом. На мой взгляд, если вы оптимизируете более быстрые вставки (особенно инкрементную массовую вставку, например, когда вы массово загружаете данные в непустую таблицу), такая таблица: без кластерного индекса, без ограничений, без внешних ключей, без значений по умолчанию и НЕТ Первичный ключ в базе данных с простой моделью восстановления - лучший вариант. Теперь, если вы когда-нибудь захотите запросить эту таблицу (а не сканировать ее полностью), вы можете добавить некластеризованные неуникальные индексы по мере необходимости, но сведите их к минимуму.

На самом деле это неправильный - как ясно показывает Кимберли Трипп (королева индексирования): наличие кластерного индекса хороший приведет к увеличивать производительности INSERT! sqlskills.com/BLOGS/KIMBERLY/post/…

marc_s 05.09.2011 01:05

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

zvolkov 05.09.2011 23:45

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

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