ruby-on-rails database design-patterns database-design

ruby on rails - Claves primarias compuestas contra el campo ID de objeto único



ruby-on-rails database (15)

... cómo la base de datos maneja los campos de ID de una manera no eficiente y cuando está construyendo índices, los tipos de árbol tienen fallas ...

Esto era casi una tontería, pero puede estar relacionado con el problema de la contención del bloque de índice cuando se asignan números incrementales a un PK a una tasa alta de diferentes sesiones. Si es así, el índice REVERSE KEY está ahí para ayudar, aunque a expensas de un tamaño de índice mayor debido a un cambio en el algoritmo de división de bloques. http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/schema.htm#sthref998

Vaya sintético, particularmente si ayuda a un desarrollo más rápido con su conjunto de herramientas.

Heredé una base de datos creada con la idea de que las claves compuestas son mucho más ideales que usar un campo de Id. De objeto único y que al construir una base de datos, nunca se debe usar una única ID única como clave principal. Como estaba construyendo un front-end de Rails para esta base de datos, tuve dificultades para cumplir con las convenciones de Rails (aunque era posible usar vistas personalizadas y algunas gemas adicionales para manejar claves compuestas).

El razonamiento detrás de este diseño de esquema específico de la persona que lo escribió tenía que ver con cómo la base de datos maneja los campos de ID de una manera no eficiente y cuando está construyendo índices, los tipos de árbol son defectuosos. Esta explicación carecía de profundidad y todavía estoy tratando de entender el concepto (estoy familiarizado con el uso de claves compuestas, pero no el 100% del tiempo).

¿Alguien puede opinar o agregar más profundidad a este tema?


@JeremyDWill

Gracias por proporcionar un equilibrio muy necesario para el debate. En particular, gracias por la información sobre DOMAIN s.

De hecho, utilizo claves sustitutivas en todo el sistema en aras de la coherencia, pero hay compromisos involucrados. La causa más común para que maldijera el uso de claves sustitutas es cuando tengo una tabla de búsqueda con una lista breve de valores canónicos: utilizaría menos espacio y todas mis consultas serían más cortas / más fáciles / más rápidas si hubiera hecho los valores. PK en lugar de tener que unirse a la mesa.


Básicamente, soy un miembro del equipo clave sustituto, e incluso si aprecio y entiendo argumentos como los presentados aquí por JeremyDWill, todavía estoy buscando el caso donde la clave "natural" es mejor que el sustituto ...

Otras publicaciones que tratan este tema suelen referirse a la teoría de base de datos relacional y al rendimiento de la base de datos. Otro argumento interesante, siempre olvidado en este caso, está relacionado con la normalización de tablas y la productividad del código :

cada vez que creo una tabla, ¿perderé tiempo?

  1. identificando su clave primaria y sus características físicas (tipo, tamaño)
  2. recordando estas características cada vez que quiero referirme a él en mi código?
  3. explicando mi elección PK a otros desarrolladores en el equipo?

Mi respuesta es no a todas estas preguntas:

  1. No tengo tiempo para perder tratando de identificar "la mejor clave principal" cuando trato con una lista de personas.
  2. No quiero recordar que la clave principal de mi tabla de " computer " es una cadena de 64 caracteres de longitud (¿acepta Windows tantos caracteres para un nombre de computadora?).
  3. No quiero explicar mi elección a otros desarrolladores, donde uno de ellos finalmente dirá "Sí, amigo, pero tenga en cuenta que tiene que administrar las computadoras en diferentes dominios? ¿Esta cadena de 64 caracteres le permite almacenar el nombre de dominio + el ¿nombre de la computadora?".

Así que he estado trabajando durante los últimos cinco años con una regla muy básica: cada tabla (llamémosla '' myTable '') tiene su primer campo llamado '' id_MyTable '' que es de tipo uniqueIdentifier. Incluso si esta tabla admite una relación "muchos a muchos", como una tabla '' ComputerUser '', donde la combinación de '' id_Computer '' y '' id_User '' forma una clave principal muy aceptable, prefiero crear este campo '' id_ComputerUser '' ser un identificador único, solo para cumplir con la regla.

