2009-09-05 7 views
18

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

В качестве примера, рассмотрим следующую таблицу, которая иллюстрирует проблему:

---------------------------------------------------------------- 
| 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.

Каковы преимущества и недостатки использования сложного внешнего ключа в этом случае? Что бы вы предпочли?

ответ

26

Я лично считаю составные первичные ключи болезненными. Для каждой таблицы, к которой вы хотите присоединиться к таблице «Источники», вам необходимо добавить поле source_id и id_on_source.

Я бы создал стандартный автоматически увеличивающий первичный ключ в вашей таблице источников и добавил уникальный индекс в столбцы source_id и id_on_source.

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

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

+0

Подумайте о составной PK для хранения Эры и метки времени (1, 1970 ~ 2106) (2, 2106 ~ 2242). Поскольку INT8, INT16, INT32, INT64 основаны на двоичном и битовом размерах, у нас нет подходящего размера INT за год 9999. INT недостаточно, а BIG INT слишком велик. – Alix

12

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

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

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

+3

О чем вы, собственно, говорите? Если у вас возникли конфликты при слиянии, возможно, вам не нужна ошибка, а не дублирование данных? –

+2

@JeffDavis Точно, суррогатные ключи предлагают избыточность AFAIK. – nottinhill

+0

Можете ли вы объяснить, почему составные клавиши медленно присоединяются? Я пытаюсь понять, почему я не использовал бы составные клавиши. Если у меня есть таблица, которая ссылается на другую с составным ключом (A, B), мне фактически не нужно присоединяться к целому pk. Я мог бы также написать 'ON (a.A = another.A)', правильно? Так что же делает это медленнее? – displayname

1

Некоторые люди рекомендуют использовать глобально уникальный идентификатор (GUID): merge replication and transactional replication with updating subscriptions use uniqueidentifier columns to guarantee that rows are uniquely identified across multiple copies of the table. Если значение, если глобально уникально, когда оно создано, то вам не нужно добавлять source_id, чтобы сделать его уникальным.


Хотя UniqueID хороший первичный ключ, я согласен, что это, как правило, лучше использовать (уникальный не обязательно) ключ другой, естественно, в качестве кластерного индекса. Например, если uniqueid является PK, который идентифицирует сотрудников, вы можете захотеть, чтобы кластеризованный индекс был отделом (если ваши операторы выбора обычно извлекают всех сотрудников в рамках данного отдела). Если вы хотите использовать unqiqueid в качестве кластерного индекса, см. Функцию NEWSEQUENTIALID(): это создает последовательные уникальные значения, которые (будучи последовательными) имеют лучшую производительность кластеризации.

+0

просто будьте осторожны (в SQL Server) ** НЕ **, чтобы сделать ваш основной ключ GUID кластеризованным ключом таблицы (по умолчанию это) - см. Замечательную статью Kim Tripp о том, почему нет: http: // www. sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx –

+0

добавил к моему ответу, чтобы ответить на этот комментарий – ChrisW

+0

Что касается GUID: Если требование состоит только в том, чтобы иметь уникальный id для каждой записи, да, это сработает. Но если вам нужно знать, что такое источник, тогда вам либо придется публиковать исходный идентификатор в записи в любом случае, либо вы должны иметь таблицу поиска где-то в другом месте (yuck), или вам нужно искать все возможные источники, которые ищут этот GUID (двойной yuck). Если вам все равно нужно сохранить исходный идентификатор, GUID не добавляет значения. – Jay

6

Я считаю, что составные клавиши создают очень естественную и описательную модель данных. Мой опыт исходит от Oracle, и я не думаю, что при создании составной ПК возникают технические проблемы. Фактически, любой, кто анализирует словарь данных, сразу поймет что-то о таблице. В вашем случае было бы очевидно, что каждый источник_ид должен иметь уникальный id_on_source.

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

+1

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

+1

