¿Es una mala práctica tener una columna de "estado de registro" en una tabla de base de datos?

12

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.

ADTC
fuente
El problema con las restricciones únicas (que ya nombró) es exactamente por qué las tablas de historial son a menudo preferibles: puede mantener las restricciones de clave únicas en las tablas originales y no agregarlas en la tabla de historial. Además, las tablas de historial separadas permiten más fácil usar opciones de almacenamiento específicas (dependientes de la base de datos) para ellos, por lo que a menudo son mejores en términos de almacenamiento, no peor. Cuando tiene muchas de esas tablas, los desencadenantes y las tablas de historial no deben escribirse a mano, sino generarse, eso resolverá el problema de cómo mantenerlas "actualizadas".
Doc Brown

Respuestas:

5

Sé esto como un "Soft Delete"; simplemente marcando un registro como "eliminado", aunque realmente no lo es.

¿Es esta una buena práctica o una mala práctica?

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.

¿Afecta la normalización de los datos?

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.

¿Cuáles son las posibles trampas?

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.

¿Hay algún método alternativo para lograr el mismo objetivo? (ver nota)

No, realmente no.

¿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)?

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é 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?

¿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.

Phill W.
fuente
Buena respuesta, pero hay opciones alternativas, por ejemplo, mover las filas a una tabla de respaldo desde donde puede recuperarlas. La tabla de respaldo puede tener índices mínimos. Esto minimiza los problemas que observa con el enfoque existente (índice más grande, posible confusión para los usuarios de la tabla, etc.), pero obviamente agrega el hecho de que tiene otra tabla que mantener (y significa que las entradas se han ido a referencias de claves externas). Hay bastantes otras opciones, pero de hecho, las que vienen a la mente son algunas implementaciones personalizadas, no algo general proporcionado por cada base de datos SQL para tales casos.
Frank Hopkins
9

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.

Justin Cave
fuente
Oracle Flashback es exactamente la solución ideal para lo que quiero. Lástima que es propiedad de Oracle.
ADTC
4

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.

Mike apoya a Monica
fuente
3

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)

Jules
fuente
Concepto interesante Analizaré cómo se puede implementar esto.
ADTC
1

Veo y uso este patrón con frecuencia para estos casos de uso:

  • metadatos donde solo desea mostrar los valores vigentes hoy. Por ejemplo, para elegir de una lista de fabricantes de automóviles en una lista desplegable donde habilitado = 1, los valores de las tablas para ID, VALOR, HABILITADO son 1, 'Ford', 1 y 2, 'Edsel', 0, 3, 'Toyota' , 1 da solo las opciones de Ford y Toyota
  • para un sistema de administración de casos donde el paradigma es que un caso solo puede estar en un estado a la vez. En este caso, la columna de alternancia se llamaba CORRIENTE con valores de 0 o 1 impuestos por restricciones de verificación. A medida que un caso se mueve de un estado a otro, la aplicación actualiza el indicador ACTUAL del estado anterior a 0 y el nuevo a 1

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.

kevinsky
fuente
1

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 recordStatussolo dos estados ACTIVEo CANCELLEDen combinación con una lastUpdatedOnmarca de tiempo. Yo uso en recordStatuslugar de lo statusque generalmente tiene un significado comercial.

Cuando estoy sincronizando la base de datos de informes con la aplicación, hago un filtro lastUpdatedOnpara saber cuáles voy a reemplazar en el lado de los informes.

En el lado de los informes, no tendré los campos recordStatuso lastUpdatedOnya que generalmente no se informará sobre ellos. Como tal, cuando veo un CANCELLEDestado, 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, Pendingno 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 versionNoque proporciona un bloqueo optimista para su registro.

Otra opción en lugar de recordStatuses recordActivealmacenarla como una booleanque ocupa menos espacio y menos indexación, pero me preocuparían las necesidades futuras que no puede prever.

Arquímedes Trajano
fuente