Почему нецелесообразно иметь первичный ключ в объединяемой таблице?

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

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

Почему в этом примере нехорошо иметь первичный ключ?

create_table :categories_posts, :id => false do |t|
  t.column :category_id, :integer, :null => false
  t.column :post_id, :integer, :null => false
end
add_index :categories_posts, :category_id
add_index :categories_posts, :post_id

РЕДАКТИРОВАТЬ: Как я уже говорил Клетусу, я могу понять потенциальную полезность поля автоматического номера в качестве первичного ключа даже для таблицы соединений. Однако в приведенном выше примере автор явно избегает создания поля автоматического нумерации с синтаксисом «: id => false» в операторе «create table». Обычно Rails автоматически добавляет поле идентификатора с автонумерацией в таблицу, созданную при такой миграции, и это становится первичным ключом. Но для этой соединительной таблицы автор специально помешал. Я не был уверен, почему он решил последовать этому подходу.


person pez_dispenser    schedule 19.05.2009    source источник
comment
Редакторам: может быть важно подчеркнуть контекст этого вопроса. Чаще всего НЕ иметь первичный ключ.   -  person Mark Canlas    schedule 19.05.2009
comment
Хорошая статья - это статья Кодда 1970 года sizes.upenn.edu/~zives/ 03f / cis550 / codd.pdf   -  person Matt Rogish    schedule 19.05.2009
comment
Следует учитывать, что эта статья была написана в 1970 году, когда ввод-вывод и хранение данных были относительно намного, намного дороже. Однако в наше время затраты на добавление дополнительного столбца первичного ключа почти всегда минимальны. Мне бы хотелось, чтобы кто-нибудь представил реальный случай, когда лишний столбец создает измеримую проблему.   -  person DGM    schedule 03.01.2018


Ответы (8)


