¿Se necesita una columna de identificación única en una tabla de muchos a muchos (unión)?

22

Comencé algunos proyectos con EF, pero tenía algunas preguntas sobre unir tablas y claves, etc. Digamos que tengo una tabla de aplicaciones y una tabla de permisos. Las aplicaciones tienen muchos permisos y cada permiso puede pertenecer a muchas aplicaciones (muchas a muchas).

Ahora, las tablas de Solicitud y Permisos son fáciles:

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

Pero, ¿cuál es la MEJOR forma de hacer la mesa de unión? Tengo estas dos opciones:

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

O

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

¿Alguna vez te has quemado haciéndolo de un lado a otro? ¿Es estrictamente preferencia? Se me ha ocurrido que muchas de las "diferencias" serán eliminadas por mi patrón de repositorio (por ejemplo, casi nunca crearía un objeto de permiso completo y lo agregaría a una aplicación, sino que lo haría por ID o nombre único o algo), pero creo que estoy buscando historias de terror, de una forma u otra.

solidau
fuente

Respuestas:

20

Creo que te refieres a la tabla de "unión", no a la tabla de "unión".

No es necesario que una tabla de unión tenga su propio campo ID. Nunca necesitaría unirse o filtrar en una identificación de este tipo. Solo se uniría o filtraría en los ID de las tablas que está mapeando. Una identificación en una tabla de unión es una pérdida de espacio en disco.

Entonces, la "mejor" opción es evitar la identificación. Por lo general, una tabla de unión tendrá 2 índices de cobertura. Cada índice de cobertura utiliza una de las ID asignadas como el campo de clasificación principal.

Pero "lo mejor" no es una posibilidad remota. Es un problema muy pequeño tener un campo de identificación redundante. No tendrás historias de terror sobre una pequeña cantidad de disco desperdiciado. El ID no "robará" el índice agrupado porque no desea agrupar en el combo asignado de todos modos.

Si su marco quiere que todas las tablas tengan una ID, entonces hágalo. Si los estándares de la base de datos de su equipo dictan que todas las tablas deben tener una ID, entonces hágalo. Si no, entonces evítalo.

mike30
fuente
2
Bueno, usted ya dijo que agregar una ID es una concesión menor, fácilmente superada por los beneficios potenciales, por lo que me parece que (dado que tener una ID única en cada tabla es más o menos la mejor práctica en la mayoría de los DBMS y ORM) recomendaría tener una ID como la "mejor" o la "opción predeterminada", en lugar de no tenerla.
Robert Harvey
44
"Nunca necesitarías unirte o consultar sobre una identificación de este tipo", decir "nunca" en una situación tecnológica invita a que eso suceda. Dicho esto, no son momentos en los que se unirá que se unen a la mesa (sí, he oído que se hace referencia como "unir" mesa de más de una tabla de "unión") a todavía una cuarta mesa porque las entidades unidas son, de hecho, una objeto de negocio propio.
Jesse C. Slicer el
44
@RobertHarvey. Una identificación es una buena práctica para las entidades. Pero una unión es más un detalle de implementación para muchas relaciones, no una entidad en sí misma. Pero como señala el control deslizante Jesse C., hay casos en los que un cruce podría considerarse una entidad comercial.
mike30
1
"pérdida de espacio en disco". - Creo que algunos motores (¿InnoDB?) Crean una clave primaria (interna) de todos modos si no la crea usted mismo, por lo que es posible que no gane espacio en el disco al no tenerla.
Alex
@Alex. Pones un PK compuesto en las ID asignadas.
mike30
11

A lo largo de los años, adquirí el hábito de dar a cada tabla "TableName" una clave primaria autogenerada "TableNameID", sin excepciones, ni siquiera para las tablas de unión. Puedo decir que nunca me arrepentí, porque hace muchas cosas más fáciles al crear código genérico que hace algo para "todas las tablas" o "algunas tablas", o para "muchas filas de varias tablas diferentes".

Por ejemplo, si alguien le pide que almacene algunas filas de tablas diferentes (o referencias a ellas) en un archivo o en la memoria, por ejemplo, para fines de registro, es muy útil cuando sabe de antemano que solo necesita almacenar exactamente una nombre de la tabla y exactamente un ID entero, y no tiene que lidiar con ningún "caso especial".

Otra cosa, cuando comienza con PK combinados, probablemente algunas veces más tarde se encontrará con la necesidad de claves foráneas combinadas (ya que puede llegar a un punto en el que desea agregar una referencia FK a su ApplicationPermissionstabla). Entonces, el siguiente requisito puede ser que este FK sea único junto con otros atributos o claves foráneas, lo que resultará en una mayor complejidad en general. Nada que no sea posible manejar para la mayoría de los sistemas de DB modernos, por supuesto, pero una solución uniforme facilita mucho la vida de los programadores.

Y finalmente, una declaración como SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)funciona bien con una sola columna como clave principal, pero nunca he visto un dialecto SQL hasta ahora que le permita hacer esto con teclas combinadas. Si sabe de antemano que nunca necesitará una consulta como esta, está bien, pero no se sorprenda si mañana obtiene un requisito que se resolverá más fácilmente con este tipo de SQL.

Por supuesto, cuando espera que su ApplicationPermissionstabla contenga varios cientos de millones de filas, debe considerar evitar algo como a ApplicationPermissionsID.

Doc Brown
fuente
Aunque no terminé eligiendo tu respuesta. Me gustan aspectos de ello. Gracias por tus pensamientos (voto positivo).
solidau
6

Si bien la respuesta de Mike es buena, estas son las razones por las que agregaría un campo de ID por separado o no.

  1. Considere utilizar un campo de ID separado para la tabla de unión / unión si contiene campos distintos al ID . Esto tiende a notar que es una entidad de primera clase.

  2. Considere usar un campo de ID separado si las API o cualquier lógica existente tienden a usar campos únicos para recuperar / editar entidades. Eso puede ayudar a otras personas a seguir su código en el contexto de un proyecto más grande.

  3. No lo use si no hay un beneficio específico (KISS). EF sabe cómo manejar este tipo de tabla y a veces se puede pasar por alto una restricción única compuesta cuando otras personas intentan comprender este tipo de relación. Además, al normalizar, trato de usar la clave más pequeña posible que define de forma única la tupla . En su segundo ejemplo, efectivamente tiene 2 claves principales candidatas separadas.

Zachary Yates
fuente
-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

Recuerde crear un índice y una clave externa en ambos PersonIdy AddressId.

No importa lo que otros piensen que es "mejor" o "debería", esta es la forma más simple y fácil de permitir que la base de datos funcione correctamente.

16PlusYearsAsADeveloper
fuente
1
Creo que hay un problema con este enfoque es el esquema permite que dos PersonAddressfilas con idéntica PersonIdy AddressIdvalores.
Sam