Primero tengo que aclarar que la columna de estado no pretende reflejar el estado de un elemento del mundo real representado por el registro (fila) en la tabla. Más bien, está destinado a mostrar el estado del registro en sí.
Puede ser tan simple como Activo / Inactivo o complicado como Aprobado / Suprimido / Bloqueado / Pendiente / Rechazado, etc. El estado se puede almacenar en una columna entera booleana / corta o en una columna de un solo carácter, con asignaciones como true
/ 1
= Activo o A
= Aprobado.
La idea básica es tener un soporte de recuperación de papelera de reciclaje / basura en la aplicación (y simularlo en la base de datos). Si hay una interfaz gráfica de usuario u otra interfaz que supuestamente puede permitir que un usuario "elimine" registros, en realidad no elimina el registro en la tabla, sino que simplemente cambia el estado del registro a Inactivo o Eliminado. Cuando la interfaz obtiene registros, siempre obtiene los registros que solo coinciden con la condición de que el estado sea Activo o Aprobado.
Si el usuario comete un error y el registro "eliminado" (en la perspectiva del usuario) necesita ser recuperado, un DBA puede volver a conectar fácilmente el registro para que esté activo o aprobado, lo que sería mejor que buscar copias de seguridad y, con suerte, encontrar el registro original allí. O la interfaz en sí misma puede permitir al usuario ver los registros eliminados en una vista separada y restaurarlos según sea necesario, o incluso eliminarlos permanentemente (eliminar el registro real).
Mis preguntas:
- ¿Es esta una buena práctica o una mala práctica?
- ¿Afecta la normalización de los datos?
- ¿Cuáles son las posibles trampas?
- ¿Hay algún método alternativo para lograr el mismo objetivo? (ver nota)
- ¿Cómo puede hacer que la base de datos imponga restricciones únicas en los datos solo para un determinado estado (pero permita cualquier número de duplicados para otros estados)?
- ¿Por qué las bases de datos no proporcionan una característica similar a la "papelera de reciclaje" o el seguimiento / recuperación de tablas de forma nativa, por lo que podemos permitir que las interfaces eliminen los registros reales sin preocupaciones?
Nota: Leí acerca de mantener una tabla de historial separada, pero eso parece peor en términos de almacenamiento y tener que generar desencadenantes y mantener los desencadenantes actualizados con el esquema de la tabla rastreada.
fuente
Respuestas:
Sé esto como un "Soft Delete"; simplemente marcando un registro como "eliminado", aunque realmente no lo es.
Depende.
Si esto es algo que sus usuarios necesitan [mucho], entonces probablemente sea algo bueno. Sin embargo, en la gran mayoría de los casos, diría que está agregando [muchos] gastos generales por poco beneficio.
No, pero le afectará su indexación de los datos.
Asegúrese de incluir la columna "eliminada" en sus índices, de modo que estas filas se excluyan lo antes posible en sus consultas.
Sus datos se vuelven un poco más complejos. Todo lo que se acerca a los datos debe "saber" acerca de estos registros adicionales, "realmente no hay". O bien, debe crear Vistas en esas tablas que excluyen estas filas y usar estas vistas, por ejemplo, en su Herramienta de informes preferida.
Su base de datos puede aumentar de tamaño. Si realmente no está eliminando estas filas, todavía están allí, ocupando espacio. Esto puede o no ser un problema, especialmente porque los ha incluido en sus índices, por lo que el espacio que consumen se multiplica.
No, realmente no.
No es fácil. La integridad referencial declarativa (cláusulas de clave externa) es la forma más limpia de implementar esto y es fácil para cosas como las herramientas de informes recoger estas reglas para determinar las relaciones entre las tablas. Dichas reglas se aplican a todos los registros, independientemente del "estado" (y no hay forma de evitarlo).
La alternativa es usar Triggers, fragmentos de código de procedimiento que imponen la integridad referencial entre tablas y hacen todas las cosas inteligentes y condicionales que necesita. Eso es bueno para su caso particular, pero la mayoría de los beneficios del RI declarativo desaparecen: no hay relaciones [externamente] detectables entre sus tablas; todo eso está "oculto" en los disparadores.
¿Por qué lo harían ellos?
Estas son bases de datos, después de todo, no sistemas de archivos u hojas de cálculo.
Lo que hacen, [pueden] hacer muy, muy bien.
Lo que no hacen, probablemente no ha habido mucha demanda.
fuente
Es una practica. Si es bueno o malo depende en gran medida de su aplicación y con qué frecuencia realmente va a necesitar / querer hacer un "recuperar". Sería bastante dudoso un plan para poner ese tipo de columna de cada tabla en el sistema; parece muy poco probable que realmente se moleste en implementar la recuperación en cada tabla del sistema. Y requiere implementación: en la gran mayoría de los casos, no está recuperando una sola fila de una sola tabla, debe recorrer las tablas secundarias para recuperar filas y actualizar tablas relacionadas.
Para la mayoría del resto de las preguntas, depende en gran medida de la implementación. Por ejemplo, Oracle proporciona diferentes métodos para rastrear todos los cambios en una tabla: Flashback Data Archive (FDA también conocido como Total Recall) es el enfoque más reciente para mantener un historial completo de cada versión de una fila y el archivo en la base de datos para implementar El patrón de borrado suave. Otras bases de datos pueden proporcionar otras formas de implementar el patrón. Dependiendo de la base de datos y de cómo implemente la eliminación suave, habrá varios impactos en el rendimiento, si se pueden aplicar restricciones y cómo, etc. Si estamos hablando de Oracle, puede hacer mucho con índices basados en funciones, por ejemplo , en SQL Server, a menudo puede usar índices filtrados para fines similares.
fuente
Es muy común usar un campo "marcado para eliminación" en los sistemas MRP / ERP.
Por ejemplo, es posible que desee marcar una parte o un registro de inventario que ya no se vende como inactivo, pero todavía hay pedidos pendientes asociados con él. Hacer una eliminación real en el registro podría afectar los pedidos que aún no se han enviado, las entradas del libro mayor que aún no se han publicado, las tablas de historial que no se crearán hasta fin de mes, etc. Muchos sistemas rechazarán la eliminación de un registro a menos que pase una serie de validaciones contra otras tablas. Si está eliminando en cascada a través de sus relaciones, una eliminación real puede ser aún más destructiva.
En cambio, al marcarlo para eliminarlo, coloca un marcador claro de intención en el registro y luego una tarea programada puede eliminar el registro si verifica que todas las tablas relacionadas ya no hacen referencia a él.
Se podría hacer un caso similar para esta característica en una tabla de clientes y otras tablas de "largo plazo". Incluso tiene sentido en tablas más volátiles como los pedidos, aunque el nombre de la bandera puede convertirse en algo como "enviado" o "cancelado". Sirve la misma función: no lo elimine en este momento, sino que lo use como un indicador para el programa de purga para que intente validar la eliminación del registro en el futuro.
fuente
Como solución alternativa, el uso del abastecimiento de eventos permite objetivos similares sin complicar la estructura de la tabla, aunque hace que el código para modificar sus datos sea un poco más complejo, ya que tiene que escribir la modificación en un evento que puede persistir en un historial de eventos . Esto le permite volver a crear la base de datos como estaba en cualquier momento, lo que puede ser una característica muy útil.
(No creo que esto sea lo que quisiste decir con "tabla de historial", que creo que querías decir simplemente copiar registros modificados o eliminados en otra tabla antes de cambiarlos)
fuente
Veo y uso este patrón con frecuencia para estos casos de uso:
El problema es hacer cumplir la integridad de los datos si más de una aplicación o servicio web está escribiendo en tablas. ¿Cómo se asegura que para un caso solo hay un estado actual? Como señala Justin Cave, esto se puede hacer en Oracle creando un índice virtual basado en una función, pero esta sobrecarga adicional para lo que originalmente parecía un concepto simple.
fuente
Es una buena práctica si planea usar sus datos para generar informes (cualquier aplicación lo suficientemente grande necesitaría tener informes).
Para acelerar su aplicación, realmente no debe permitir que las herramientas de informes se ejecuten en su base de datos. Como tal, deberías hacer una copia / sincronización a otra base de datos.
Utilizo
recordStatus
solo dos estadosACTIVE
oCANCELLED
en combinación con unalastUpdatedOn
marca de tiempo. Yo uso enrecordStatus
lugar de lostatus
que generalmente tiene un significado comercial.Cuando estoy sincronizando la base de datos de informes con la aplicación, hago un filtro
lastUpdatedOn
para saber cuáles voy a reemplazar en el lado de los informes.En el lado de los informes, no tendré los campos
recordStatus
olastUpdatedOn
ya que generalmente no se informará sobre ellos. Como tal, cuando veo unCANCELLED
estado, eliminaría el registro del lado del informe de esa manera, solo tiene registros activos.Esto se puede ampliar a otros tipos de tiendas, como archivos o copias de seguridad, donde se requiere una sincronización casi completa. Sin embargo, informar es el propósito más común.
Tenga en cuenta que su ejemplo de
Approved
,New
,Pending
no es una buena idea poner como un campo común que tiene un negocio que significa que debe ir sólo donde hace negocio sentido sabia.En cuanto a bloqueado, use el
versionNo
que proporciona un bloqueo optimista para su registro.Otra opción en lugar de
recordStatus
esrecordActive
almacenarla como unaboolean
que ocupa menos espacio y menos indexación, pero me preocuparían las necesidades futuras que no puede prever.fuente