La principal ventaja es que no tiene que preocuparse por el uso de la clave principal y / o clave externa dentro de su código. Una vez que tenga el nombre de la tabla, conocerá el nombre y el tipo de PK. Una vez que sepa qué enlaces se implementan en su modelo de datos, sabrá el nombre de las claves externas disponibles en la tabla.

No estoy seguro de que mi regla sea la mejor. ¡Pero es muy eficiente!


El uso de los campos ''único (objeto) ID'' simplifica las uniones, pero debe intentar que la otra clave (posiblemente compuesta) siga siendo única: NO relaje las restricciones no nulas y SÍ mantenga la restricción única.

Si el DBMS no puede manejar enteros únicos de forma efectiva, tiene grandes problemas. Sin embargo, el uso de un ''ID único (de objeto)'' y la otra clave usa más espacio (para los índices) que solo la otra clave, y tiene dos índices para actualizar en cada operación de inserción. Por lo tanto, no es un regalo de promoción, pero siempre que mantenga la clave original, entonces estará bien. Si elimina la otra clave, está rompiendo el diseño de su sistema; todo el infierno se desatará eventualmente (y podrías o no ver que el infierno se desató).


He estado desarrollando aplicaciones de bases de datos durante 15 años y todavía tengo que encontrar un caso en el que una clave no sustituta sea una mejor opción que una clave sustituta.

No estoy diciendo que ese caso no exista, solo digo que cuando se tienen en cuenta los problemas prácticos de desarrollar una aplicación que accede a la base de datos, generalmente los beneficios de una clave sustituta comienzan a abrumar a la pureza teórica de no -las llaves de sustitución.


La mayoría de los motores comúnmente utilizados (MS SQL Server, Oracle, DB2, MySQL, etc.) no experimentarían problemas notables con un sistema de clave sustituta. Algunos incluso pueden experimentar un aumento en el rendimiento por el uso de un sustituto, pero los problemas de rendimiento son altamente específicos de la plataforma.

En términos generales, la clave natural (y por extensión, la clave compuesta) versa el debate clave sustituto tiene una larga historia sin posibilidad de "respuesta correcta" a la vista.

Los argumentos para las claves naturales (singular o compuesto) generalmente incluyen algunos de los siguientes:

1) Ya están disponibles en el modelo de datos. La mayoría de las entidades que se modelan ya incluyen uno o más atributos o combinaciones de atributos que satisfacen las necesidades de una clave con el propósito de crear relaciones. Agregar un atributo adicional a cada tabla incorpora una redundancia innecesaria.

2) Eliminan la necesidad de ciertas uniones. Por ejemplo, si tiene clientes con códigos de clientes y facturas con números de factura (ambas son claves "naturales") y desea recuperar todos los números de factura para un código de cliente específico, simplemente puede usar "SELECT InvoiceNumber FROM Invoice WHERE CustomerCode = ''XYZ123''" . En el enfoque clásico de clave sustituta, el SQL se vería así: "SELECT Invoice.InvoiceNumber FROM Invoice INNER JOIN Customer ON Invoice.CustomerID = Customer.CustomerID WHERE Customer.CustomerCode = ''XYZ123''" .

3) Contribuyen a un enfoque más aplicable universalmente al modelado de datos. Con las claves naturales, el mismo diseño se puede utilizar en gran medida sin cambios entre diferentes motores SQL. Muchos enfoques de claves indirectas utilizan técnicas de motor de SQL específicas para la generación de claves, lo que requiere una mayor especialización del modelo de datos para implementar en diferentes plataformas.

Los argumentos para las claves sustitutas tienden a girar en torno a problemas que son específicos del motor SQL:

1) Permiten cambios más fáciles a los atributos cuando cambian los requisitos o las reglas del negocio. Esto se debe a que permiten que los atributos de datos se aíslen en una sola tabla. Esto es principalmente un problema para los motores SQL que no implementan de forma eficiente las construcciones estándar de SQL como DOMAIN. Cuando un atributo se define mediante una instrucción DOMAIN, los cambios en el atributo se pueden realizar en todo el esquema utilizando una instrucción ALTER DOMAIN. Diferentes motores SQL tienen diferentes características de rendimiento para alterar un dominio, y algunos motores SQL no implementan DOMINIOS en absoluto, por lo que los modeladores de datos compensan estas situaciones al agregar claves sustitutas para mejorar la capacidad de realizar cambios en los atributos.

