|
|
|
Как правильно реализовать связь "многие-ко-многим"
|
|||
|---|---|---|---|
|
#18+
Возникла у меня с коллегами дискурсия на тему, как правильно реализовать связь «многие-ко-многим» в базе данных. Для меня, сомнений нет, но вот коллега настаивает на своём варианте. Условия задачи: Есть две таблицы: 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 . Уважаемое сообщество, посоветуйте, как лучше убедить коллегу правильно реализовать связь «многие-ко-многим». ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.02.2008, 17:07 |
|
||
|
Как правильно реализовать связь "многие-ко-многим"
|
|||
|---|---|---|---|
|
#18+
http://www.sql.ru/forum/actualsearch.aspx?search=%F1%F3%F0%F0%EE%E3%E0%F2%ED%FB%E5+vs&sin=0&a=&ma=0&bid=36&dt=-1&s=1&so=1 можно без vs http://www.ibase.ru/devinfo/NaturalKeysVersusAtrificialKeysByTentser.html ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2008, 16:56 |
|
||
|
Как правильно реализовать связь "многие-ко-многим"
|
|||
|---|---|---|---|
|
#18+
Как правило связи N:M не являются самостоятельной сущностью и у таблицы связи нет дочерних таблиц. В таком случае введение еще одного суррогатного ключа - IDENTITY -- это просто трата места на диске на само это поле IDENTITY первичный ключ по нему. В данном случае таблица разрослась примерно в 1.5 раза, и совершенно без каких-то преимуществ. В запросах, если будет доступ через эту таблицу к другим (ее родителям) в случае лишнего суррогата и указания его PK на входе нужно будет делать доп. чтения реальных данных из таблицы связи, а в первом варианте можно этого не делать (на самом деле это - стандартный недостаток суррогатных ключей). Но ошибкой второй пример не является, говоря строго, хотя доводы типа "я всегда так делал" конечно не повод так делать (в смысле - надо иногда и думать, а не только делать). Участие же полей PK в запросах изменения таблиц можно и нужно делать всегда, в любом из двух вариантов. Возможны другие доводы "за" второй вариант, типа методологические соглашения по построению всех таблиц для того, чтобы клиентское ПО например с ними как-то унифицированно работало (т.е. по-другому клиент просто не сможет с таблицей работать), но я бы в таком случае первым делом задумался над тем, насколько хорошо написан клиент. Резюме: я бы сказал, что надо делать по первому варианту, если не существует очень серьезных причин делать по второму. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2008, 19:53 |
|
||
|
Как правильно реализовать связь "многие-ко-многим"
|
|||
|---|---|---|---|
|
#18+
MasterZivРезюме: я бы сказал, что надо делать по первому варианту, если не существует очень серьезных причин делать по второму. Причины появляются, как только возникает, например, необходимость временной блокировки связи, срок действия связи и т. п. (атрибуты именно связи, как Вы и писали). Так что в описанном случае (необходимости именно связи через промежуточную таблицу) лично я бы делал сразу по второму варианту, а не ждал, когда через пару дней/месяцев/лет возникнет необходимость переделывать структуру. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2008, 10:35 |
|
||
|
Как правильно реализовать связь "многие-ко-многим"
|
|||
|---|---|---|---|
|
#18+
Правильный первый вариант. Первичный ключ там ненужен. А как понадобится, несложно его добавить. С другой стороны, если таблица не огромна, то врятли наличие лишнего поля всерьез скажется на производительности. Но вдруг таблица разрастется, а это поле используется клиентом. Отказаться от него будет уже не так просто. Предлагаю выбрать первый вариант, пообещав коллеге, как только появятся острая нужда в первичном ключе, его тут же добавить. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2008, 11:46 |
|
||
|
|

start [/forum/topic.php?fid=32&fpage=107&tid=1544008]: |
0ms |
get settings: |
9ms |
get forum list: |
21ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
63ms |
get topic data: |
10ms |
get forum data: |
3ms |
get page messages: |
54ms |
get tp. blocked users: |
1ms |
| others: | 231ms |
| total: | 400ms |

| 0 / 0 |
