SQL: clave primaria de tabla de muchos a muchos

125

Esta pregunta surge después de leer un comentario en esta pregunta:

Diseño de bases de datos

Cuando crea una tabla de muchos a muchos, debe crear una clave primaria compuesta en las dos columnas de clave externa, o crear una clave primaria "ID" sustituta de incremento automático, y simplemente colocar índices en sus dos columnas FK (y tal vez una restricción única)? ¿Cuáles son las implicaciones en el rendimiento para insertar nuevos registros / reindexar en cada caso?

Básicamente, esto:

PartDevice
----------
PartID (PK/FK)
DeviceID (PK/FK)

vs. esto:

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)

El comentarista dice:

hacer que las dos ID sean PK significa que la tabla está físicamente ordenada en el disco en ese orden. Entonces, si insertamos (Parte1 / Dispositivo1), (Parte1 / Dispositivo2), (Parte2 / Dispositivo3), entonces (Parte 1 / Dispositivo3) la base de datos tendrá que separar la tabla e insertar la última entre las entradas 2 y 3. Para muchos registros, esto se vuelve muy problemático ya que implica mezclar cientos, miles o millones de registros cada vez que se agrega uno. Por el contrario, una PK de autoincremento permite que los nuevos registros se agreguen hasta el final.

La razón por la que pregunto es porque siempre me he inclinado a hacer la clave primaria compuesta sin una columna de incremento automático sustituto, pero no estoy seguro de si la clave sustituta es realmente más eficaz.

Andy White
fuente
Aquí hay una pregunta de Silimar publicada en SO: stackoverflow.com/questions/344068/…
Tony
(Intenté agregar esto a mi comentario anterior pero no puedo) Dependiendo de la cantidad de inserciones, también puede reconstruir periódicamente su índice para asegurarse de que arroje resultados rápidamente. En SQL Server también puede ajustar el FILLFACTOR del índice para proporcionar suficiente espacio para las inserciones antes de que tenga que mover los datos.
Tony
1
¿La respuesta a esto no depende de qué DBMS se utiliza? Sospecho que MySQL se comportará de una manera en este caso, SQL-Server ligeramente de otra manera, etc.
Radu Murzea
Advertencia: sin una etiqueta de base de datos específica, gran parte de lo que se dice aquí es sospechoso. ¡Diferentes motores funcionan de manera diferente!
Rick James

Respuestas:

85

Con un mapeo simple de dos columnas de muchos a muchos, no veo ninguna ventaja real de tener una clave sustituta. Tener una clave primaria activada (col1,col2)es única (suponiendo que sus valores col1y col2en las tablas referenciadas sean únicos) y un índice separado (col2,col1)detectará aquellos casos en los que el orden opuesto se ejecutaría más rápido. El sustituto es una pérdida de espacio.

No necesitará índices en las columnas individuales ya que la tabla solo debe usarse para unir las dos tablas referenciadas.

El comentario al que hace referencia en la pregunta no vale los electrones que usa, en mi opinión. Parece que el autor piensa que la tabla está almacenada en una matriz en lugar de una estructura de árbol de múltiples vías equilibrada de rendimiento extremadamente alto.

Para empezar, nunca es necesario almacenar u ordenar la tabla , solo el índice. Y el índice no se almacenará secuencialmente, se almacenará de manera eficiente para poder recuperarlo rápidamente.

Además, la gran mayoría de las tablas de la base de datos se leen con mucha más frecuencia que las escritas. Eso hace que todo lo que haga en el lado de selección sea mucho más relevante que cualquier cosa en el lado de inserción.

