2008-09-30 17 views
14

Tengo una pregunta con respecto a las dos columnas adicionales (timeCreated, timeLastUpdated) para cada registro que vemos en muchas soluciones. Mi pregunta: ¿hay una mejor alternativa?¿Cómo evitas agregar campos de marca de tiempo a tus tablas?

Escenario: tiene una gran base de datos (en términos de tablas, no registros), y luego el cliente viene y le pide que agregue "marca de tiempo" al 80% de sus tablas.

Creo que esto se puede lograr usando una tabla separada (TIMESTAMPS). Esta tabla tendría, además de la columna obvia de marcas de tiempo, el nombre de la tabla y la clave principal de la tabla que se está actualizando. (Supongo que aquí utiliza una int como clave principal para la mayoría de las tablas, pero el nombre de la tabla probablemente debería ser una cadena).

Para imaginar esto, suponga este escenario básico. Tendríamos dos tablas:

PAGO: - (sus registros habituales)
Hora: - {fecha y hora actual} + {TABLE_UPDATED, id_of_entry_updated, timestamp_type}

en cuenta que en este diseño que no necesita los dos columnas "extra" en su objeto de pago nativo (que, dicho sea de paso, podrían llegar a través de su solución ORM) porque ahora está indexando por TABLE_UPDATED y id_of_entry_updated. Además, timestamp_type le dirá si la entrada es para inserción (por ejemplo, "1"), actualización (por ejemplo, "2") y cualquier otra cosa que desee agregar, como "eliminación".

Me gustaría saber qué piensas de este diseño. Estoy muy interesado en las mejores prácticas, lo que funciona y escalas en el tiempo. Referencias, enlaces, entradas de blog son más que bienvenidas. Conozco al menos una patente (pendiente) que trata de resolver este problema, pero parece que los detalles no son públicos en este momento.

Saludos, Eduardo

Respuesta

12

Mientras tanto, registre también al usuario que realizó el cambio.

La falla con el diseño de mesa separada (además del rendimiento de combinación resaltado por otros) es que supone que cada tabla tiene una columna de identidad para la clave. Eso no siempre es cierto.

Si usa SQL Server, la nueva versión 2008 es compatible con algo que llaman Change Data Capture que debería quitar mucho del dolor del que está hablando. Creo que Oracle puede tener algo similar también.


Actualización: Al parecer, Oracle lo llama lo mismo que SQL Server. O mejor dicho, SQL Server llama lo mismo que Oracle, desde la implementación de Oracle fue primero;)
http://www.oracle.com/technology/oramag/oracle/03-nov/o63tech_bi.html

+0

Esta es la publicación más feliz que alguna vez me ha hecho. Me estaba preparando para escribir una publicación que deseara exactamente esto. No creo que Oracle tenga algo como esto. Si lo hace, voy a patearme a mí mismo. – MusiGenesis

+0

Me enojo pensando en todo el tiempo que he perdido al agregar los campos ModifiedBy y CreatedDateTime a mis tablas. – MusiGenesis

+0

Uh, sí, Oracle ha tenido esto durante años. –

1

La ventaja del método que sugerimos es que se le da la opción de agregar otros campos a su mesa TIMESTAMP, como el seguimiento del usuario que realizó el cambio. También puede realizar un seguimiento de las ediciones en campos confidenciales, por ejemplo, ¿quién modificó el precio de este contrato?

registro de anotaciones cambios en un archivo separado significa que puede mostrar varios cambios en un registro, como:

mm hh/DD/AA: mm: ss Añadido por XXX dd/mm/aa hh: mm: PRECIO ss campo modificado por XXX, dd/mm/aa hh: mm: ss Registro eliminado por XXX

Una desventaja adicional es el código de la voluntad realizar inserciones en la tabla de marcas de tiempo para reflejar los cambios en las tablas principales.

5

Creo que prefiero agregar las marcas de tiempo a las tablas individuales. Unirse a tu tabla de marca de tiempo en una clave compuesta, una de las cuales es una cadena, va a ser más lenta y si tienes una gran cantidad de datos eventualmente será un problema real.

Además, muchas veces cuando mira las marcas de tiempo, es cuando está depurando un problema en su aplicación y querrá los datos allí mismo, en lugar de tener que unirse siempre contra la otra tabla.

+0

la unión no necesitará utilizar la cadena como parte de la cláusula "ON". Si es la primera parte de un índice, solo se puede verificar una vez por consulta, dependiendo de qué tan bueno sea el optimizador. – BCS

+0

Pero si está almacenando marcas de tiempo de diferentes tablas en una gran tabla TIMESTAMP, necesitará diferenciar las marcas de tiempo de INVOICE de, por ejemplo, marcas de tiempo USERACCOUNT, por lo que no tendrá que ser: ON TIMESTAMP.id_of_entry Y tablename = 'INVOICE ¿? – Dana

+0

Creo que tienes razón, Dana. Sin embargo, dado que los nombres de tabla son únicos, ¿cree que puedo salirse con la suya con un hash simple (como usar la representación ascii de los nombres de tabla para convertirlo en un int)? De esta forma terminaría indizando en dos campos int. ¿Qué piensas? – esegura

