una sencillos paso normalizar normalizacion normales normal formas forma ejemplos datos conceptos como basicos performance database-design readability maintainability

performance - paso - normalizacion de base de datos ejemplos sencillos



Diseño de normalización de la base de datos: tablas únicas o múltiples (7)

¿Debería esto estar representado en la base de datos como 1 tabla o 3 tablas? Mi amigo y yo tenemos opiniones diferentes sobre esto, así que me gustaría ver las opiniones generales sobre esto. (Tal vez debería ser un voto para cualquiera de las soluciones?)

Create Table Order // Basic fields of the table - ID (Primary key) - CustomerID (integer, with a FK) - Quantity - ProductID (integer, with a FK) // Then depending on user selection, either these fields need to be specified // (could be factored out to a separate table): { - InternalAccountID (integer, with a FK) - InternalCompanyID (integer, with a FK) } // Or these (could be factored out to a separate table): { - ExternalAccountNumber (free text string) - ExternalCompanyName (free text string) - ExtraInformation (free text string) }

1 enfoque de tabla:

Pros:

  • rendimiento (una inserción en lugar de dos, control FK, sin uniones)
  • probablemente tome menos espacio (las tablas adicionales tienen campos + índices + campo ID extra)
  • una mesa en lugar de tres
  • difícilmente justificable dividirse en tablas nuevas solo para 2 + 3 campos (¿o qué?)

Contras:

  • Campos Nullable
  • Columna "tipo" potencialmente extra (se puede omitir)
  • Rompe 3NF (?)

Pros y contras amablemente solicitados, así como las opiniones personales. :)

EDITAR: Intenté simplificar el ejemplo utilizando diferentes entidades de las que realmente estoy usando, por lo que cualquier sugerencia para modificar el modelo realmente no me ayudaría. Es decir, se centran más en los aspectos técnicos que en el modelo de dominio.


Mi opinión sería que si

// Then depending on user selection, either these fields need to be specified // (could be factored out to a separate table): { - InternalAccountID (integer, with a FK) - InternalCompanyID (integer, with a FK) } // Or these (could be factored out to a separate table): { - ExternalAccountNumber (free text string) - ExternalCompanyName (free text string) - ExtraInformation (free text string) }

siempre son 1: 1 con un pedido (es decir, no puede tener 3 ID de cuenta), luego déjelo como una sola tabla. Para solucionar su problema nulo, podría agregar una columna más llamada InternalCustomer (boolean) o CustomerType (varChar) que podría usar para definir a un cliente interno o externo para saber cuál de los dos conjuntos de campos debe mirar para un cliente específico.

Dado que no conocemos el uso completo de esta información o el esquema para toda la base de datos, cualquier respuesta al respecto no puede ser totalmente calificada.


A medida que aumenta el volumen, la selección de dos tablas puede ser mucho más rápida que una . A veces, este tipo de refactorización (partición) se realiza en bases de datos maduras para aumentar el rendimiento.

Imagina usar esto para una unión de varias tablas, donde algunos criterios están en esta tabla, pero otros están en tablas diferentes.

select from order join customer using (customer_id) where order.order_date between ? and ? and customer.name = ?

Puede terminar obteniendo todas las filas de order para las fechas del disco, y luego descartando muchas de ellas porque no coinciden con la combinación. Esta captura del disco está destinada a ser lenta y puede estropear su memoria caché RAM.

select from order join order_detail using (order_id) join customer using (customer_id) where order.order_date between ? and ? and customer.name = ?

En este caso, cuando carga todas las filas de order desde el disco, no va a doler tanto como antes, porque la tabla es más estrecha y más pequeña. No necesita cargar todos los campos largos que son irrelevantes para el filtrado. Eventualmente, después de unirse al customer , solo obtendrá esas filas order_detail que coinciden con todos los criterios.

Si espera que esto sea grande, debe considerar dividir la tabla para que los campos que son más críticos para las búsquedas se encuentren en una tabla, y los campos "datos" en otra (s) tabla (s) uno-a-uno.

La conclusión es: la forma y el dominio normales son una cosa, pero el rendimiento a menudo requiere compensaciones . Puede ocultar algunos de ellos (cubrir la división con una vista), pero no todos (campos duplicados / agregados por una selección más rápida).


Si desea evitar la duplicación de datos, debe elegir una solución de 2 o 3 tablas. Por ejemplo, si tiene las columnas External en la tabla Orden, el valor podría existir varias veces. Si los datos son así:

ID ExternalCompanyName 1 ACME 2 ACME 3 My Company 4 ACME

