claves primarias compuestas es una mala práctica? [cerrado]


14

Quiero saber si las claves primarias compuestas son una mala práctica y, de no ser así, en qué escenarios es recomendable usar.

Mi pregunta está basada en este artículo.

errores de diseño de bases de datos

La parte sobre las claves primarias compuestas:

Mala práctica No. 6: claves primarias compuestas

Este es un punto controvertido, ya que muchos diseñadores de bases de datos hablan hoy en día sobre el uso de un campo autogenerado de ID de entero como la clave principal en lugar de uno compuesto definido por la combinación de dos o más campos. Actualmente se define como la "mejor práctica" y, personalmente, tiendo a estar de acuerdo con ella.

Imagen de una clave primaria compuesta

Sin embargo, esto es solo una convención y, por supuesto, los DBE permiten la definición de claves primarias compuestas, que muchos diseñadores piensan que son inevitables. Por lo tanto, al igual que con la redundancia, las claves primarias compuestas son una decisión de diseño.

Sin embargo, tenga cuidado, si se espera que su tabla con una clave primaria compuesta tenga millones de filas, el índice que controla la clave compuesta puede crecer hasta un punto donde el rendimiento de la operación CRUD se degrada mucho. En ese caso, es mucho mejor usar una clave primaria de ID de entero simple cuyo índice sea lo suficientemente compacto y establezca las restricciones DBE necesarias para mantener la unicidad.


44
Esta no es una práctica "buena" o "mala". Cada decisión de diseño debe cumplir un propósito; Si puede explicar (a usted mismo y a otros) por qué necesita un PK compuesto, está listo para comenzar. Por el contrario, si puede explicar por qué no lo necesita, también puede hacerlo. El artículo al que enlaza hace un trabajo muy pobre explicando, en mi opinión.
mustaccio

Este artículo señala un punto, pero si buscamos marcos populares (como los rieles, por ejemplo) en sus "mejores prácticas" no es compatible con este tipo de claves primarias, entonces pregunté por qué. Es por dificultades técnicas o algo más.
hackvan

Es más fácil para los diseños de marco admitir claves primarias enteras de columna simple "simples". Y dado que la mayoría de los desarrolladores (al menos en mi experiencia personal) no tienen mucho en términos de habilidades de base de datos (al menos en relación con los usuarios de este sitio), funciona lo suficientemente bien para la mayoría de los usuarios del software. Como la mayoría de los usuarios del software no necesitan claves compuestas (o no creen que las necesiten, al menos al inicio), pueden salirse con la suya al no proporcionar (buen) soporte para claves compuestas.
Willem Renzema

1
¿Cómo es un GUID mejor que un INTEGER [Serie | Auto_Increment | Identidad | <whatever_integer_you_like>]?
Vérace

44
No contrataría a ese autor
paparazzo

Respuestas:


31

¡Decir que el uso de "Composite keys as PRIMARY KEY is bad practice"es un completo disparate!

¡Los compuestos a PRIMARY KEYmenudo son algo muy "bueno" y la única forma de modelar situaciones naturales que ocurren en la vida cotidiana!

¡Piense en el clásico ejemplo de enseñanza Databases-101 de estudiantes y cursos y en los muchos cursos tomados por muchos estudiantes!

Crear mesas curso y alumno:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Le daré el ejemplo en el dialecto PostgreSQL (y MySQL ): debería funcionar para cualquier servidor con un poco de ajuste.

Ahora, es obvio que desee realizar un seguimiento de las cuales estudiante está tomando el cual por supuesto - por lo que tiene lo que se llama joining table(también llamados linking, many-to-manyo m-to-ntablas). ¡También se conocen como associative entitiesen jerga más técnica!

1 curso puede tener muchos estudiantes.
1 estudiante puede tomar muchos cursos.

Entonces, creas una tabla de unión

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Ahora, la única manera sensata de darle una mesa a esta PRIMARY KEYes hacer que sea KEYuna combinación de curso y estudiante. De esa manera, no puedes obtener:

  • un duplicado de combinación de estudiante y curso

    • un curso solo puede tener al mismo estudiante matriculado una vez, y

    • un estudiante solo puede matricularse en el mismo curso solo una vez

  • también tiene una búsqueda preparada KEYen el curso por estudiante, también conocido como índice de cobertura ,

  • ¡Es trivial encontrar cursos sin estudiantes y estudiantes que no toman cursos!

    - El ejemplo db-fiddle tiene la restricción PK plegada en CREATE TABLE - Se puede hacer de cualquier manera. Prefiero tener todo en la declaración CREATE TABLE.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Ahora, si descubriera que las búsquedas de estudiantes por curso fueron lentas, use un UNIQUE INDEXon (sc_student_id, sc_course_id).

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

No hay ninguna bala de plata para añadir índices - que van a hacer que INSERTs y UPDATEes más lento, pero en la gran ventaja de la enorme disminución deSELECT los tiempos! Depende del desarrollador decidir indexar dado su conocimiento y experiencia, pero decir que los compuestos siemprePRIMARY KEY son malos es simplemente incorrecto.

¡En el caso de unir tablas, generalmente son las únicas PRIMARY KEY que tienen sentido! ¡Las tablas de unión también son muy frecuentemente la única forma de modelar lo que sucede en los negocios o la naturaleza o en prácticamente todos los ámbitos que se me ocurren!

Esta PK también es útil como una covering indexque puede ayudar a acelerar las búsquedas. En este caso, sería particularmente útil si uno estuviera buscando regularmente en (course_id, student_id), lo cual, uno podría imaginar, ¡a menudo puede ser el caso!

