2009-06-10 14 views
22

Me pregunto qué es un mejor diseño para la tabla de intersección para una relación de muchos a muchos.Diseño de relación de muchos a muchos - Intersection Table Design

Los dos enfoques que estoy considerando son:

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) 
) 

o

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

¿Hay beneficios a uno sobre el otro?
EDIT 2: **** Tenga en cuenta: Planeo usar Entity Framework para proporcionar una API para la base de datos. Con eso en mente, ¿una solución funciona mejor con EF que la otra?

EDIT: En una nota relacionada, para una tabla de intersección que las dos columnas hacen referencia a la misma tabla (ejemplo abajo), ¿hay una manera de hacer que los dos campos se diferencian en un disco?

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

Quiero evitar que el siguiente

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

Para evitar que su ejemplo (que se llama "auto-referencia"), es suficiente para añadir una restricción CHECK en el nivel de tabla " ALTER TABLE dbo.SomethingIntersection ADD CONSTRAINT CHK_SomeIntersection_SelfRefNoNoNo CHECK (ParentRecord <> ChildRecord) " --- Pero no resolverá el caso A-> B-> C-> A de esta manera simple. – van

+0

Me preocupan más las referencias propias que las referencias redondas, ¡gracias! –

Respuesta

9

La segunda versión es la mejor para mí, evita la creación de un índice adicional.

+0

He aceptado esta respuesta ya que funciona mejor con Entity Framework. La tabla de unión/intersección se pliega muy bien en las Entidades generadas en el modelo. –

+1

Necesitarás otro índice en la segunda versión si quieres acceder a la tabla de intersecciones de la Tabla B. –

12

Es un tema de debate. Prefiero el primer formulario porque considero que es mejor poder buscar la fila de asignación en un único valor, y me gusta aplicar una consistencia quizás absurda de tener una clave primaria de columna única disponible en todas las tablas sin falta. Otros piensan que tener esa columna es una pérdida estúpida de espacio.

Nos encontramos en unas cuantas rondas de boxeo desnudo en un bar de Nueva Jersey cada dos meses.

+3

Acepto que una identidad de fila puede ser muy útil, especialmente si alguna vez llega un momento en que necesite una referencia directa a la correlación. +1 para el boxeo bare-nudle, primera regla de DBA Fight Club ... – CAbbott

+2

@ caos @ Bien puesto. Prefiero lo último pero aún así te voté. Minas una cerveza, gracias :) – onedaywhen

+1

Merece la pena señalar Entity framework trata la tabla de interés PK'less de forma diferente que una tabla PK'd – hanzolo

4

Lo que estás construyendo se llama "Intersección".

Tengo un recuerdo muy claro de mi profesor de base de datos en la escuela diciendo que una relación de intersección es casi siempre una entidad en sí misma, por lo que normalmente vale la pena asignar espacio para ello como tal. Esto indicaría que el primero es más "correcto".

Dicho esto, yo personalmente prefiero este último. Realmente se trata de si alguna vez recuperarás uno de estos registros directamente o si solo usarás la tabla cuando te unas a una de las tablas originales.

+0

sacaste un gran punto ... Creo que lo que dijo el profesor tiene sentido para mí. – Sung

3

Desde la perspectiva de un desarrollador, prefiero la primera. Es más fácil escribir y probar al tratar con él.

No necesito comprobar si hay dos claves para recuperar un registro único.

4

si va con la primera, simplemente use una IDENTIDAD en la PK, no necesita perder el espacio (disco y caché de memoria) con UNIQUEIDENTIFIER.

+0

+1: buen punto, KM – van

3

Si no tiene ningún campo adicional en la tabla de intersección, realmente no necesita una identificación propia, y agregar uno no agrega ningún beneficio. Sin embargo, si va a incluir otros campos en esa tabla, y en muchos casos lo hará, debe tener su propia identificación como clave principal.

Regla de oro, por supuesto, pero ahí lo tienes.

+0

¿Por qué debería tener una ID porque se agregaron otras columnas? –

+2

Porque de repente es un artículo en sí mismo y es posible que deba consultarlo fácilmente. Ninguna mesa * requiere * una identificación, es algo útil de tener. Como dije, regla general. –

1

Beneficios de la primera:

La capacidad de buscar la tabla de unión por un solo valor. Esto hace que algunas operaciones de búsqueda sean más simples en el lado del cliente.

Algunos ORM (NHibernate) también requieren identificadores en cada entidad para que la persistencia funcione correctamente.

Beneficios de la segunda:

Más sencillo modelo de datos, sin necesidad de crear el índice adicional.

Requiere menos memoria.

1

El segundo es mejor. Limita la caja de conexiones (cuadro de intersección) a no tener más de una apariencia del mismo par. Si no hay otras columnas en la caja de conexiones, no hará búsquedas de esta tabla de todos modos, excepto por medio de las dos claves externas.

+0

El primero también lo hace "CONSTRAINT IX_Intersection UNIQUE (TableAId, TableBId" –

0

Dado que la combinación TableAId-TableBId es única y que la tabla se utiliza únicamente para implementar una relación de muchos a muchos me gustaría ir con la segunda opción. Desde un punto de vista puramente lógico, la primera aplicación se reduce a la segunda. Desde una perspectiva estructural, sus bases de datos necesitan mantener tanto una clave/índice principal como una restricción en la primera implementación, mientras que en el segundo solo necesita maitainizar la clave/índice principal.

10

Uso versión 1 si su "intersección" en realidad es una entidad por sí misma, es decir:

  • que tiene propiedades adicionales
  • que pueda buscar los objetos (y no navega en una relación)

Usuario versión-2 si es puramente tabla de relaciones NM. En cuyo caso también asegurarse de que:

  • que tienen su PK (CLUSTERED) con la primera columna relativa a la mesa de su búsqueda más a menudo: por ejemplo, si las tablas son persona Dirección, entonces yo supongo que usted buscaría all-addresses-of-a-person más a menudo que para all-people-at-this-address. Por lo que debe poner su PK incluir PersonaID primera
  • todavía puede tener otro de una columna identificador único, pero sólo:

    1. o bien no lo convierten en un PK
    2. o que sea un PK, pero no agrupado especificar, por lo que se puede utilizar para CLUSTERED el índice único que abarca dos columnas de referencia
    3. a menos que utilice GUID por su diseño, podría luego se adhieren a INT tipo de columna IDENTIDAD

En ambos casos, es posible que desee crear otro ÍNDICE que cubra las 2 columnas, pero en otro orden, si busca con frecuencia desde el otro lado de la relación.

3

Respondiendo a su segunda pregunta ...

Sólo tiene que añadir una restricción de comprobación, así:

CREATE TABLE SomeIntersection 
(
    ParentRecord INT REFERENCES TableA NOT NULL, 
    ChildRecord INT REFERENCES TableA NOT NULL, 
    PRIMARY KEY(TableAId, TableBId), 
    CHECK (ParentRecord <> ChildRecord) 
) 
Cuestiones relacionadas