в общем, должна ли каждая таблица в базе данных иметь поле идентификатора для использования в качестве PK? - PullRequest
43 голосов
/ 30 июля 2009

Это похоже на дубликат, даже когда я его спрашиваю, но я искал и не нашел его. Это кажется хорошим вопросом для SO - хотя я уверен, что смогу найти его во многих блогах и т. Д. ТАК будет больше споров, чем вы можете получить в блоге.

У меня проблема с объединением: получение слишком большого количества записей. Я думаю об этом как о «расширении». Я добавил таблицу к набору объединений, и число строк увеличилось слишком сильно. Обычно, когда это происходит, я добавляю выбор всех полей идентификаторов, которые участвуют в объединении. Таким образом, совершенно очевидно, где происходит расширение, и я могу изменить ON объединения, чтобы исправить это. За исключением этого случая, таблица, которую я добавил, не имеет поля идентификатора. Для меня это проблема. Но, возможно, я ошибаюсь.

Вопрос: должна ли каждая таблица в базе данных иметь поле IDENTITY, которое используется в качестве PK? Есть ли недостатки наличия поля идентификатора в каждой таблице? Что если вы достаточно уверены, что эта таблица никогда не будет использоваться в отношениях PK / FK?

Связано, но не дублировано: Когда иметь столбец идентификаторов не очень хорошая идея?

По-видимому, эта дискуссия

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

Этот пост (суррогатные и натуральные ключи) также актуален.

Ответы [ 10 ]

60 голосов
/ 30 июля 2009

Есть две концепции, которые близки, но их не следует путать: IDENTITY и PRIMARY KEY

Каждая таблица (за исключением редких условий) должна иметь PRIMARY KEY, то есть значение или набор значений, которые однозначно идентифицируют строку.

См. здесь для обсуждения почему.

IDENTITY - это свойство столбца в SQL Server, что означает, что столбец будет автоматически заполняться приращением значений.

Из-за природы этого свойства значения этого столбца по своей природе UNIQUE.

Однако в столбце IDENTITY автоматически не создается ограничение UNIQUE или индекс UNIQUE, и после выдачи SET IDENTITY_INSERT ON можно вставить повторяющиеся значения в столбец IDENTITY, если это не было явным UNIQUE ограничено.

Столбец IDENTITY не обязательно должен быть PRIMARY KEY, но чаще всего он используется для заполнения суррогата PRIMARY KEY s

Это может или не может быть полезно в любом конкретном случае.

Поэтому ответ на ваш вопрос:

Вопрос: должна ли каждая таблица в базе данных иметь поле IDENTITY, которое используется в качестве PK?

это:

Нет. Есть случаи, когда таблица базы данных НЕ должна иметь поле IDENTITY как PRIMARY KEY.

Три случая приходят мне на ум, когда не лучшая идея иметь IDENTITY как PRIMARY KEY:

  • Если ваш PRIMARY KEY составной (как в таблицах ссылок «многие ко многим»)
  • Если ваш PRIMARY KEY натуральный (например, код штата)
  • Если ваш PRIMARY KEY должен быть уникальным для всех баз данных (в этом случае вы используете GUID / UUID / NEWID)

Все эти случаи подразумевают следующее условие:

У вас не должно быть IDENTITY, когда вы заботитесь о значениях вашего PRIMARY KEY и явно вставляете их в свою таблицу.

Обновление:

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

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

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

В этом случае вы просто ссылаетесь на таблицу ссылок по составному ключу.

Этот запрос:

CREATE TABLE a (id, data)
CREATE TABLE b (id, data)
CREATE TABLE ab (a_id, b_id, PRIMARY KEY (a_id, b_id))
CREATE TABLE business_rule (id, a_id, b_id, FOREIGN KEY (a_id, b_id) REFERENCES ab)

SELECT  *
FROM    business_rule br
JOIN    a
ON      a.id = br.a_id

гораздо эффективнее, чем этот:

CREATE TABLE a (id, data)
CREATE TABLE b (id, data)
CREATE TABLE ab (id, a_id, b_id, PRIMARY KEY (id), UNIQUE KEY (a_id, b_id))
CREATE TABLE business_rule (id, ab_id, FOREIGN KEY (ab_id) REFERENCES ab)

