Почему я читаю так много негативных мнений об использовании составных ключей? - PullRequest
13 голосов
/ 18 августа 2010

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

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

Ответы [ 9 ]

12 голосов
/ 18 августа 2010

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

Рассмотрим две таблицы Person и Event, а также множествоотношения между ними, называемые Appointment.

Если у вас есть составной ключ в таблице Person, состоящий из имени, фамилии и даты рождения, а также составной ключ в Event таблица, состоящая из места и имени, в таблице Appointment вы получите пять полей для идентификации отношения.

Условие для привязки отношения будет довольно длинным:

select Person,*, Event.*
from Person, Event, Appointment
where
  Person.FirstName = Appointment.PersonFirstName and
  Person.LastName = Appointment.PersonLastName and
  Person.BirthDate = Appointment.PersonBirthDate and
  Event.Place = Appointment.EventPlace and
  Event.Name = Appointment.EventName`.

Если у вас есть ключи с автонумерацией для таблиц Person и Event, вам понадобятся только два поля в таблице Appointment, чтобы идентифицировать отношение, и условие намного меньше:

select Person,*, Event.*
from Person, Event, Appointment
where
  Person.Id = Appointment.PersonId and Event.Id = Appointment.EventId
7 голосов
/ 18 августа 2010

Если для доступа к вашим данным вы используете только написанное самостоятельно SQL, все в порядке.

Однако для некоторых ORM s, адаптеров и т. Д. Требуется одно поле PK для идентификации.запись.

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

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

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

Это не так вваш случай.

Во-первых, человек может изменить свое имя и даже дату рождения

Во-вторых, я легко могу представить двух John Smiths, рожденных в один и тот же день.

бывшее означает, что если человек меняет свое пAme, вам придется обновить его в каждой таблице, которая ссылается на persons;последнее означает, что второй John Smith не сможет попасть в вашу базу данных.

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

4 голосов
/ 18 августа 2010

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

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

3 голосов
/ 19 августа 2010

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

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

  2. Jet / ACE кластеры на ПК и только на ПК.Это имеет потенциальные недостатки и потенциальные преимущества (например, если вы рассматриваете случайный Autonumber как PK).

  3. По моему опыту, ненулевое требование для составного PK делает большинство естественных ключейневозможно без использования потенциально проблемных значений по умолчанию.Он также разрушает ваш уникальный индекс в Jet / ACE, поэтому в приложении Access (до 2010 года) вы в конечном итоге применяете уникальность в своем приложении.Начиная с A2010, макросы данных на уровне таблицы (которые работают как триггеры) можно использовать для перемещения этой логики в ядро ​​базы данных.

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

  5. Как я упоминал выше, единственные составные ключи вмои приложения находятся в таблицах N: N.Я бы никогда не добавил суррогатный ключ к объединяющей таблице , за исключением в относительно редком случае, когда объединяющая таблица сама является родителем для связанных таблиц (например, запись Person / Company N: N может иметь связанные JobTitlesнесколько рабочих мест в одной компании).Вместо того, чтобы хранить составной ключ в дочерней таблице, вы должны хранить суррогатный ключ.Я бы, скорее всего, не сделал суррогатный ключ PK - я бы оставил составной PK на паре значений FK.Я бы просто добавил Autonumber с уникальным индексом для присоединения к дочерним таблицам.

Я добавлю больше, как я думаю об этом.

3 голосов
/ 18 августа 2010

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

Вот простой пример, использующий общее расположение ученика / класса.

лицо
FirstName
LastName
Адрес

Класс * * 1 010 ИмяКласса
InstructorFirstName
InstructorLastName
InstructorAddress
MeetingTime

StudentClass - таблица присоединения многих ко многим
StudentFirstName
StudentLastName
StudentAddress
ИмяКласса
InstructorFirstName
InstructorLastName
InstructorAddress
MeetingTime

Вы только что перешли от наличия таблицы с несколькими столбцами из 2 столбцов, в которой использовались суррогатные ключи, к таблице из многих столбцов с 8 столбцами, в которой использовались составные ключи, поскольку они имеют внешние ключи из 3 и 5 столбцов. Вы не можете по-настоящему избавиться ни от одного из этих полей, потому что тогда записи не будут уникальными, поскольку и студенты, и преподаватели могут иметь повторяющиеся имена. Черт возьми, если у вас два человека с одним и тем же адресом, у вас все еще серьезные проблемы.

3 голосов
/ 18 августа 2010

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

Преимущество одного столбца "id" (или суррогатного ключа) состоит в том, что он может повысить производительность, сделав более узкий ключ. Поскольку этот ключ может быть перенесен в индексы этой таблицы (в виде указателя на физическую строку из строки индекса) и в другие таблицы в виде столбца FK, это может уменьшить пространство и повысить производительность. Хотя многое зависит от конкретной архитектуры вашей RDBMS. Я не достаточно знаком с Access, чтобы комментировать это, к сожалению.

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

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

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

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

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

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

1 голос
/ 07 сентября 2010

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

Давайте рассмотрим общий пример таблицы, которая имела болееодин ключ-кандидат: таблица Payroll со столбцами employee_number, salary_amount, start_date и end_date.

Ниже приведены четыре ключа-кандидата:

UNIQUE (employee_number, start_date); -- simple constraint 
UNIQUE (employee_number, end_date); -- simple constraint 
UNIQUE (employee_number, start_date, end_date); -- simple constraint 
CHECK (
       NOT EXISTS (
                   SELECT Calendar.day_date
                     FROM Calendar, Payroll AS P1
                    WHERE P1.start_date <= Calendar.day_date
                          AND Calendar.day_date < P1.end_date 
                    GROUP 
                       BY P1.employee_number, Calendar.day_date
                 )
      ); -- sequenced key i.e. no over-lapping periods for the same employee

Требуется применение только одного из этих ключей, т.е. последовательного ключа.Тем не менее, большинство программистов не подумают добавить такой ключ, не говоря уже о том, как его кодировать.На самом деле, я бы поспорил, что большинство кодеров Access добавят в таблицу увеличивающийся столбец автонумерации, сделают столбец автонумерации PRIMARY KEY, не смогут добавить ограничения для любого из ключей-кандидатов и убедятся, что их таблица имеет ключ!

1 голос
/ 18 августа 2010

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

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

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

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

1 голос
/ 18 августа 2010

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

https://stackoverflow.com/search?q=composite+primary+key

...