сделанный удар. Обычно вы обнаружите, что первичные объекты будут иметь уникальный ключ БД. например Таблица клиентов с CustomerId. Его обычно вторичные связанные таблицы, которые имеют составные ключи, и большинство из них не имеют ссылок FK на них. например если вы храните историю телефонных номеров клиентов, то в таблице Customer_contact_history столбцы CustomerId, phone, changeate могут быть составными PK, поскольку эти 3 вещи являются, естественно, уникальными. – softveda

+0

Я даю вам голосование, потому что я согласен в принципе. Но я не думаю, что это лучшее решение в этом конкретном примере! – Jay

1

Добавление лишнего столбца идентификатора приведет к тому, что вам необходимо обеспечить соблюдение двух ограничений уникальности вместо одного.

Использование этого дополнительного столбца идентификатора в качестве внешнего ключа в других ссылочных таблицах вместо ключа, который представляет себя естественным образом, заставит вас делать БОЛЬШЕ объединений, а именно во всех случаях, когда вам нужен оригинальный soruce_ID plus ID_on_source наряду с данными из таблицы ссылок.

+0

Нужно ли вам применять уникальность в этом приложении? Если вы получаете данные из этих других систем, по-видимому, это их проблема для обеспечения уникальности. Он возвращается к тому, что вам нужно выполнить. – Jay

+0

Что касается дополнительного соединения: я бы сохранил источник и id_on_source в одной таблице, будь то первичный ключ или нет. Я не вижу здесь никакой причины иметь вторую справочную таблицу для перевода. Держите все вместе. – Jay

8

У вас есть бизнес-требование, чтобы комбинация этих двух атрибутов была уникальной. Таким образом, у вас должно быть ограничение UNIQUE на эти два атрибута. Называете ли вы, что ограничение UNIQUE «первичное» действительно просто предпочтение, оно не имеет большого влияния, кроме документации.

Вопрос только в том, добавите ли вы дополнительную колонку и пометьте ее UNIQUE. Единственная причина, по которой я могу это сделать, - это производительность, которая является законной причиной.

Лично мне не нравится подход к превращению каждой базы данных в по существу график, где сгенерированные столбцы являются по существу указателями, и вы просто переходите от одного к другому. Я думаю, что это отбрасывает все величие реляционной системы. Если вы отступите и подумаете об этом, вы представляете кучу столбцов, которые не имеют никакого значения для вашего бизнеса. Возможно, вас заинтересует мой related blog post.

3

Практически единственный раз, когда я использую составной первичный ключ, когда старшая часть ключа является ключом к другой таблице. Например, я мог бы создать таблицу OrderLineItem с первичным ключом OrderId + LineNumber. Поскольку многие обращения к таблице OrderLineItem будут «упорядочивать последовательность orderlineitem с использованием (orderid)» или некоторые варианты этого, это часто бывает удобно. Это также облегчает просмотр дампов базы данных, чтобы выяснить, какие позиции связаны с каким порядком.

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

Ключи из двух частей не плохие; Я делаю это довольно часто. Я не хочу использовать ключ из трех частей. Я бы сказал, что более трех частей забыл об этом.

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

2

У меня возникли проблемы с использованием множества составных клавиш, поэтому я бы не рекомендовал его (более подробно), я также нашел, что там есть преимущества в независимом/суррогатном ключе (а не естественном) при попытке отбросить ошибки пользователя. Проблема заключалась в том, что через набор отношений одна таблица объединила две таблицы, где для каждой части строки составной была одинаковой (это было уместно в 3-й нормальной форме - сравнение между двумя частями родителя). Я де-дублировал эту часть составных отношений в таблице соединений (поэтому вместо parent1ID, other1ID, parent2ID, other2ID был parentID, other1ID, other2ID), но теперь отношение не могло обновлять изменения в первичном ключе, поскольку оно пыталось сделать это дважды по каждому маршруту и ​​провалиться посередине.

Смежные вопросы