SELECT  *
FROM    business_rule br
JOIN    a_to_b ab
ON      br.ab_id = ab.id
JOIN    a
ON      a.id = ab.a_id

, по понятным причинам.

14 голосов
/ 30 июля 2009

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

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

12 голосов
/ 30 июля 2009

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

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

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

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

4 голосов
/ 31 июля 2009

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

Добавление столбца идентификаторов не является бесплатным. При добавлении ненужного столбца идентификаторов в таблицу накладные расходы - как правило, 4 байта на строку хранения для значения идентификатора, плюс целый дополнительный индекс (который, вероятно, будет весить 8-12 байтов на строку плюс накладные расходы). Кроме того, требуется немного более эффективный план запроса, поскольку для каждой таблицы имеется дополнительный индекс. Конечно, если таблица маленькая, а машина большая, эти издержки не критичны - но для самых больших систем это важно.

4 голосов
/ 30 июля 2009

В каждой таблице должен быть набор полей, которые однозначно ее идентифицируют. Будет ли поле числового идентификатора отделено от полей данных, будет зависеть от домена, который вы пытаетесь смоделировать. Не все данные легко попадают в парадигму «единого числового идентификатора», и поэтому нецелесообразно применять их принудительно. Учитывая это, многие данные легко вписываются в эту парадигму и поэтому требуют такой идентификатор. Не существует единого ответа, чтобы всегда делать X в любой среде программирования, и это еще один пример.

3 голосов
/ 30 июля 2009

Если вы смоделировали, спроектировали, нормализовали и т. Д., То у вас не будет столбцов идентификации.

Вы определили естественные и подходящие ключи для своих таблиц.

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

Или из-за идеологии: они обращаются к ОО-разработчикам, которых я нашел.

Хорошо, предположим, столбцы идентификаторов. Когда ваша база данных станет более сложной, скажем, несколько слоев, как вы можете напрямую связываться с таблицами parent и grand-.child. Вы не можете: вам всегда нужны промежуточные таблицы и хорошо проиндексированные столбцы PK-FL. С составным ключом, это все для вас ...

Не поймите меня неправильно: я использую их. Но я знаю, почему я их использую ...

Edit:

Мне было бы интересно сопоставить совпадения «всегда идентификаторы» + «без сохраненных процедур», с одной стороны, с «использовать хранимые процы» + «идентификаторы, когда они приносят пользу», с другой ...

1 голос
/ 30 июля 2009

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

otoh, никакая таблица не нуждается в идентификаторе, и, конечно, не каждая таблица получает выгоду от одного ... Примеры: таблица с коротким и функциональным ключом, таблица, которая не имеет никакой другой таблицы, ссылающейся на нее через чужой Ключ или таблица, находящаяся в отношении «один к нулю или один» с другой таблицей ... ни один из них не нуждается в Идентичности

1 голос
/ 30 июля 2009

Да, для подавляющего большинства случаев.

Крайние случаи или исключения могут быть такими, как:

  • таблицы двустороннего соединения для связи модели m: n
  • временные таблицы, используемые для массовой вставки огромных объемов данных

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

Марк

1 голос
/ 30 июля 2009

Я не могу вспомнить ни одного недостатка наличия поля идентификатора в каждой таблице. Если вы укажете тип поля идентификатора, достаточно места для роста таблицы.

Тем не менее, вам не обязательно иметь одно поле, чтобы гарантировать идентичность ваших строк. Так что нет, поле с одним ID не обязательно .

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

Вы можете прекрасно иметь PRIMARY KEY (fa, fb) на своем столе:

CREATE TABLE t(fa INT , fb INT);
ALTER TABLE t ADD PRIMARY KEY(fa , fb);
0 голосов
/ 30 июля 2009

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

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

Лично я избегаю столбцов IDENTITY (увеличивающихся столбцов идентификаторов, таких как 1, 2, 3, 4), таких как чума. Они вызывают много хлопот, особенно если вы удаляете строки из этой таблицы. Вместо этого я использую сгенерированные уникальные идентификаторы, если в таблице нет естественного ключа.

Во всяком случае, понятия не имею, является ли это принятой практикой, просто мне кажется правильным. YMMV.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...