0

Creo que las uniones adicionales que tendrá que realizar para obtener las marcas de tiempo serán un golpe de rendimiento leve y un dolor en el cuello. Aparte de eso, no veo ningún problema.

1

Si configura el material de sello de tiempo para funcionar fuera de disparadores, que cualquier acción que puede desencadenar una desencadenar (¿Lee?) puede registrarse. También puede haber algunas ventajas de bloqueo.

(Tome todo eso con un grano de sal, no soy un DBA o SQL gurú)

10

He utilizado un diseño donde cada tabla a auditar tenía dos tablas:

create table NAME (
    name_id int, 
    first_name varchar 
    last_name varchar 
    -- any other table/column constraints 
) 

create table NAME_AUDIT (
    name_audit_id int 
    name_id int 
    first_name varchar 
    last_name varchar 
    update_type char(1) -- 'U', 'D', 'C' 
    update_date datetime 
    -- no table constraints really, outside of name_audit_id as PK 
) 

A Se ha creado un disparador de base de datos que rellena NAME_AUDIT cada vez que se hace algo al NAME. De esta forma, tiene un registro de cada cambio realizado en la mesa y cuándo. La aplicación no tiene conocimiento real de esto, ya que es mantenido por un disparador de base de datos.

Funciona razonablemente bien y no requiere ningún cambio en el código de la aplicación para implementar.

+0

+1 la gran ventaja aquí es que las tablas de auditoría se pueden agregar más adelante sin cambios en el esquema que están auditando; gracias, me preguntaba cómo lograr esto para un DB que estoy construyendo! – jcollum

1

Sí, me gusta ese diseño y lo uso con algunos sistemas. Por lo general, alguna variante de:

LogID int 
Action varchar(1)  -- ADDED (A)/UPDATED (U)/DELETED (D) 
UserID varchar(20) -- UserID of culprit :) 
Timestamp datetime -- Date/Time 
TableName varchar(50) -- Table Name or Stored Procedure ran 
UniqueID int   -- Unique ID of record acted upon 
Notes varchar(1000) -- Other notes Stored Procedure or Application may provide 
0

Hicimos exactamente lo que usted hizo. Es ideal para el modelo de objetos y la capacidad de agregar nuevos sellos y diferentes tipos de sellos a nuestro modelo con un código mínimo. También estábamos rastreando al usuario que realizó el cambio, y gran parte de nuestra lógica se basó en gran medida en estos sellos. Se ejecutó muy bien.

Un inconveniente es informar y/o mostrar muchos sellos diferentes en la pantalla. Si lo haces de la manera en que lo hicimos, causó muchas combinaciones. Además, los cambios de final de espalda fueron un dolor.

0

Nuestra solución es mantener una tabla de "Transacción", además de nuestra tabla de "Sesión". Las instrucciones UPDATE, INSERT y DELETE se administran a través de un objeto "Transaction" y cada una de estas instrucciones SQL se almacena en la tabla "Transaction" una vez que se ha ejecutado correctamente en la base de datos. Esta tabla "Transaction" tiene otros campos como transactiontType (I para INSERT, D para DELETE, U para UPDATE), transactionDateTime, etc., y una clave externa "sessionId", que nos dice finalmente quién envió la instrucción. Incluso es posible, a través de algún código, identificar quién hizo qué y cuándo (Gus creó el registro el lunes, Tim cambió el Precio unitario el martes, Liz agregó un descuento adicional el jueves, etc.).

Pros para esta solución son:

  1. eres capaz de decir "qué a quién y cuándo", y mostrarlo a sus usuarios! (Necesitará algo de código para analizar las sentencias SQL)
  2. si se replica sus datos, y se produce un error de replicación, puede reconstruir su base de datos a través de esta tabla

Contras son

  1. 100 000 datos actualizaciones al mes significan 100 000 registros en Tbl_Transaction
  2. por último, esta tabla tiende a ser el 99% de su volumen de base de datos

Nuestra cho hielo: todos los registros de más de 90 días se eliminan automáticamente todas las mañanas

-1

Philippe,

no se limitan a eliminar los mayores de 90 días, moverlos primero en una base de datos separada o escribirlos en un archivo de texto, hacer algo para preservarlos, simplemente elimínalos de la base de datos principal de producción.

Si alguna vez se llega a la conclusión, la mayoría de las veces es un caso de "él con la mayor cantidad de documentación gana".

1

Una pesadilla con su diseño es que cada inserción, actualización o eliminación debería golpear esa mesa. Esto puede causar problemas importantes de rendimiento y bloqueo. Es una mala idea generalizar una tabla como esa (no solo para las marcas de tiempo). También sería una pesadilla sacar los datos.

Si su código se descompone en el nivel de la GUI al agregar campos que no desea que el usuario vea, está escribiendo incorrectamente el código en su GUI que debe especificar solo el número mínimo de columnas que necesita y nunca seleccionar * .

Cuestiones relacionadas