Некоторые примечания:

  1. Комбинация category_id и post_id уникальна сама по себе, поэтому дополнительный столбец идентификатора является избыточным и расточительным.
  2. Фраза «иметь первичный ключ нехорошо» в скринкасте неверна. У вас все еще есть первичный ключ - он просто состоит из двух столбцов (например, CREATE TABLE foo (cid, pid, PRIMARY KEY (cid, pid)). Людям, которые привыкли прибегать к значениям идентификаторов везде, это может показаться странно, но в теории отношений это вполне правильно и естественно; автор скринкаста лучше сказал бы, что «нехорошо иметь неявный целочисленный атрибут с именем« ID »в качестве первичного ключа».
  3. Избыточно иметь дополнительный столбец, потому что вы в любом случае разместите уникальный индекс для комбинации category_id и post_id, чтобы не вставлять повторяющиеся строки.
  4. Наконец, хотя в общей номенклатуре его называют «составным ключом», это также является избыточным. Термин «ключ» в реляционной теории на самом деле представляет собой набор из нуля или более атрибутов, которые однозначно идентифицируют строку, поэтому можно сказать, что первичный ключ - это category_id, post_id.
  5. Поместите САМЫЙ ВЫБОРНЫЙ столбец ПЕРВЫМ в объявление первичного ключа. Обсуждение построения деревьев b (+ / *) выходит за рамки этого ответа (некоторые обсуждения более низкого уровня см .: http://www.akadia.com/services/ora_index_selectivity.html), но в вашем случае вы, вероятно, захотите, чтобы это было в post_id, category_id, поскольку post_id будет отображаться реже в таблицу и тем самым сделать индекс более полезным. Конечно, поскольку таблица настолько мала, а индексом будут, по сути, строки данных, это не очень важно. Это было бы в более широких случаях, когда таблица шире.
person Matt Rogish    schedule 19.05.2009
comment
Это объяснение затронуло все точки нечеткости, на которых я застревал. Спасибо. автор скринкаста лучше сказал бы, что «нехорошо иметь неявный целочисленный атрибут под названием« ID »в качестве первичного ключа» И спасибо за разъяснение этого: лишний столбец лишний, потому что вы поместите уникальный индекс на комбинация category_id и post_id в любом случае, чтобы не вставлять повторяющиеся строки - person pez_dispenser; 19.05.2009
comment
Неверно говорить «ноль» или «больше» (помимо теории базовых множеств) см .: sea.upenn.edu/~zives/03f/cis550/codd.pdf - person Matt Rogish; 19.05.2009
comment
ОК, это нормально в реляционной теории (пустой набор в качестве ключа), но НЕ в SQL - person Matt Rogish; 20.05.2009
comment
Шестая причина заключается в том, что наличие синтетического первичного ключа приведет к (небольшому) снижению производительности при записи в таблицу. Это связано с тем, что вам нужно будет сгенерировать следующий ключ и обновить другой индекс с каждой вставкой в ​​таблицу, но поскольку маловероятно, что вы когда-либо будете ссылаться на синтетический ключ, вы не получите никакого ускорения чтения из-за наличия индекс. Ничего не получить за что-то - плохой компромисс. - person neuronaut; 07.07.2015

Администратор баз данных сказал бы вам, что первичный ключ в этом случае на самом деле является комбинацией двух столбцов FK. Поскольку Rails / ActiveRecord плохо работает с составными PK (по крайней мере, по умолчанию), это может быть причиной.

person Hank Gay    schedule 19.05.2009
comment
Когда вы говорите по умолчанию, вы имеете в виду, что есть способ заставить Rails работать хорошо, но это сложно сделать? - person pez_dispenser; 19.05.2009
comment
совет: взгляните на has_and_belongs_to_many (вместе с has_many_through) blog.hasmanythrough.com/2007/1/15/ - он волшебным образом (вроде как) воспользуется преимуществом объединенной таблицы - person Matt Rogish; 19.05.2009
comment
@po Я слышал, что существуют плагины, которые заставляют AR работать с естественными ключами (включая составные) вместо суррогатных ключей. Не знаю, работают они или нет. - person Hank Gay; 19.05.2009

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

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

person cletus    schedule 19.05.2009
comment
Я понимаю, что вы имеете в виду, говоря о полезности поля автоматического номера в качестве первичного ключа даже для таблицы соединений. Однако в приведенном выше примере автор явно избегает создания поля автоматического нумерации с синтаксисом: id = ›false в операторе создания таблицы. Обычно Rails автоматически добавляет поле идентификатора с автонумерацией в таблицу, созданную при такой миграции, и это становится первичным ключом. Но для этой соединительной таблицы автор специально помешал. Я не был уверен, почему он решил последовать этому подходу. - person pez_dispenser; 19.05.2009

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

Но это просто говорит о том, почему это не хорошая идея ... но почему это должна быть плохая идея?

Учтите, что добавление столбца идентификаторов приведет к дополнительным расходам. Таблица займет на 50% больше дискового пространства. Хуже обстоит дело с индексом. С полем идентификатора вы должны поддерживать счетчик идентификаторов плюс второй индекс. Вы утроите объем дискового пространства и утроите объем работы, который необходимо выполнять с каждой вставкой. Единственное преимущество - это немного более короткое предложение WHERE в команде DELETE.

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

person James Curran    schedule 19.05.2009
comment
Все первичные ключи не являются столбцами идентификации! - person Jonathan Leffler; 19.05.2009
comment
Прости. Я следил за тобой до последнего предложения. Я не понял, что вы имели в виду: с другой стороны, если поля составного ключа представляют собой всю таблицу, то индекс может быть таблицей. - person pez_dispenser; 19.05.2009
comment
Совет: нет никаких преимуществ в добавлении индекса, который равен всей таблице, как если бы ваш первичный ключ был составным ключом, состоящим из каждого столбца в таблице. Когда мы это делаем, таблица служит индексом. Надеюсь, это полезно. Извините, если это не так. - person Lucas Wilson-Richter; 19.05.2009
comment
Некоторые СУБД поддерживают концепцию индексных таблиц. Они полезны, когда, как сказал Джеймс, все столбцы в таблице составляют первичный ключ (например, объединяющая таблица) и когда нет необходимости в индексе для второго столбца (в таблице только для индекса). - person Jonathan Leffler; 19.05.2009

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

Я полагаю, если вы не против того, чтобы ваша база данных была неточной и время от времени предоставляла неверные ответы, тогда вы могли бы обойтись без ... но большинство людей хотят точных ответов от своей СУБД, и для таких людей первичные ключи имеют решающее значение.

person Jonathan Leffler    schedule 19.05.2009
comment
Какие неточные данные первичный ключ предотвратил бы в этой объединенной таблице, состоящей из двух столбцов? Я не сомневаюсь, что вы правы, но я просто не понимаю, какие недействительные данные здесь могут быть. Не могли бы вы привести мне пример? - person pez_dispenser; 19.05.2009
comment
Я имел в виду повторяющиеся строки. Вы также можете найти другие примеры, особенно с обильно разбросанными столбцами идентификаторов и без уникальных ограничений для естественных ключей. Если в таблице есть не только ключевые столбцы, но и другие столбцы, вы действительно можете иметь базу данных, содержащую противоречия, а если вы знакомы с классической логикой, то знаете, что аргументация противоречия приводит к ошибкам. - person Jonathan Leffler; 19.05.2009

Размещение наиболее селективного столбца первым должно иметь значение только в объявлении INDEX. В объявлении KEY это не должно иметь значения (потому что, как было правильно указано, KEY - это SET, а внутри набора порядок не имеет значения - набор {a1, a2} совпадает с набором {a2 , a1}).

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

person Community    schedule 19.05.2009
comment
Большинство, если не все, продукты СУБД, которые я использовал (MySQL, Sybase ASE, SQL Server, Oracle), неявно создают уникальный индекс для объявления PRIMARY KEY в указанном вами порядке. Да, это нарушает логическую / физическую независимость, но это единственный выход (если вы не создаете таблицу без первичного ключа, создаете уникальный индекс, а затем каким-то образом отметите первичный ключ) - person Matt Rogish; 19.05.2009
comment
Кроме того, SQL по определению нарушает ТОННУ реляционной модели, включая: D - person Matt Rogish; 19.05.2009

Я хотел прокомментировать следующий комментарий: «Ноль и более говорить некорректно».

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

Я также хотел прокомментировать, что неправильно говорить «ноль или больше». Теория отношений, широко известная сегодня среди немногих людей, которые все еще пытаются изучить детали этой теории, на самом деле ТРЕБУЕТ возможности ключа без атрибутов.

Но когда я нажал кнопку «комментарий», система ответила мне, что для комментирования требуется оценка репутации 50 (или около того).

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

person Community    schedule 19.05.2009
comment
Я вижу - перечитывая словарь базы данных Date, говорится, что пустой PK используется для ограничения relvar одной строкой. Хорошо, я покупаю это - это не явно указано в письме Кодда, но кроме этого ограниченного граничного случая, когда кто-то будет использовать пустой ключ? - person Matt Rogish; 20.05.2009

Плюсы наличия единого ПК

  • Однозначно идентифицирует строку с одним значением
  • Позволяет при необходимости ссылаться на отношения из других источников.
  • Некоторые инструменты хотят, чтобы у вас было одно целое значение pk

Минусы единого ПК

  • Использует больше места на диске
  • Требуется 3 индекса, а не 1
  • Без уникального ограничения вы можете получить несколько строк для одного и того же отношения.

Примечания

  • Вам необходимо определить уникальное ограничение, если вы хотите избежать дублирования
  • На мой взгляд, не используйте один pk, если ваша таблица будет огромной, иначе уступите место на диске для удобства. Да, это расточительно, но кого волнуют несколько МБ на диске в реальных приложениях.
person RichH    schedule 19.05.2009
comment
Требуется 3 индекса, а не 1 - я предполагаю, что вы имеете в виду первичный ключ в поле автоматического номера плюс два других индекса в моем примере выше (а не два дополнительных индекса, не перечисленных в моем примере). Без уникального ограничения вы можете получить несколько строк для одного и того же отношения - ›Таким образом, в этом случае PK должен будет ссылаться на два столбца в этой объединенной таблице. Другими словами, первичный ключ, который просто состоит из поля автоматического номера, не будет работать. Надеюсь, я понимаю. - person pez_dispenser; 19.05.2009