Este es solo un pequeño ejemplo de dónde un compuesto PRIMARY KEYpuede ser una muy buena idea, ¡y la única forma sensata de modelar la realidad! Fuera de mi cabeza, puedo pensar en muchos, muchos más.

Un ejemplo de mi propio trabajo!

¡Considere una tabla de vuelo que contiene un flight_id, una lista de aeropuertos de salida y llegada y los horarios relevantes y luego también una tabla de cabina con tripulantes!

La única forma sensata de modelar esto es tener una tabla flight_crew con el flight_id y el crew_id como atributos, ¡y la única forma sensata PRIMARY KEYes utilizar la clave compuesta de los dos campos!


2
En el ejemplo de curso y estudiantes, ¿es posible que course_student tenga una idclave principal y un índice único cs_student_id cs_course_idy tenga los mismos resultados?
Hackvan

2
¿Por qué desperdiciar recursos haciendo eso? Con PK (course_id, student_id), por definición, que ya tiene un índice único en esos campos! Un índice único en (student_id, course_id) podría ser útil para acelerar las búsquedas; por ejemplo, si estaba buscando estudiantes que no estaban tomando ningún curso, pero esa decisión podría ser operativa, pero en estos días de almacenamiento relativamente barato, Lo recomendaría, especialmente porque uno pensaría que la tabla no se actualizará con mucha frecuencia.
Vérace

1
Estoy completamente de acuerdo con las tablas de enlaces: estoy trabajando con varias en este momento. Sin embargo, cuando me pongo mi sombrero de C #, estoy trabajando con el generador reversepoco y creando clases útiles (buscar, guardar, etc.) para la siguiente capa. Me encontré con un problema importante: las teclas compuestas se convierten en PITA por tener un código genérico de guardar / buscar. Sí, tal vez podría volver a los archivos EDMX, pero aún necesito trabajar con un código de caso especial (¿contar columnas Pkey?) O agregar una clave sustituta artificial (no me gusta y necesito restricciones de unicidad adicionales :(). Entonces, supongo personas que no les gustan los compuestos están hablando del código de la capa de la aplicación.
Richard Griffiths

Dependiendo de la frecuencia de las inserciones y la frecuencia de la ventana de desfragmentación de índice vs mantenimiento, esta es la mejor solución. Pero algunas opciones de diseño son compromisos impulsados ​​por requisitos que pueden no ser visibles de inmediato. Pero como dijo un comentario, identifique las ventajas y desventajas de ambos escenarios y haga una elección de diseño.
Jonathan Fite

¿Qué sucede cuando un alumno repite el curso? Luego, a menos que los cursos separados en el tiempo obtengan diferentes identificadores, tendrá otra tabla de mapeo. O agregue un campo para la fecha del curso que ahora debe agregarse a la clave.
iheanyi

3

Mi opinión a medias: una "clave primaria" no tiene que ser la única clave única utilizada para buscar datos en la tabla, aunque las herramientas de administración de datos la ofrecerán como selección predeterminada. Entonces, para elegir si desea tener un compuesto de dos columnas o un número generado aleatoriamente (probablemente en serie) como la clave de la tabla, puede tener dos claves diferentes a la vez.

Si los valores de datos incluyen un término único adecuado que puede representar la fila, prefiero declararlo como "clave primaria", incluso si es compuesto, que usar una clave "sintética". La clave sintética puede funcionar mejor por razones técnicas, pero mi elección predeterminada es designar y usar el término real como clave principal, a menos que realmente necesite ir en sentido contrario para que su servicio funcione.

Un Microsoft SQL Server tiene la característica distinta pero relacionada del "índice agrupado" que controla el almacenamiento físico de datos en orden de índice, y también se usa dentro de otros índices. De forma predeterminada, se crea una clave primaria como un índice agrupado, pero en su lugar puede elegir no agrupado, preferiblemente después de crear el índice agrupado. Por lo tanto, puede tener una columna de identidad entera generada como índice agrupado y, por ejemplo, el nombre de archivo nvarchar (128 caracteres) como clave principal. Esto puede ser mejor porque la clave de índice agrupada es estrecha, incluso si almacena el nombre del archivo como el término de clave externa en otras tablas, aunque este ejemplo es un buen caso para no hacerlo.

Si su diseño involucra la importación de tablas de datos que incluyen una clave primaria inconveniente para identificar datos relacionados, entonces está bastante atrapado con eso.

https://www.techopedia.com/definition/5547/primary-key describe un ejemplo de elegir si almacenar datos con el número de seguro social de un cliente como la clave del cliente en todas las tablas de datos, o generar un id_cliente arbitrario cuando registrarlos En realidad, este es un grave abuso de SSN, aparte de si funciona o no; Es un valor de datos personales y confidenciales.

Por lo tanto, una ventaja de usar un hecho del mundo real como clave es que sin volver a unirse a la tabla "Cliente", puede recuperar información sobre ellos en otras tablas, pero también es un problema de seguridad de datos.

Además, tiene problemas si el SSN u otra clave de datos se registró incorrectamente, por lo que tiene el valor incorrecto en 20 tablas restringidas en lugar de solo en "Cliente". Mientras que el customer_id sintético no tiene un significado externo, no puede ser un valor incorrecto.


1
Aprecio especialmente la observación de que dependiendo de los datos del cliente como clave, incluso los datos únicos conocidos del cliente (aquí, SSN), se descomponen si esos datos alguna vez necesitan corregirse.
ToolmakerSteve
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.