paxdiablo
fuente
El último punto no es una buena generalización: "la gran mayoría de las tablas de bases de datos se leen mucho más a menudo que se escriben". Encuentro muchos ejemplos de tablas asociativas que deben escribirse con mucha frecuencia, por ejemplo, una tabla que vincule al cliente con el pedido.
usuario
55
@buffer, mantendré ese comentario (técnicamente, es una generalización solo si digo "todas las tablas", "gran mayoría" se basa en la experiencia). Pensemos también en su ejemplo, un pedido se crea una vez (puede actualizarse ocasionalmente, pero es poco probable que cambie la información clave / índice, más para alcanzar cosas como el estado del pedido. Sin embargo, esas actualizaciones y las selecciones que deberá hacer para imprimir facturas o generar informes de gestión van a
pesar
Piense en Amazon: miles de pedidos creados cada hora.
usuario
9
@buffer, sí, pero de nuevo, cada una de esas órdenes seguramente será consultada muchas veces para hacer (por ejemplo) empaquetado, facturación, actualizaciones de estado, análisis de negocios, etc. El número absoluto de creaciones es menos importante que la relación entre creaciones y lecturas.
paxdiablo
1
Mi punto es insertque importará si se hace miles de veces por hora. No puede simplemente ignorarlo solo porque la relación de inserta selectes <1. En este caso, un cliente se preocupa por cuánto tiempo lleva hacer un pedido.
usuario
19

No se necesita una clave sustituta para las tablas de enlaces.

Una PK activada (col1, col2) y otro índice único activado (col2, col1) es todo lo que necesita

A menos que utilice un ORM que no puede hacer frente y dicta el diseño de su base de datos para usted ...

Editar: Respondí lo mismo aquí: SQL: ¿Necesita una clave primaria incremental automática para las tablas Muchos-Muchos?

gbn
fuente
3
Puede estar bien con un índice dups en col2 en lugar de un índice único en (col2, col1). La ventaja del índice de dos columnas es que permite escaneos de índice solo en col2 solo o en col1 y col2 (aunque el otro índice, en (col1, col2) también maneja el caso 'ambos'). La desventaja es el almacenamiento adicional necesario para la columna adicional. Esto generalmente no es significativo, por lo que el consejo está lejos de ser horrible. Sin embargo, si col1 y col2 son grandes o de tamaños muy diferentes, puede ahorrarse algo de espacio sin perjudicar el rendimiento al elegir tener el segundo índice solo en la columna más corta.
Jonathan Leffler
@gbn: El segundo índice en (col2, col1) no necesita ser único, ¿verdad?
usuario
1
poner un índice único en (col1, col2) después de que ya es un PK es totalmente redundante
Don Cheadle
@mmcrae: ¿dónde estamos haciendo eso?
gbn
2
@mmcrae: Su comentario es "poner un índice único en (col1, col2) ..". El orden de las columnas en un índice es importante. (col2, col1)no es (col1, col2). El PK de (col1, col2)puede no ser adecuado para todas las consultas y generar escaneos, por lo que tener el reverso de eso mejora el rendimiento porque permite búsquedas donde col2 es mejor. Por ejemplo, validación FK cuando la tabla con col2 tiene una eliminación. Se verificará la tabla secundaria de niños
gbn
12

Podría ser necesaria una clave primaria incremental si se hace referencia a la tabla. Puede haber detalles en la tabla de muchos a muchos que debían extraerse de otra tabla utilizando la clave primaria incremental.

por ejemplo

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)
Other Details

Es fácil extraer los 'Otros detalles' usando PartDevice.ID como FK. Por lo tanto, se necesita el uso de la clave primaria incremental.

Jronny
fuente
1
¡Gracias! Llegué a la respuesta mientras buscaba casi el mismo escenario que usted describió. Pero te alejaste de tu primera oración agregando "Otros detalles". ¿Qué sucede si tuviera una tabla de mapeo de muchos a muchos, a la que necesito hacer referencia desde otra tabla? Es decir, la tabla de mapeo de muchos a muchos no ha almacenado ninguna otra información ... ¿Tendría sentido la columna ID adicional de todos modos? Si no, ¿cómo hacer referencia a un registro de la tabla de mapeo en su lugar?
misanthrop
Aquí hay dos opciones: puede usar la clave compuesta como una clave externa de su tabla de referencia (esto agrega una columna adicional a su nueva tabla), o puede crear una columna de identificación en la tabla de mapeo y establecer una restricción única para el compuesto original clave principal, mientras que la nueva columna de identificación se convertirá en la clave principal.
Vočko
6

La forma más corta y directa en que puedo responder a su pregunta es decir que habrá un impacto en el rendimiento si las dos tablas que está vinculando no tienen claves primarias secuenciales. Como indicó / citó, el índice de la tabla de enlaces se fragmentará o el DBMS trabajará más duro para insertar registros si la tabla de enlaces no tiene su propia clave primaria secuencial. Esta es la razón por la cual la mayoría de las personas colocan una clave primaria de incremento secuencial en las tablas de enlaces.

Bernhard Hofmann
fuente
2

Entonces parece que si el ÚNICO trabajo es vincular las dos tablas, la mejor PK sería la PK de doble columna.

Pero si sirve para otros fines, agregue otro NDX como PK con claves foráneas y un segundo índice único.

Index o PK es la mejor manera de asegurarse de que no haya duplicados. PK permite que herramientas como Microsoft Management Studio hagan parte del trabajo (crear vistas) por usted

michael kosak
fuente