Diseño de base de datos para registro de auditoría

151

Cada vez que necesito diseñar una nueva base de datos, paso bastante tiempo pensando en cómo debo configurar el esquema de la base de datos para mantener un registro de auditoría de los cambios.

Ya se han hecho algunas preguntas sobre esto, pero no estoy de acuerdo en que haya un mejor enfoque para todos los escenarios:

También me topé con este interesante artículo sobre Mantener un registro de cambios en la base de datos que intenta enumerar los pros y los contras de cada enfoque. Está muy bien escrito y tiene información interesante, pero ha hecho que mis decisiones sean aún más difíciles.

Mi pregunta es: ¿Hay alguna referencia que pueda usar, tal vez un libro o algo así como un árbol de decisión al que pueda referirme para decidir qué camino tomar en función de algunas variables de entrada, como:

  • La madurez del esquema de la base de datos.
  • Cómo se consultarán los registros
  • La probabilidad de que sea necesario volver a crear registros
  • Lo que es más importante: escribir o leer el rendimiento
  • Naturaleza de los valores que se registran (cadena, números, blobs)
  • Espacio de almacenamiento disponible

Los enfoques que conozco son:

1. Agregue columnas para la fecha y el usuario creados y modificados

Ejemplo de tabla:

  • carné de identidad
  • valor_1
  • valor_2
  • valor_3
  • Fecha de creación
  • fecha_modificada
  • creado por
  • modificado por

Contras principales: perdemos la historia de las modificaciones. No se puede revertir después de confirmar.

2. Insertar solo tablas

Ejemplo de tabla :

  • carné de identidad
  • valor_1
  • valor_2
  • valor_3
  • de
  • a
  • eliminado (booleano)
  • usuario

Contras principales: ¿Cómo mantener actualizadas las claves extranjeras? Enorme espacio necesario

3. Cree una tabla de historial separada para cada tabla

Ejemplo de tabla de historial:

  • carné de identidad
  • valor_1
  • valor_2
  • valor_3
  • valor_4
  • usuario
  • eliminado (booleano)
  • marca de tiempo

Contras principales: necesita duplicar todas las tablas auditadas. Si el esquema cambia, también será necesario migrar todos los registros.

4. Crear una tabla de historial consolidado para todas las tablas

Ejemplo de tabla de historial:

  • nombre de la tabla
  • campo
  • usuario
  • nuevo valor
  • eliminado (booleano)
  • marca de tiempo

Contras principales: ¿Podré recrear los registros (revertir) si es necesario fácilmente? La columna new_value debe ser una cadena enorme para que pueda admitir todos los tipos de columnas diferentes.

jbochi
fuente
1
¿Y qué hay de usar una base de datos de historial en lugar de tablas?
Jowen
Tal vez podría consultar el diseño de github.com/airblade/paper_trail
zx1986
¿Es una mala idea registrar todas las consultas (requeridas) ejecutadas tal como están?
Dinushan

Respuestas:

87

Un método que utilizan algunas plataformas wiki es separar los datos de identificación y el contenido que está auditando. Agrega complejidad, pero terminas con una pista de auditoría de registros completos, no solo listas de campos que fueron editados que luego tienes que combinar para darle al usuario una idea de cómo se veía el registro anterior.

Entonces, por ejemplo, si tuviera una tabla llamada Oportunidades para rastrear ofertas de ventas, en realidad crearía dos tablas separadas:

Oportunidades
Oportunidades_Contenido (o algo así)

La tabla Oportunidades tendría información que usaría para identificar de forma exclusiva el registro y albergaría la clave principal a la que haría referencia para sus relaciones de clave externa. La tabla Oportunidades_Contenido contendría todos los campos que sus usuarios pueden cambiar y para los que desea mantener un seguimiento de auditoría. Cada registro en la tabla de Contenido incluiría su propia PK y los datos modificados por y fecha modificada. La tabla Oportunidades incluiría una referencia a la versión actual, así como información sobre cuándo se creó originalmente el registro principal y quién lo hizo.

Aquí hay un ejemplo simple:

