Соотношение «многие ко многим» - дизайн таблицы пересечений - PullRequest
22 голосов
/ 10 июня 2009

Мне интересно, каков лучший дизайн для таблицы пересечений для отношений «многие ко многим».

Два подхода, которые я рассматриваю:

CREATE TABLE SomeIntersection 
(
     IntersectionId UNIQUEIDENTIFIER PRIMARY KEY,
     TableAId UNIQUEIDENTIFIER REFERENCES TableA NOT NULL,
     TableBId UNIQUEIDENTIFIER REFERENCES TableB NOT NULL,
     CONSTRAINT IX_Intersection UNIQUE(TableAId, TableBId )
) 

или

CREATE TABLE SomeIntersection 
(
     TableAId UNIQUEIDENTIFIER REFERENCES TableA NOT NULL,
     TableBId UNIQUEIDENTIFIER REFERENCES TableB NOT NULL,
     PRIMARY KEY(TableAId, TableBId )
) 

Есть ли преимущества одного над другим?
РЕДАКТИРОВАТЬ 2: **** Обратите внимание: Я планирую использовать Entity Framework для предоставления API для базы данных. Имея это в виду, одно решение работает лучше с EF, чем другое?

РЕДАКТИРОВАНИЕ: В связанной заметке для таблицы пересечений, в которой два столбца ссылаются на одну и ту же таблицу (пример ниже), есть ли способ сделать два поля в записи разными?

CREATE TABLE SomeIntersection 
(
     ParentRecord INT REFERENCES TableA NOT NULL,
     ChildRecord INT REFERENCES TableA NOT NULL,
     PRIMARY KEY(TableAId, TableBId )
)

Я хочу предотвратить следующее

ParentRecord          ChildRecord
=================================
      1                    1         --Cyclical reference! 

Ответы [ 11 ]

13 голосов
/ 10 июня 2009

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

Каждую пару месяцев мы встречаемся в нескольких раундах бокса с голыми суставами в баре в Нью-Джерси.

10 голосов
/ 11 июня 2009

Используйте version-1 , если ваше "пересечение" на самом деле является сущностью само по себе, что означает:

  • имеет дополнительные свойства
  • вы можете искать эти объекты (а не перемещаться по отношению)

Пользователь версия-2 , если это чисто таблица отношений N-M. В этом случае также убедитесь, что:

  • у вас есть ваш PK (CLUSTERED) с первым столбцом, относящимся к таблице, которую вы ищете чаще всего: например, если ваши таблицы имеют Персональный адрес, то я предполагаю, что вы будете искать все адреса адресов человек чаще, чем для всех людей по этому адресу. Таким образом, вы должны поставить свой ПК, чтобы сначала включить PersonID
  • у вас все еще может быть другой УНИКАЛЬНЫЙ идентификатор из одной колонки, но просто:

    1. либо не делай это ПК
    2. или сделайте его PK, но укажите NON CLUSTERED, чтобы можно было использовать CLUSTERED для индекса UNIQUE, охватывающего два ссылочных столбца
    3. Если вы не используете GUID в своем дизайне, вы можете придерживаться типа столбца INT IDENTITY

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

9 голосов
/ 10 июня 2009

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

4 голосов
/ 10 июня 2009

Если вы идете первым, просто используйте IDENTITY на ПК, вам не нужно тратить пространство (кэш диска и памяти) на UNIQUEIDENTIFIER.

4 голосов
/ 10 июня 2009

То, что вы строите, называется «Пересечение».

У меня очень ясная память о моем профессоре базы данных в школе, который сказал, что отношения пересечений почти всегда являются самостоятельными объектами, и поэтому обычно стоит выделить для них место как таковое. Это указывало бы на то, что первое более «правильно».

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

3 голосов
/ 11 июня 2009

Отвечая на ваш второй вопрос ...

Вам просто нужно добавить проверочное ограничение, например:

CREATE TABLE SomeIntersection 
(
     ParentRecord INT REFERENCES TableA NOT NULL,
     ChildRecord INT REFERENCES TableA NOT NULL,
     PRIMARY KEY(TableAId, TableBId),
     CHECK (ParentRecord <> ChildRecord)
)
3 голосов
/ 10 июня 2009

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

Правило большого пальца, конечно, но вот, пожалуйста.

3 голосов
/ 10 июня 2009

С точки зрения разработчика, я предпочитаю первое. Проще писать и тестировать, когда имеешь дело с этим.

Мне не нужно проверять наличие двух ключей для получения уникальной записи.

1 голос
/ 10 июня 2009

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

1 голос
/ 10 июня 2009

Преимущества первого:

Возможность поиска таблицы соединений по одному значению. Это упрощает некоторые операции поиска на стороне клиента.

Некоторым ORM (NHibernate) также требуются идентификаторы в каждой сущности, чтобы постоянство работало должным образом.

Преимущества второго:

Более простая модель данных, без необходимости создавать дополнительный индекс.

Требуется меньше памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...