2012-06-11 22 views
5

Tenemos un requisito en nuestra aplicación donde necesitamos almacenar referencias para acceder más tarde.Historización de la base de datos

Ejemplo: Un usuario puede enviar una factura a la vez y todas las referencias (dirección del cliente, cantidad calculada de dinero, descripciones del producto) que esta factura contiene y los cálculos deben almacenarse a lo largo del tiempo.

Necesitamos retener las referencias de alguna manera, pero ¿y si el p. Ej. el nombre del producto cambia? Así que de alguna manera tenemos que copiar todo para que quede documentado para más adelante y no se vea afectado por los cambios en el futuro. Incluso cuando se eliminan productos, es necesario revisarlos más tarde cuando se almacena la factura.

¿Cuál es la mejor práctica aquí en relación con el diseño de bases de datos? Incluso cuál es el enfoque más flexible, por ej. cuando el usuario desea editar su factura más tarde y restaurarla desde el db?

¡Gracias!

Respuesta

9

Aquí es una manera de hacerlo:

enter image description here

En esencia, nunca modificar o eliminar los datos existentes. Lo "modificamos" creando una nueva versión. Lo "borramos" configurando el indicador DELETED.

Por ejemplo:

  • Si el producto cambia el precio, insertamos una nueva fila en PRODUCT_VERSION mientras que los pedidos de edad se mantienen conectados a la edad PRODUCT_VERSION y el precio de edad.
  • Cuando el comprador cambia la dirección, simplemente insertamos una nueva fila en CUSTOMER_VERSION y vinculamos nuevas órdenes a eso, manteniendo los pedidos anteriores vinculados a la versión anterior.
  • Si se elimina el producto, realmente no lo eliminamos. Simplemente configuramos el indicador PRODUCT.DELETED, por lo que todos los pedidos realizados históricamente para ese producto permanecen en la base de datos.
  • Si se elimina al cliente (por ejemplo, porque (s) solicitó no estar registrado), establezca el indicador CUSTOMER.DELETED.

Advertencias:

  • Si el nombre del producto tiene que ser único, que no se pueden cumplir de forma declarativa en el modelo anterior. Necesitarás "promocionar" el NOMBRE de PRODUCT_VERSION a PRODUCT, convertirlo en una clave y renunciar a la capacidad de "evolucionar" el nombre del producto, o imponer la exclusividad solo en los últimos PRODUCT_VER (probablemente a través de activadores).
  • Existe un problema potencial con la privacidad del cliente. Si un cliente es eliminado del sistema, puede ser conveniente eliminar físicamente sus datos de la base de datos y simplemente establecer CUSTOMER.DELETED no hará eso. Si eso es una preocupación, elimine los datos sensibles a la privacidad en todas las versiones del cliente o, alternativamente, desconecte los pedidos existentes del cliente real y reconéctelos a un cliente especial "anónimo", luego elimine físicamente todas las versiones del cliente.

Este modelo usa muchas relaciones de identificación. Esto conduce a claves externas "gordas" y podría ser un problema de almacenamiento ya que MySQL no admite compresión de índice avanzado (a diferencia de, digamos, Oracle), pero por otro lado InnoDB always clusters the data en PK y este agrupamiento puede ser beneficioso. para el rendimiento. Además, las UNIONES son menos necesarias.

modelo equivalente con las relaciones no identificación y claves suplentes se vería así:

enter image description here

+0

Para tener nombres únicos de productos, puede agregar una tabla con solo nombres de productos, donde el nombre es el pk, y un enlace a esa tabla desde PRODUCT_VERSION –

+0

@OweJessen. Claro que podría tener la tabla LATEST_PRODUCT_VERSION con NAME único, pero eso no significa contar como solución "declarativa", ya que necesitaría insertar y eliminar filas manualmente en esa tabla a medida que se crean nuevas versiones de productos. A menos que esté utilizando un DBMS que pueda actualizar automáticamente las vistas materializadas y hacer cumplir la exclusividad en ellas (como las vistas indizadas de MS SQL Server), el propio DBMS mantiene LATEST_PRODUCT_VERSION por usted. –

1

Puede agregar una columna en la tabla del producto para indicar si se está vendiendo o no. Luego, cuando el producto es "eliminado", simplemente establece el indicador para que ya no esté disponible como un producto nuevo, pero conserva los datos para futuras búsquedas.

Para hacer frente a los cambios de nombre, debe utilizar ID para referirse a los productos en lugar de usar el nombre directamente.

+0

Ese segundo punto no le ayudará si quiere incluir históricamente el nombre del producto como lo fue cuando era vendido. Digamos que el mismo ItemId se aplica a "Coke" hasta 1988 y luego a "Coke Classic" después, y él quiere saber que se llamaba "Coke" en órdenes más antiguas. Su sugerencia es lo que intenta evitar: cualquier informe que genere utilizando datos normalizados mostrará "Coke Classic" en todos los pedidos anteriores a 1988 o no. – David

+0

Es cierto ... una forma de lidiar con eso sería crear un nuevo producto para los cambios de nombre, o agregar otra tabla para rastrear los nombres de los productos (que se acerca a la solución de @Branko Dimitrijevic). – whrrgarbl

