database - una - view lenta mysql
¿Cómo evitas agregar campos de marca de tiempo a tus tablas? (11)
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?
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)
TIMESTAMP: - {current timestamp} + { TABLE_UPDATED
, id_of_entry_updated
, timestamp_type
}
Tenga en cuenta que en este diseño no necesita esas dos columnas "adicionales" en su objeto de pago nativo (que, dicho sea de paso, podría llegar a través de su solución ORM) porque ahora está indexando por TABLE_UPDATED
e 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
Creo que las uniones extra 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.
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 buscas marcas de tiempo, es cuando estás depurando un problema en tu aplicación y querrás los datos allí mismo, en lugar de tener que unirte siempre a la otra mesa.
He utilizado un diseño en el que cada tabla para 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
)
Se crea un activador de base de datos que rellena NAME_AUDIT
cada vez que se hace algo con 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.
Hicimos exactamente lo que hiciste. 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.
Una desventaja es informar y / o mostrar muchas estampillas 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.
La ventaja del método que sugiere es que le ofrece la opción de agregar otros campos a su tabla TIMESTAMP, como hacer un seguimiento del usuario que realizó el cambio. También puede realizar un seguimiento de ediciones en campos confidenciales, por ejemplo, ¿quién cambió el precio de este contrato?
El registro de cambios en un archivo separado significa que puede mostrar varios cambios en un registro, como:
mm / dd / aa hh: mm: ss Agregado por XXX mm / dd / aa hh: mm: ss Campo PRECIO Modificado por XXX, mm / dd / aa hh: mm: ss Grabación borrada por XXX
Una desventaja es el código adicional que realizará inserta en su tabla TIMESTAMPS para reflejar los cambios en sus tablas principales.
Si configura el material de marca de tiempo para que se ejecute en desencadenadores, se puede registrar cualquier acción que pueda desencadenar un desencadenante (¿lecturas?). También puede haber algunas ventajas de bloqueo.
(Tome todo eso con un grano de sal, no soy DBA o gurú de SQL)
Sí, me gusta ese diseño y lo uso con algunos sistemas. Usualmente, 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
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.).
Los profesionales para esta solución son:
- ¡puede decir "qué y cuándo" y mostrarlo a sus usuarios! (Necesitará un código para analizar las declaraciones de SQL)
- si sus datos se replican y la replicación falla, puede reconstruir su base de datos a través de esta tabla
Contras son
- 100 000 actualizaciones de datos por mes significan 100 000 registros en Tbl_Transaction
- Finalmente, esta tabla tiende a ser el 99% de su volumen de base de datos
Nuestra elección: todos los registros anteriores a 90 días se eliminan automáticamente cada mañana
Philippe,
No elimine simplemente aquellos que tienen más de 90 días, muévalos primero a un DB separado o escríbalos en un archivo de texto, haga algo para preservarlos, simplemente extráigalos del DB de producción principal.
Si alguna vez se llega a eso, la mayoría de las veces se trata de "¡él con la mayor cantidad de documentación gana!"
Mientras lo hace, también registre al usuario que realizó el cambio.
El error 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 de 2008 admite algo que ellos llaman Change Data Capture
que debería quitarle mucho del dolor del que está hablando. Creo que Oracle puede tener algo similar también.
Actualización: aparentemente Oracle lo llama lo mismo que SQL Server. O, mejor dicho, SQL Server lo llama lo mismo que Oracle, ya que la implementación de Oracle fue lo primero;)
http://www.oracle.com/technology/oramag/oracle/03-nov/o63tech_bi.html
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 rompería 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 *.