2) Permiten implementaciones de concurrencia más sencillas que las claves naturales. En el caso de la llave natural, si dos usuarios trabajan simultáneamente con el mismo conjunto de información, como una fila de cliente, y uno de los usuarios modifica el valor de la clave natural, una actualización del segundo usuario fallará porque el código del cliente es la actualización ya no existe en la base de datos. En el caso de clave sustituta, la actualización se procesará correctamente porque los valores de ID inmutables se utilizan para identificar las filas en la base de datos, no los códigos de cliente mutables. Sin embargo, no siempre es deseable permitir la segunda actualización: si el código del cliente cambió, es posible que no se permita al segundo usuario proceder con su cambio porque la "identidad" real de la fila ha cambiado; el segundo usuario puede estar actualizando la fila incorrecta. Ni las claves indirectas ni las claves naturales, por sí mismas, abordan este problema. Las soluciones integrales de simultaneidad deben abordarse fuera de la implementación de la clave.

3) Funcionan mejor que las llaves naturales. El rendimiento es más directamente afectado por el motor SQL. El mismo esquema de base de datos implementado en el mismo hardware utilizando diferentes motores SQL a menudo tendrá características de rendimiento dramáticamente diferentes, debido a los mecanismos de recuperación y almacenamiento de datos de los motores SQL. Algunos motores SQL se aproximan mucho a los sistemas de archivos planos, donde los datos se almacenan de manera redundante cuando el mismo atributo, como un Código del cliente, aparece en múltiples lugares en el esquema de la base de datos. Este almacenamiento redundante por parte del motor SQL puede causar problemas de rendimiento cuando es necesario realizar cambios en los datos o el esquema. Otros motores SQL proporcionan una mejor separación entre el modelo de datos y el sistema de almacenamiento / recuperación, lo que permite cambios más rápidos de datos y esquemas.

4) Las claves sustitutas funcionan mejor con ciertas bibliotecas de acceso a datos y marcos de GUI. Debido a la naturaleza homogénea de la mayoría de los diseños de claves sustitutas (por ejemplo, todas las claves relacionales son números enteros), las bibliotecas de acceso a datos, ORM y GUI pueden trabajar con la información sin necesidad de un conocimiento especial de los datos. Las claves naturales, debido a su naturaleza heterogénea (diferentes tipos de datos, tamaño, etc.), no funcionan tan bien con kits de herramientas y bibliotecas automatizados o semiautomatizados. Para escenarios especializados, como bases de datos SQL incorporadas, puede ser aceptable diseñar la base de datos con un conjunto de herramientas específico. En otros escenarios, las bases de datos son recursos de información empresarial, a las que se accede simultáneamente por múltiples plataformas, aplicaciones, sistemas de informes y dispositivos, y por lo tanto no funcionan tan bien cuando se diseñan con un foco en una biblioteca o marco en particular. Además, las bases de datos diseñadas para trabajar con kits de herramientas específicos se convierten en un inconveniente cuando se presenta el siguiente gran conjunto de herramientas.

Tiendo a caer en el lado de las llaves naturales (obviamente), pero no soy fanático al respecto. Debido al entorno en el que trabajo, donde cualquier base de datos dada que ayudo a diseñar puede ser utilizada por una variedad de aplicaciones, uso claves naturales para la mayoría del modelado de datos, y rara vez presento sustitutos. Sin embargo, no salgo de mi camino para tratar de volver a implementar las bases de datos existentes que usan sustitutos. Los sistemas de clave sustituta funcionan bien, no es necesario cambiar algo que ya está funcionando bien.

Hay algunos recursos excelentes que analizan los méritos de cada enfoque:

http://www.google.com/search?q=natural+key+surrogate+key

http://www.agiledata.org/essays/keys.html

http://www.informationweek.com/news/software/bi/201806814


Las claves compuestas pueden ser buenas, ya que pueden afectar el rendimiento, pero no son la única respuesta, de la misma forma que una clave única (sustituta) no es la única respuesta.