1

El problema al que se enfrenta es, como estoy seguro, un resultado de la normalización de la base de datos. Uno de los enfoques para resolver esto se puede tomar de las técnicas de Business Intelligence: archivar los datos en un estado des-normalizado en un Data Warehouse.

datos normalizados: mesa

  • órdenes
    • OrderId
    • CustomerId
  • Clientes Tabla
    • CustomerId
    • Nombre
    • etc
  • tabla Elementos
    • ItemId
    • Itemname
    • itemprice
  • OrderDetails Tabla
    • ItemDetailId
    • OrderId
    • ItemId
    • ItemQty
    • etc

Cuando se le preguntó y se almacena de-normalizada, la tabla de almacenamiento de datos se parece a

  • OrderId
  • CustomerId
  • CustomerName
  • CustomerAddress
  • (otro Cliente campos)
  • ItemDetailId
  • ItemId
  • ITEMNAME
  • itemprice
  • (Otros OrderDetail y campos Posición)

Por lo general, o bien hay una cierta clase del trabajo programado que extrae datos de los datos normalizados en el Almacén de datos de forma programada, O si su el signo permite, se puede hacer cuando una orden alcanza un cierto estado. (Tal como se envió) Podría ser que los registros se almacenen en cada cambio de estado (con un campo llamado OrderStatus virando el estado actual), por lo que los datos completamente des-normalizados están disponibles para cada paso del proceso de reclamo/cumplimiento. Cuándo y cómo archivar los datos en el almacén variará según sus necesidades.


Hay una gran cantidad de gastos generales involucrados en lo anterior, pero el otro enfoque común que conozco lleva incluso MÁS sobrecarga.

El otro enfoque sería hacer que las tablas sean de solo lectura.Si un cliente desea cambiar su dirección, no edita su dirección existente, inserta un nuevo registro.

Así que si mi dirección es AddressId 12 cuando solicite por primera vez en su sitio en Jamnuary, entonces me mudo el 4 de julio, obtengo una nueva AddressId vinculada a mi cuenta. (Say AddressID 123123 porque su sitio es muy exitoso y ha atraído una gran cantidad de clientes.)

órdenes que palced antes del 4 de julio de tendrían AddressID 12 asociada con ellos, y los pedidos realizados en o después del 4 de julio de 123123. han AddressID

Repita ese patrón con cada tabla que necesite retener datos históricos.


Tengo un tercer enfoque, pero buscarlo es difícil. Utilizo esto solo en una aplicación, y en realidad funciona bastante bien en esta única instancia, que tenía necesidades empresariales bastante específicas para reconstruir los datos exactamente como lo era en un momento específico. No lo usaría a menos que tuviera necesidades comerciales similares.

En un estado específico, serialice los datos en un documento Xml u otro documento que pueda usar para reconstruir los datos. Esto le permite guardar los datos tal como estaban en el momento en que se serializaron, conservando la estructura de la tabla original y las relaitons.

+0

sí ... qué dijo David Stratton ... quitando mi respuesta más coloquial de la misma idea. – GDP

+0

@Greg P ​​- Iba a votar por usted. Su respuesta es más concisa y aún relevante. – David

+0

Lo volvió a agregar para la posteridad ... no me gusta ser repetitivo cuando hay una respuesta más concisa, gracias sin embargo. – GDP

1

Has abierto un debate eterno entre el enfoque purista y práctico.

Desde el punto de vista de normalización de su base de datos, "debería" conservar todos los datos relevantes. En otras palabras, digamos que un nombre de producto cambia, guarde la fecha del cambio para que pueda retroceder en el tiempo y reconstruir su factura con ese nombre de producto, y todos los demás datos tal como existieron ese día.

Un enfoque "de" normalizado consiste en ver esa factura como un "momento en el tiempo", registrando en los datos de tablas relevantes como lo fue realmente ese día. Este enfoque le permite sacar esa factura sin dependencias en absoluto, pero nunca podría volver a crear esa factura desde cero.

0

Cuando tiene datos sensibles al tiempo, utiliza elementos como el producto y las tablas de clientes como tablas de búsqueda y almacena la información directamente en sus tablas de órdenes/detalles de pedidos. Para que la tabla de pedidos contenga el nombre y la dirección del cliente, los detalles contendrán toda la información relevante sobre el producto incluyendo especialmente el precio (nunca desea confiar en la tabla de productos para información de precios más allá de la búsqueda inicial el orden).

Esto NO es desnormalización, los datos cambian con el tiempo pero necesita el valor histórico, por lo que debe almacenarlos en el momento en que se crea el registro o perderá la intergrity de datos. No desea que sus informes financieros de repente indiquen que vendió un 30% más el año pasado porque tiene actualizaciones de precios. Eso no es lo que vendiste.

+1

"Esto NO se desnormaliza ..." Eso es correcto. En los sistemas relacionales, los datos duplicados significan "los mismos valores con el mismo significado". Aquí, los valores pueden ser los mismos, pero el significado es diferente. (Precio actual, por ejemplo, frente al precio en el momento del pedido.) –

Cuestiones relacionadas