Ahora, si ACME cambia los nombres a ACME, Inc. debe actualizar muchas filas. Si las tablas están normalizadas, donde las compañías externas se encuentran en una tabla separada, debería actualizar una fila. Tenga en cuenta que puede haber un argumento para poner el Número de cuenta en su propia tabla, pero lo dejaremos para una normalización extrema.

No parece ser una relación de 1 a 1 entre un pedido y una empresa / cuenta, a menos que cada empresa / cuenta solo tenga un pedido. suena más como una relación de 1 a muchos.

Ahora, qué ocurre si se comete un error al actualizar ExternalCompanyName en un entorno de tabla única, y solo algunas de las filas se actualizan. Tiene algunas filas con ACME y algunas filas con ACME, Inc. Usted termina con una situación de datos erróneos.

Además, si esto es realmente una relación de uno a muchos, realmente no está ahorrando espacio. Está duplicando datos en el orden, en lugar de almacenarlos una vez en otra tabla.


No iría con la solución de 3 mesas. Al dividir estos datos en 3 tablas, no puede tener ninguna consulta que devuelva un encabezado de orden completo sin unirse con la clave externa, y cada inserción de un nuevo pedido actualiza varias tablas e índices, lo que es un problema para la concurrencia. Sugeriría usar 2 tablas, una para InternalOrders y otra para ExternalOrders. Para aquellos casos en los que necesite una consulta consolidada de datos de ambos conjuntos de órdenes, defina una vista que sea la unión de ambas tablas.

Me sorprende ver la identificación del producto y la cantidad como parte del encabezado de la orden. Cada base de datos de seguimiento de pedidos que he visto divide los artículos ordenados como una tabla separada, utilizando el ID del pedido como una clave externa, de modo que un solo pedido puede incluir varios productos (o el mismo producto con diversas cantidades, tiempos de entrega, etc. )


No soy purista, así que 3nf es bueno cuando tiene sentido ... pero no tienes que dar por hecho que siempre lo hará.

Desde un punto de vista pragmático, ¿cuál es tu objetivo? Su lista de pros y contras es un buen comienzo. Agregaría algunas ideas más a la lista, como mejor le parezca.

1) ¿ Alguna otra tabla en su base de datos deberá relacionarse (por ejemplo, unirse) a esta información? Ese es el punto de un RDB.

2) ¿Su base de datos crecerá? Incluso si 1 mesa tiene sentido ahora, ¿siempre tendrá sentido? Te arrepentirás si crees que deseas agregar más tablas, y tu tabla no normalizada te está obligando a "solucionarlo", lidiando con filas adicionales devueltas, tiempos de ejecución más lentos, etc.

3) ¿Qué sucede cuando su cliente obtiene una nueva cuenta externa o qué tiene usted? ¿Creará un nuevo disco? ¿Cómo responderá a preguntas como "¿Cuál es el número de cuenta de la gente del cliente?".

...

Creo que, en general, voy por escalable, que en este caso puede significar 3nf. 1 tabla es más fácil de tratar en un ámbito muy limitado, pero si algo cambia alguna vez, se tratará con "¿Cómo divido esta tabla en tablas 3nf correctamente relacionadas, sin desordenar todas las dependencias que se han creado en ¿eso?". Ese no es divertido.


¿La información de la cuenta está asociada con el cliente antes de que pueda realizar un pedido (es decir, tiene otra tabla en la que rastrea qué ID de cuenta se le pueden dar)? ¿Puede abstraer todas las cuentas a un esquema razonablemente uniforme (que puede tener algunos nulos) para que tenga un AccountId universal (clave sustituta) y luego la tabla de Account tiene 3 campos varchar y uno que rastrea el tipo de cuenta (utilizada para facturación, etc.)?

Si puede hacer eso, su orden rastrea solo un ID de cuenta dado que a la orden (como entidad) realmente no le importa qué método de pago se utilizó, solo le preocupa que sea un Id. De cuenta legítimo / existente / aprobado para ese usuario. Todo lo demás es asunto de otra persona, por así decirlo (facturación o control de fondos, etc.) y esa entidad y su procesamiento necesitarán más datos de todos modos.

Esto mantiene su Orden limpio y libre de nulidades y facilita la separación de las preocupaciones también.

Conceptualmente, su Orden es realmente llamada tabla de hechos, con solo números y FK-s, pequeño en tamaño de artículo pero con un gran número de ellos.

Asi que:

Table Order ( - OrderId - Quantity - ProductId - DiscountId -- sonner or latter :-) - AccountId - PaymentStatus -- probaly FK as well or predefined constant ) Table Account ( - AccountId - BillingInfo -- akka ext acct number as text - PrincialName -- akka ext company name, some equivalent for internal acct-s - AdditionalData )


Espero que esto se explique por sí mismo.