Lo que me preocupa es la vaguedad en el razonamiento para elegir claves compuestas. La mayoría de las veces, la imprecisión sobre cualquier aspecto técnico indica una falta de comprensión, tal vez siguiendo las pautas de otra persona, en un libro o artículo ...

No hay nada de malo con una única ID única: de hecho, si tienes una aplicación conectada a un servidor de base de datos y puedes elegir qué base de datos estás usando, todo será bueno, y puedes hacer prácticamente cualquier cosa con tus claves y no realmente sufrir demasiado mal.

Se ha escrito y se escribirá mucho sobre esto, porque no hay una sola respuesta. Hay métodos y enfoques que deben aplicarse con cuidado de manera especializada.

He tenido muchos problemas con las identificaciones que la base de datos proporciona automáticamente, y las evito siempre que sea posible, pero aún las uso de vez en cuando.


No tengo experiencia, pero aún estoy a favor de Usar la clave principal como id. Aquí está la explicación usando un ejemplo.

El formato de los datos externos puede cambiar con el tiempo. Por ejemplo, podría pensar que el ISBN de un libro sería una buena clave principal en una tabla de libros. Después de todo, los ISBN son únicos. Pero a medida que se escribe este libro en particular, la industria editorial en los Estados Unidos se está preparando para un cambio importante a medida que se agregan dígitos adicionales a todos los ISBN. Si hubiéramos usado el ISBN como la clave principal en una tabla de libros, tendríamos que actualizar cada fila para reflejar este cambio. Pero luego tendríamos otro problema. Habrá otras tablas en la base de datos que hacen referencia a las filas en la tabla de libros a través de la clave principal. No podemos cambiar la clave en la tabla de libros a menos que primero revisemos y actualicemos todas estas referencias. Y eso implicará descartar restricciones de clave externa, actualizar tablas, actualizar la tabla de libros y finalmente restablecer las restricciones. En general, esto es algo de dolor. Los problemas desaparecen si usamos nuestro propio valor interno como clave principal. Ningún tercero puede venir y decirnos arbitrariamente que cambiemos nuestro esquema: controlamos nuestro propio espacio de claves. Y si algo como el ISBN necesita cambiar, puede cambiar sin afectar a ninguna de las relaciones existentes en la base de datos. En efecto, hemos desacoplado el tejido de filas de la representación externa de datos en esas filas.

Aunque la explicación es bastante libre, pero creo que explica las cosas de una manera más simple.


Puede hacer ambas cosas, ya que es probable que una gran base de datos de empresas sea utilizada por varias aplicaciones, incluidos DBA humanos que ejecutan consultas únicas e importaciones de datos, diseñarla exclusivamente para el beneficio de los sistemas ORM no siempre es práctico o deseable.

Lo que tiendo a hacer estos días es agregar una propiedad "RowID" a cada tabla; este campo es un GUID, y tan único para cada fila. Esta NO es la clave principal, es una clave natural (si es posible). Sin embargo, cualquier capa de ORM que funcione en la parte superior de esta base de datos puede usar RowID para identificar sus objetos derivados.

Por lo tanto, puede tener:

CREATE TABLE dbo.Invoice ( CustomerId varchar(10), CustomerOrderNo varchar(10), InvoiceAmount money not null, Comments nvarchar(4000), RowId uniqueidentifier not null default(newid()), primary key(CustomerId, CustomerOrderNo) )

¡Entonces su DBA está contento, su arquitecto ORM está feliz y la integridad de su base de datos se conserva!


Solo quería agregar algo aquí que nunca veo cubierto cuando analizo campos de identidad enteros autogenerados con bases de datos relacionales (porque los veo mucho), y es decir, su tipo de base puede desbordarse en algún momento.

Ahora no estoy tratando de decir que esto automáticamente hace que los identificadores compuestos sean el camino a seguir, pero es una cuestión de hecho que aunque se podrían agregar lógicamente más datos a una tabla (que aún es única), el único entero autogenerado la identidad podría evitar que esto suceda.

Sí, me doy cuenta de que para la mayoría de las situaciones es poco probable, y el uso de un entero de 64 bits te da mucho espacio libre, y de forma realista, la base de datos probablemente debería haber sido diseñada de manera diferente si ocurriera un desbordamiento como este.

