Нужны ли в таблицах ссылок бессмысленное поле первичного ключа?
Я работаю над несколькими таблицами ссылок, и я подумал (Danger Will Robinson, Danger), каковы возможные структуры таблицы ссылок и каковы их про и con.
Я придумал несколько возможных ограничений для таблицы ссылок:
Традиционная модель с тремя колонками
- id - автоматический номер PRIMARY
- table1fk - внешний ключ
- table2fk - внешний ключ
Это классика, в большинстве книг, - сказал Нуфф.
Индексированная 3-х столбчатая модель
- id - автоматический номер PRIMARY
- table1fk - внешний ключ
INDEX ('table1fk')
- table2fk - внешний ключ
INDEX ('table2fk')
В моем собственном опыте поля, которые вы запрашиваете, не индексируются в традиционной модели. Я обнаружил, что индексирование полей внешнего ключа повышает производительность, как и следовало ожидать. Не существенное изменение, а хорошая оптимизация.
Составной ключ 2 столбца ADD PRIMARY KEY ('table1fk' , 'table2fk')
- table1fk - внешний ключ
- table2fk - внешний ключ
С этим я использую составной ключ, так что запись из таблицы 1 может быть связана только с записью на таблице2 один раз. Поскольку ключ является составным, я могу добавить записи (1,1), (1,2), (2,2) без ошибок дублирования.
Возможны ли какие-либо потенциальные проблемы с опцией составного ключа 2 столбца? Есть ли проблема с индексацией, которая может возникнуть? Выиграла производительность? Все, что могло бы дисквалифицировать это как возможный вариант?
Ответы
Ответ 1
Для настоящих таблиц ссылок они обычно не существуют как объектные объекты в моих объектных моделях. Таким образом, суррогатный ключ никогда не используется. Съемный элемент из коллекции приводит к удалению элемента из отношения ссылки, где известны оба внешних ключа (Person.Siblings.Remove(Sibling)
или Person.RemoveSibling(Sibling)
, которые соответствующим образом переведены на уровне доступа к данным как usp_Person_RemoveSibling(PersonID, SiblingID)
).
Как отметил Майк, если он станет фактическим объектом в вашей объектной модели, тогда он может заслуживать идентификатор. Однако даже с добавлением временных факторов, таких как эффективные начальные и конечные даты отношений и т.д., Это не всегда ясно. Например, сбор может иметь эффективную дату, связанную с совокупным уровнем, поэтому сама связь все еще не может стать объектом с любыми открытыми свойствами.
Я хотел бы добавить, что вам может понадобиться таблица, индексированная в обоих направлениях в двух столбцах внешнего ключа.
Ответ 2
Я бы использовал составной ключ и лишний бессмысленный ключ.
Я бы не использовал систему ORM, которая применяет такие правила для моей структуры db.
Ответ 3
Если это настоящая таблица соединений "много-ко-многим", то дамп ненужного столбца id (если ваш ORM не требует этого, в этом случае вам нужно решить, будет ли ваш интеллект превзойти вашу практичность).
Но я считаю, что истинные таблицы соединений довольно редки. Обычно это не так давно, прежде чем я захочу поместить некоторые другие данные в эту таблицу. Из-за этого я почти всегда моделирую эти таблицы соединений как объекты с самого начала и вставляю там идентификатор.
Ответ 4
Наличие одного столбца pk может значительно помочь в ситуации аварийного восстановления. Поэтому, хотя теоретически правильно, что вам нужны только 2 внешних ключа. На практике, когда дерьмо попадает в вентилятор, вам может понадобиться один столбец. Я никогда не был в ситуации, когда я был завинчен, потому что у меня был единственный идентификатор столбца, но я был в тех местах, где я был привинчен, потому что я этого не делал.
Ответ 5
Композитный ПК и отключите кластеризацию.
Ответ 6
Я использовал составной ключ для предотвращения повторной записи и позволял базе данных обрабатывать исключение. С помощью одного ключа вы полагаетесь на внешнее приложение для проверки базы данных для дублирования перед добавлением новой записи.
Ответ 7
Я использовал оба варианта, единственное преимущество использования первой модели (с uid) заключается в том, что вы можете переносить идентификатор вокруг как число, тогда как в некоторых случаях вам придется выполнять некоторую конкатенацию строк с помощью составного ключа для транспортируйте его вокруг.
Я согласен, что не индексирование внешних ключей - это плохая идея в зависимости от того, как вы идете.
Ответ 8
Если вы используете ORM для получения/изменения данных, для некоторых из них требуется первичный ключ с одним столбцом (спасибо Tom H за указание на это) для правильной работы (я считаю, что Subsonic 2.x был таким образом, не уверен в 3.x).
По моему мнению, наличие первичного ключа не влияет на производительность до какой-либо измеримой степени, поэтому я обычно использую его.
Ответ 9
I (почти) всегда использует дополнительный первичный ключ с одним столбцом. Это обычно упрощает создание пользовательских интерфейсов, поскольку, когда пользователь выбирает этот конкретный объект привязки, я могу идентифицировать его с единственным целочисленным значением, а не создавать и анализировать составные идентификаторы.
Ответ 10
Если вам нужно пройти таблицу соединений "в обоих направлениях", которая начинается только с ключа table1fk или только таблицы table2fk, вы можете добавить второй, обратный составной индекс.
ADD KEY ('table2fk', 'table1fk')
Ответ 11
Правильный ответ:
- Первичный ключ
('table1fk' , 'table2fk')
- Еще один индекс на
('table2fk' , 'table1fk')
Потому что:
- Вам не нужен индекс только для table1fk или table2fk: оптимизатор будет использовать PK
- Скорее всего, вы будете использовать таблицу "оба" пути
- Добавление суррогатного ключа требуется только из-за ORM braindead
Ответ 12
Есть что-то называемое идентификацией и неидентификацией. При идентификации отношений FK является частью PK во многих таблицах. Например, скажем, что у нас есть таблицы Person
, Company
и таблица many-to-many Employment
. В идентифицирующей связи оба fk PersonID
и CompanyID
являются частью pk, поэтому мы не можем повторять комбинацию PersonID, CompanyID
.
TABLE Employment(PersonID int (PK,FK), CompanyID int (PK,FK))
Теперь предположим, что мы хотим захватить историю занятости, поэтому человек может покинуть компанию, работать где-то в другом месте и позже вернуться в ту же компанию. Здесь связь не идентифицируется, теперь комбинация PersonID, CompanyID
может повторяться, поэтому таблица будет выглядеть примерно так:
TABLE Employment(EmploymentID int (PK), PersonID int (FK), CompanyID int (FK),
FromDate datetime, ToDate datetime)