Pregunta

Supongamos que tengo una tabla de base de datos que tiene una columna de fecha y hora de la última vez que se actualizó o insertó. Lo que sería preferible:

  1. Haz que un activador actualice el campo.
  2. Haga que el programa que está haciendo la inserción / actualización establezca el campo.

La primera opción parece ser la más fácil ya que ni siquiera tengo que volver a compilar para hacerlo, pero eso no es realmente un gran problema. Aparte de eso, tengo problemas para pensar en alguna razón para hacer una sobre la otra. ¿Alguna sugerencia?

¿Fue útil?

Solución

La primera opción puede ser más robusta porque la base de datos mantendrá el campo. Esto viene con la posible sobrecarga de usar desencadenadores.

Si pudieras tener otras aplicaciones escribiendo en esta tabla en el futuro, a través de sus propias interfaces, me gustaría utilizar un disparador para que no repitas esa lógica en ningún otro lugar.

Si su aplicación lo es, o cualquier otra aplicación accedería a la base de datos a través del mismo nivel de datos, evitaría que la pesadilla que los activadores pueden inducir y colocar la lógica directamente en su nivel de datos (SQL, ORM, procesos almacenados). , etc.).

Por supuesto, tendría que asegurarse de que su fuente de tiempo (su aplicación, las PC de sus usuarios, su servidor SQL) sea correcta en cualquier caso.


En cuanto a por qué no me gustan los desencadenantes:

Tal vez fui precipitado llamándolos una pesadilla. Como todo lo demás, son apropiados en moderación. Si los usas para cosas muy simples como esta, podría subir a bordo.

Es cuando el código de activación se vuelve complejo (y costoso) que los activadores comienzan a causar muchos problemas. Son un impuesto oculto en cada consulta de inserción / actualización / eliminación que ejecute (según el tipo de activador). Si ese impuesto es aceptable, entonces pueden ser la herramienta adecuada para el trabajo.

Otros consejos

No mencionaste 3. Use un procedimiento almacenado para actualizar la tabla. El procedimiento puede establecer las marcas de tiempo como se desee.

Quizás eso no sea factible para ti, pero no lo vi mencionado.

Yo diría que se dispara en caso de que alguien use algo además de tu aplicación para actualizar la tabla, probablemente también quieras tener un LastUpdatedBy y usar SUSER_SNAME () para eso, de esta manera puedes ver quién hizo la actualización

Mientras esté usando un DBMS en cuyos activadores confío, siempre optaré por la opción de activación. Permite que el DBMS se ocupe de tantas cosas como sea posible, lo que generalmente es bueno.

Funciona asegúrese de que bajo cualquier circunstancia la columna de marca de tiempo tenga el valor correcto. Los gastos generales serían despreciables.

Lo único que estaría en contra de los disparadores es la portabilidad. Si eso no es un problema, no creo que haya una pregunta a qué dirección ir.

Soy un defensor de los procedimientos almacenados para todo. El proceso de actualización podría contener un GETDATE () para la columna.

Y no me gustan los activadores para este tipo de actualización. La falta de visibilidad de los factores desencadenantes tiende a causar confusión.

Esto me parece una lógica de negocios ... Estaría más dispuesto a poner esto en el código. Deje que la base de datos administre el almacenamiento de datos ... ni más ni menos.

Los disparadores son una bendición y una maldición.

Bendición: puede usarlos para habilitar todo tipo de control de restricciones personalizado y administración de datos sin el conocimiento o los cambios de los sistemas de fondo.

Maldición: no sabes qué está pasando detrás de tu espalda. Problemas de concurrencia / puntos muertos por objetos adicionales introducidos en transacciones que originalmente no se esperaban. Comportamiento fantasma que incluye cambios en el entorno de sesión, recuentos de filas no confiables. Activación excesiva de condiciones ... hotspot adicionales / penalizaciones de rendimiento.

La respuesta a esta pregunta (Actualizar fechas implícitamente (disparador) o explícitamente (código)) usualmente tiene una fuerte carga en el contexto. Por ejemplo, si está utilizando la última fecha de cambio como un campo informativo, es posible que solo desee cambiarla cuando un 'usuario' realmente haga cambios importantes en una fila en comparación con un proceso automatizado que simplemente actualiza algún tipo de marcador interno que a los usuarios no les importa .

Si está utilizando el activador para cambiar la sincronización o no tiene control sobre el código que ejecuta un activador tiene mucho más sentido.

Mi consejo sobre el gatillo lo usa para tener cuidado. La mayoría de los sistemas le permiten filtrar la ejecución según la operación y los campos cambiados. El uso adecuado de los activadores "antes" y "después" puede tener un impacto significativo en el rendimiento.