Pero eso no impide que alguien lo haga ... una tabla que usa un solo entero de 32 bits autogenerado ya que su identidad, que se espera que almacene todas las transacciones a nivel global para una compañía de comida rápida en particular, está fallando como tan pronto como intente insertar su transacción es 2.147.483.648 (y eso es un escenario completamente factible).

Es solo algo a tener en cuenta, que las personas tienden a ignorar o simplemente ignorar por completo. Si se va a insertar cualquier tabla con regularidad, se deben tener en cuenta la frecuencia y la cantidad de datos que se acumularán a lo largo del tiempo, y si se debe usar incluso un identificador basado en enteros.


Un enfoque práctico para desarrollar una nueva arquitectura es aquel que utiliza claves sustitutas para tablas que contendrán miles de registros altamente únicos de múltiples columnas y claves compuestas para tablas de descripción breve. Normalmente encuentro que las universidades dictan el uso de claves sustitutas mientras que los programadores del mundo real prefieren las claves compuestas. Realmente necesita aplicar el tipo correcto de clave principal a la tabla, no solo de una forma u otra.


Voy a ser breve y dulce aquí: las claves primarias compuestas no son buenas en estos días. Agregue claves arbitrarias sustitutas si puede y mantenga los esquemas de claves actuales a través de restricciones únicas. ORM está contento, eres un programador feliz y original, pero no tan feliz, pero a menos que sea tu jefe, puede lidiar con eso.


la clave principal debe ser constante y sin sentido ; las claves no sustitutas generalmente fallan uno o ambos requisitos, eventualmente

  • si la clave no es constante, tiene un problema de actualización en el futuro que puede ser bastante complicado

  • si la clave no tiene sentido, entonces es más probable que cambie, es decir, que no sea constante; véase más arriba

tome un ejemplo simple y común: una tabla de artículos de inventario. Puede ser tentador hacer que el número de artículo (número de sku, código de barras, código de pieza o lo que sea) sea la clave principal, pero un año después todos los números de artículo cambian y usted se queda con una actualización muy desordenada del todo problema de base de datos ...

EDITAR: hay un problema adicional que es más práctico que filosófico. En muchos casos, encontrará una fila en particular de alguna manera, luego la actualizará o la encontrará nuevamente (o ambas cosas). Con las claves compuestas hay más datos para realizar un seguimiento y más restricciones en la cláusula WHERE para la reubicación o actualización (o eliminación). ¡También es posible que uno de los segmentos clave haya cambiado mientras tanto! Con una clave sustituta, siempre hay un único valor que retener (la ID sustituta) y, por definición, no puede cambiar, lo que simplifica la situación significativamente.


usar llaves naturales hace una pesadilla usando cualquier ORM automático como capa de persistencia. Además, las claves externas en varias columnas tienden a superponerse entre sí y esto generará un mayor problema al navegar y actualizar la relación de manera OO.

Aún así, podría transformar la clave natural en una restricción única y agregar una identificación generada automáticamente; sin embargo, esto no elimina el problema con las claves externas, las cuales deberán cambiarse a mano; es de esperar que las columnas múltiples y las restricciones superpuestas sean una minoría de toda la relación, por lo que podría concentrarse en la refactorización donde más le importe.

pk natural tiene su escenario de motivación y uso y no es malo (tm), simplemente tienden a no llevarse bien con ORM.

mi sensación es que, como cualquier otro concepto, las claves naturales y la normalización de tablas deberían usarse cuando las restricciones de diseño sean sensibles y no tan ciegas


Parece que la persona que creó la base de datos está en el lado de las llaves naturales de las grandes claves naturales vs. el debate de las claves sustitutivas.

Nunca he oído hablar de ningún problema con btrees en campos ID, pero tampoco lo he estudiado en profundidad.

Caigo en el lado de la clave sustituta: tiene menos repetición cuando usa una clave sustituta, porque solo está repitiendo un valor único en las otras tablas. Dado que los seres humanos rara vez se unen a las mesas a mano, no nos importa si se trata de un número o no. Además, dado que solo hay una columna de tamaño fijo para buscar en el índice, es seguro suponer que los sustitutos también tienen un tiempo de búsqueda más rápido por clave principal.