powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Как правильно реализовать связь "многие-ко-многим"
5 сообщений из 5, страница 1 из 1
Как правильно реализовать связь "многие-ко-многим"
    #35152562
Возникла у меня с коллегами дискурсия на тему, как правильно реализовать связь «многие-ко-многим» в базе данных. Для меня, сомнений нет, но вот коллега настаивает на своём варианте.
Условия задачи:
Есть две таблицы:
CREATE TABLE [dbo].[users](
[userid] [int] IDENTITY(1,1) NOT NULL,
[username] [varchar](50) NOT NULL,
CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED
(
[userid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

И
CREATE TABLE [dbo].[roles](
[roleid] [int] IDENTITY(1,1) NOT NULL,
[rolename] [varchar](50) NOT NULL,
CONSTRAINT [PK_roles] PRIMARY KEY CLUSTERED
(
[roleid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Необходимо реализовать связь «многие-ко-многим» между этими таблицами.

Возможные варианты решения:
1) Стандартный вариант, везде описанный :
CREATE TABLE [dbo].[user_roles](
[userid] [int] NOT NULL,
[roleid] [int] NOT NULL,
CONSTRAINT [PK_user_roles] PRIMARY KEY NONCLUSTERED
(
[userid] ASC,
[roleid] ASC
))

GO
ALTER TABLE [dbo].[user_roles] WITH CHECK ADD CONSTRAINT [FK_role] FOREIGN KEY([roleid])
REFERENCES [dbo].[roles] ([roleid])
GO
ALTER TABLE [dbo].[user_roles] CHECK CONSTRAINT [FK_role]
GO
ALTER TABLE [dbo].[user_roles] WITH CHECK ADD CONSTRAINT [FK_user] FOREIGN KEY([userid])
REFERENCES [dbo].[users] ([userid])
GO
ALTER TABLE [dbo].[user_roles] CHECK CONSTRAINT [FK_user]
GO

2) Вариант предложенный коллегой:
CREATE TABLE [dbo].[user_roles2](
[user_roles_id] [int] IDENTITY(1,1) NOT NULL,
[userid] [int] NOT NULL,
[roleid] [int] NOT NULL,
CONSTRAINT [PK_user_roles2] PRIMARY KEY CLUSTERED
(
[user_roles_id] ASC
))
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_unique_user_roles] ON [dbo].[user_roles2]
(
[userid] ASC,
[roleid] ASC
)
GO

ALTER TABLE [dbo].[user_roles2] WITH CHECK ADD CONSTRAINT [FK_user_roles2_roles] FOREIGN KEY([roleid])
REFERENCES [dbo].[roles] ([roleid])
GO
ALTER TABLE [dbo].[user_roles2] CHECK CONSTRAINT [FK_user_roles2_roles]
GO
ALTER TABLE [dbo].[user_roles2] WITH CHECK ADD CONSTRAINT [FK_user_roles2_user] FOREIGN KEY([userid])
REFERENCES [dbo].[users] ([userid])
GO
ALTER TABLE [dbo].[user_roles2] CHECK CONSTRAINT [FK_user_roles2_user]
GO

Аргумент против второго варианта – дополнительный индекс увеличивает время вставки записей.
Аргументы коллеги за второй вариант:
- я традиционно так делал, и ничего
- при редактировании записей в таблице user_roles2 поле user_roles_id можно использовать в разделе where оператора update .
Уважаемое сообщество, посоветуйте, как лучше убедить коллегу правильно реализовать связь «многие-ко-многим».
...
Рейтинг: 0 / 0
Как правильно реализовать связь "многие-ко-многим"
    #35153650
Фотография adv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Как правильно реализовать связь "многие-ко-многим"
    #35153958
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как правило связи N:M не являются самостоятельной сущностью и у таблицы связи нет дочерних таблиц. В таком случае введение еще одного суррогатного ключа - IDENTITY -- это просто трата места на диске на
само это поле IDENTITY

первичный ключ по нему.

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

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

Резюме: я бы сказал, что надо делать по первому варианту, если не существует очень серьезных причин делать по второму.
...
Рейтинг: 0 / 0
Как правильно реализовать связь "многие-ко-многим"
    #35154552
Фотография Сергей Васкецов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivРезюме: я бы сказал, что надо делать по первому варианту, если не существует очень серьезных причин делать по второму.
Причины появляются, как только возникает, например, необходимость временной блокировки связи, срок действия связи и т. п. (атрибуты именно связи, как Вы и писали). Так что в описанном случае (необходимости именно связи через промежуточную таблицу) лично я бы делал сразу по второму варианту, а не ждал, когда через пару дней/месяцев/лет возникнет необходимость переделывать структуру.
...
Рейтинг: 0 / 0
Как правильно реализовать связь "многие-ко-многим"
    #35154802
RVK61
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Правильный первый вариант. Первичный ключ там ненужен. А как понадобится, несложно его добавить.
С другой стороны, если таблица не огромна, то врятли наличие лишнего поля всерьез скажется на производительности. Но вдруг таблица разрастется, а это поле используется клиентом. Отказаться от него будет уже не так просто.
Предлагаю выбрать первый вариант, пообещав коллеге, как только появятся острая нужда в первичном ключе, его тут же добавить.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Как правильно реализовать связь "многие-ко-многим"
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]