Finalmente, algunos sistemas son capaces de ejecutar un único activador en múltiples cambios (varias filas efectuadas dentro de una transacción) su código debe estar preparado para aplicarse como una actualización masiva de varias filas.

Normalmente diría que hágalo de la base de datos, pero depende de su aplicación. Si está utilizando LINQ-to-SQL, puede configurar el campo como marca de hora y hacer que su DAL use el campo de marca de hora para la concurrencia. Se lo maneja automáticamente, por lo que tener que repetir el código no es un evento.

Sin embargo, si está escribiendo su DAL usted mismo, entonces es más probable que maneje esto en el lado de la base de datos, ya que hace que las interfaces de usuario sean mucho más flexibles, aunque es probable que haga esto en un procedimiento almacenado que tiene " público " acceso y las tablas bloqueadas: no desea que aparezca ningún payaso que pase por alto su procedimiento almacenado escribiendo directamente en las tablas ... a menos que piense que su DAL sea un componente independiente que cualquier aplicación futura debe usar para acceder al La base de datos, en cuyo caso, podría codificarla directamente en el DAL. Por supuesto, solo debe hacer esto si puede garantizar que todos los que accedan a la base de datos lo hagan a través de su componente DAL.

Si vas a permitir " público " acceda a la base de datos para insertarla en las tablas, luego tendrá que ir con el activador porque de lo contrario, cualquier persona puede insertar / actualizar un solo campo en la tabla y el campo actualizado nunca podría actualizarse.

Mantendría la fecha en la base de datos, es decir, un desencadenante, un procedimiento almacenado, etc. En la mayoría de las aplicaciones basadas en la base de datos, la aplicación de usuario no será el único medio por el cual los usuarios comerciales obtienen datos. . Hay herramientas de informes, extractos, SQL de usuario, etc. También hay actualizaciones y correcciones que realiza el DBA para las cuales la aplicación tampoco proporcionará la fecha.

Pero honestamente, la razón número 1 por la que no lo haría desde la aplicación es que no tiene control sobre la fecha / hora en la máquina cliente. Es posible que lo estén devolviendo para obtener más días de una licencia de prueba de algo o que simplemente quieran hacerle cosas malas a su programa.

Puede hacer esto sin el desencadenador si su base de datos admite valores predeterminados en los campos. Por ejemplo, en SQL Server 2005 tengo una tabla con un campo creado así:

create table dbo.Repository
   (
    ...
   last_updated     datetime default getdate(),
    ...
   )

entonces el código de inserción simplemente deja ese campo fuera de la lista de campos de inserción.

Olvidé que solo funcionó para la primera inserción; también tengo un activador de actualización, para actualizar los campos de fecha y poner una copia del registro actualizado en mi tabla de historial, que publicaría ... pero el editor sigue cometiendo errores en mi código ...

Finalmente:

create trigger dbo.Repository_Upd on dbo.Repository instead of update
as
--**************************************************************************
--   Trigger: Repository_Upd
--    Author: Ron Savage
--      Date: 09/28/2008
--
-- Description:
-- This trigger sets the last_updated and updated_by fields before the update
-- and puts a copy of the updated row into the Repository_History table.
--
-- Modification History:
-- Date        Init  Comment
-- 10/22/2008  RS    Blocked .prm files from updating the history as they
--                   get updated every time the cfg file is run.
-- 10/21/2008  RS    Updated the insert into the history table to use the
--                   d.last_updated field from the Repository table rather
--                   than getdate() to avoid micro second differences.
-- 09/28/2008  RS    Created.
--**************************************************************************
begin
   --***********************************************************************
   -- Update the record but fill in the updated_by, updated_system and
   -- last_updated date with current information.
   --***********************************************************************
   update cr set
      cr.filename           = i.filename,
      cr.created_by         = i.created_by,
      cr.created_system     = i.created_system,
      cr.create_date        = i.create_date,
      cr.updated_by         = user,
      cr.updated_system     = host_name(),
      cr.last_updated       = getdate(),
      cr.content            = i.content
   from
      Repository cr

      JOIN Inserted i
         on (i.config_id = cr.config_id);


   --***********************************************************************
   -- Put a copy in the history table
   --***********************************************************************
   declare @extention varchar(3);
   select @extention = lower(right(filename,3)) from Inserted;

   if (@extention <> 'prm')
      begin
      Insert into Repository_History
         select
            i.config_id,
            i.filename,
            i.created_by,
            i.created_system,
            i.create_date,
            user           as updated_by,
            host_name()    as updated_system,
            d.last_updated,
            d.content
         from
            Inserted i

            JOIN Repository d
               on (d.config_id = i.config_id);
      end
end

Ron

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top