Композитный первичный ключ
Я работаю над созданием базы данных, которая будет использоваться для хранения данных, которые происходят из нескольких разных источников. Для экземпляров, которые я храню, назначаются уникальные идентификаторы исходными источниками. Каждый экземпляр, который я хранил, должен содержать информацию об источнике, из которого он пришел, вместе с идентификатором, который был связан этим источником.
В качестве примера рассмотрим следующую таблицу, которая иллюстрирует проблему:
----------------------------------------------------------------
| source_id | id_on_source | data |
----------------------------------------------------------------
| 1 | 17600 | ... |
| 1 | 17601 | ... |
| 2 | 1 | ... |
| 3 | 1 | ... |
----------------------------------------------------------------
Обратите внимание, что, хотя id_on_source
уникален для каждого источника, можно найти тот же самый id_on_source
для разных источников.
У меня есть хорошее понимание реляционных баз данных, но далек от эксперта или даже опытного пользователя. Проблема, с которой я сталкиваюсь с этим дизайном, - это то, что я должен использовать в качестве первичного ключа. Кажется, что данные диктуют использование составного первичного ключа (source_id, id_on_source)
. После небольшого поиска в Google я нашел несколько ожесточенных дебатов о плюсах и минусах составных первичных ключей, но я немного смутился.
Таблица будет иметь отношения "один ко многим" с другими таблицами и, таким образом, будет упоминаться в внешних ключах других таблиц.
Я не привязан к конкретному RDBMS
, и я не уверен, имеет ли это значение для аргумента, но позвольте сказать, что я предпочитаю работать с SQLite
и MySQL
.
Каковы плюсы и минусы использования сложного внешнего ключа в этом случае? Что бы вы предпочли?
Ответы
Ответ 1
Я лично считаю составные первичные ключи болезненными. Для каждой таблицы, к которой вы хотите присоединиться к таблице "Источники", вам нужно добавить поле source_id и id_on_source.
Я бы создал стандартный автоматически увеличивающий первичный ключ в вашей таблице источников и добавил уникальный индекс в столбцы source_id и id_on_source.
Это позволяет вам добавить только идентификатор таблицы источников в качестве внешнего ключа в других таблицах.
Как правило, я также нашел поддержку составных первичных ключей во многих средах и инструментах, которые в лучшем случае были "неоднородными" и вообще отсутствовали в других
Ответ 2
Композитные клавиши сложны для управления и медленного соединения. Поскольку вы создаете сводную таблицу, используйте суррогатный ключ (т.е. Столбец автоинкремента/идентификации). Оставьте свои столбцы с естественным ключом.
У этого также много других преимуществ. Прежде всего, если вы слились с компанией, и у них есть один и тот же источник, но с повторными ключами, у вас возникнут проблемы, если вы не используете суррогатный ключ.
Это широко признанная передовая практика в области хранилищ данных (гораздо более масштабное мероприятие, чем то, что вы делаете, но все еще актуальное), и по уважительной причине. Суррогаты обеспечивают целостность данных и быстрые соединения. Вы можете быстро сгореть с помощью естественных клавиш, поэтому держитесь подальше от них как идентификатор и используйте их только в процессе импорта.
Ответ 3
У вас есть бизнес-требование, что комбинация этих двух атрибутов уникальна. Таким образом, для этих двух атрибутов должно быть ограничение UNIQUE
. Вызываете ли вы, что ограничение UNIQUE
"primary" действительно просто предпочтение, оно не имеет большого влияния, кроме документации.
Вопрос только в том, добавляете ли вы дополнительный столбец и отмечаете его UNIQUE
. Единственная причина, по которой я могу это сделать, - это производительность, которая является законной причиной.
Лично мне не нравится подход превращения каждой базы данных в по существу график, где сгенерированные столбцы являются по существу указателями, и вы просто переходите от одного к другому. Я думаю, что это отбрасывает все величие реляционной системы. Если вы отступите и подумаете об этом, вы представляете кучу столбцов, которые не имеют никакого значения для вашего бизнеса. Вы можете быть заинтересованы в моем связанном сообщении в блоге.
Ответ 4
Я считаю, что составные клавиши создают очень естественную и описательную модель данных. Мой опыт исходит от Oracle, и я не думаю, что при создании составной ПК возникают технические проблемы. Фактически, любой, кто анализирует словарь данных, сразу поймет что-то о таблице. В вашем случае было бы очевидно, что каждый источник_ид должен иметь уникальный id_on_source.
Использование естественных ключей часто создает горячие дебаты, но люди, с которыми я работаю, как естественные ключи с хорошей перспективы модели данных.
Ответ 5
В значительной степени единственный раз, когда я использую составной первичный ключ, является то, что старшая часть ключа является ключом к другой таблице. Например, я мог бы создать таблицу OrderLineItem с первичным ключом OrderId + LineNumber. Поскольку многие обращения к таблице OrderLineItem будут "упорядочивать последовательность orderlineitem с использованием (orderid)" или некоторые варианты этого, это часто бывает удобно. Это также облегчает просмотр дампов базы данных, чтобы выяснить, какие позиции связаны с каким порядком.
Как отмечали другие, составные клавиши являются болью в большинстве других обстоятельств, потому что ваши объединения должны включать все части. Это больше похоже на то, что означает больше возможностей для ошибок, запросы медленнее и т.д.
Двусторонние ключи не плохие; Я делаю это довольно часто. Я не хочу использовать ключ из трех частей. Более трех частей, я бы сказал, забудьте об этом.
В вашем примере, я подозреваю, что мало что можно получить, используя составной ключ. Просто придумайте новый порядковый номер и пусть исходный и исходный ключ будут обычными атрибутами.
Ответ 6
У меня возникли проблемы с использованием множества составных клавиш, поэтому я бы не рекомендовал его (более подробно), я также обнаружил, что преимущества в независимом/суррогатном ключе (а не естественном) при попытке опрокинуть обратные ошибки пользователя.
Проблема заключалась в том, что через набор отношений одна таблица объединила две таблицы, где для каждой части строки составной была одинаковой (это было уместно в 3-й нормальной форме - сравнение между двумя частями родителя). Я де-дублировал эту часть составных отношений в таблице соединений (поэтому вместо parent1ID, other1ID, parent2ID, other2ID был parentID, other1ID, other2ID), но теперь отношение не могло обновлять изменения в первичном ключе, поскольку оно пыталось сделать это дважды через каждый маршрут и провалиться посередине.
Ответ 7
Некоторые люди рекомендуют использовать глобально уникальный идентификатор (GUID): репликация слиянием и репликация транзакций с обновлением подписки используют столбцы uniqueidentifier, чтобы гарантировать уникальность идентификаторов строк через несколько копий таблицы. Если значение, если оно уникально, когда оно создано, то вам не нужно добавлять source_id, чтобы сделать его уникальным.
Хотя uniqueid является хорошим первичным ключом, я согласен, что обычно лучше использовать другой, естественный (не обязательно уникальный) ключ в качестве вашего кластерного индекса. Например, если uniqueid является PK, который идентифицирует сотрудников, вы можете захотеть, чтобы кластеризованный индекс был отделом (если ваши операторы выбора обычно извлекают всех сотрудников в рамках данного отдела). Если вы хотите использовать unqiqueid в качестве кластерного индекса, см. Функцию NEWSEQUENTIALID(): это создает последовательные уникальные значения, которые (будучи последовательными ) имеют лучшую производительность кластеризации.
Ответ 8
Добавление дополнительного столбца идентификатора приведет к тому, что вам придется применять два ограничения уникальности вместо одного.
Используя этот дополнительный столбец идентификатора в качестве внешнего ключа в других ссылочных таблицах, вместо ключа, который представляет себя естественным образом, вам придется делать БОЛЬШЕ объединений, а именно во всех случаях, когда вам нужен оригинальный soruce_ID plus ID_on_source вдоль с данными из таблицы ссылок.