CREATE TABLE dbo.Page(  
    ID int PRIMARY KEY,  
    Name nvarchar(200) NOT NULL,  
    CreatedByName nvarchar(100) NOT NULL, 
    CurrentRevision int NOT NULL, 
    CreatedDateTime datetime NOT NULL

Y los contenidos:

CREATE TABLE dbo.PageContent(
    PageID int NOT NULL,
    Revision int NOT NULL,
    Title nvarchar(200) NOT NULL,
    User nvarchar(100) NOT NULL,
    LastModified datetime NOT NULL,
    Comment nvarchar(300) NULL,
    Content nvarchar(max) NOT NULL,
    Description nvarchar(200) NULL

Probablemente haría que el PK de la tabla de contenido sea una clave de varias columnas de PageID y Revisión, siempre que la Revisión sea un tipo de identidad. Usaría la columna Revisión como FK. Luego extrae el registro consolidado uniéndose así:

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

Puede haber algunos errores allí arriba ... esto está fuera de mi cabeza. Sin embargo, debería darte una idea de un patrón alternativo.

Josh Anderson
fuente
10
En términos de un buen enfoque de auditoría, pero para la producción llevará mucho tiempo desarrollar una tabla de auditoría separada para cada tabla en la base de datos, escribir disparadores para cada tabla para capturar los cambios y escribirla en la tabla de auditoría. Además, es un gran desafío desarrollar un solo informe de auditoría para todas las tablas, ya que cada tabla de auditoría tiene una estructura diferente.
asim-ishaq
11
Si escribir y mantener scripts para cada tabla es una preocupación para una organización que tiene la intención de administrar una base de datos auditada, naturalmente recomendaría que contraten un DBA experimentado o un ingeniero de software altamente flexible y con mucha experiencia con la experiencia adecuada para crear bases de datos auditadas .
Hardryv
1
¿Es correcto que PageContent.PageIDsea ​​FK Page.IDy Page.CurrentRevisionFK PageContent.Revision? ¿Es esta dependencia realmente circular?
2
He votado en contra ya que no aborda las alternativas que se mencionan. Ofrece otra opción que es una solución muy específica para un caso de uso muy específico. Pero sí veo los méritos del diseño sugerido
acteon
1
Puedo pensar en muy pocos campos que podría decir con confianza que no cambiarán, por lo que todas las tablas "principales" para cada entidad terminarían siendo simplemente id, revision_id; más de una mesa de conexiones, de verdad. Esto me parece un poco maloliente. ¿Qué ventaja tiene esto sobre el enfoque 3 en OP (tabla de historial por tabla auditada)?
Kenmore
14

Si está utilizando SQL Server 2008, probablemente debería considerar Cambiar captura de datos. Esto es nuevo para 2008 y podría ahorrarle una cantidad considerable de trabajo.

Randy Minder
fuente
Aquí está el enlace a la información de seguimiento de cambios de SQL 2012. msdn.microsoft.com/en-us/library/bb933994.aspx +1 por usar la funcionalidad integrada, no tiene sentido reinventar la rueda.
Chris
44
@ Chris, ¿alguna vez lo has usado tú mismo? De hecho, rastrea todo ... pero ser capaz de obtener información útil es otra historia. No puedo usar una rueda de tractor para mi bicicleta.
Jowen
Esto realmente hubiera sido asombroso. Pero si solo tiene la edición estándar de SQL Server, como yo, no tiene suerte: "Cambiar la captura de datos solo está disponible en las ediciones Enterprise , Developer y Enterprise Evaluation ".
Brad Turek
6

No conozco ninguna referencia, pero estoy seguro de que alguien ha escrito algo.

Sin embargo, si el propósito es simplemente tener un registro de lo que sucedió, el uso más típico de un registro de auditoría, entonces ¿por qué no simplemente mantener todo:

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

Presumiblemente esto es mantenido por un disparador.

wallyk
fuente
No conozco ninguna forma de obtener eso dentro del servidor de la base de datos, pero, por supuesto, eso podría hacerse desde afuera con la suficiente facilidad.
wallyk
55
Me parece que este es el mismo patrón de diseño que la cuarta opción que se muestra en la pregunta original.
givanse
3

Crearemos una pequeña base de datos de ejemplo para una aplicación de blogs. Se requieren dos tablas:

blog: almacena una ID de publicación única, el título, el contenido y una marca eliminada. audit: almacena un conjunto básico de cambios históricos con un ID de registro, el ID de la publicación del blog, el tipo de cambio (NUEVO, EDITAR o ELIMINAR) y la fecha / hora de ese cambio. El siguiente SQL crea bloge indexa la columna eliminada:

CREATE TABLE `blog` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `title` text,
    `content` text,
    `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';

El siguiente SQL crea la audittabla. Todas las columnas están indexadas y se define una clave foránea para audit.blog_id que hace referencia a blog.id. Por lo tanto, cuando BORRAMOS físicamente una entrada de blog, también se elimina su historial de auditoría completo.

CREATE TABLE `audit` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `blog_id` mediumint(8) unsigned NOT NULL,
    `changetype` enum('NEW','EDIT','DELETE') NOT NULL,
    `changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ix_blog_id` (`blog_id`),
    KEY `ix_changetype` (`changetype`),
    KEY `ix_changetime` (`changetime`),
    CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ajit
fuente
2

Creo que no hay nada como un árbol de decisión. Dado que algunos de los pros y los contras (o los requisitos) no son realmente contables. ¿Cómo se mide la madurez, por ejemplo?

Tan solo alinee los requisitos de su negocio para su registro de auditoría. Intente predecir cómo estos requisitos podrían cambiar en el futuro y generar sus requisitos técnicos. Ahora puede compararlo con los pros y los contras y elegir la mejor opción.

Y tenga la seguridad de que no importa cómo decida, siempre habrá alguien que piense que tomó la decisión equivocada. Sin embargo, hizo su tarea y justificó su decisión.

Peter Schuetze
fuente