Domanda

Supponiamo di avere una tabella di database con una colonna temporale dell'ultima volta che è stata aggiornata o inserita. Quale sarebbe preferibile:

  1. Avere un trigger per aggiornare il campo.
  2. Chiedi al programma che sta eseguendo l'inserimento / aggiornamento di impostare il campo.

La prima opzione sembra essere la più semplice poiché non devo nemmeno ricompilare per farlo, ma non è un grosso problema. A parte questo, ho problemi a pensare a qualsiasi motivo per fare l'uno sull'altro. Qualche suggerimento?

È stato utile?

Soluzione

La prima opzione può essere più solida perché il database manterrà il campo. Ciò comporta il possibile sovraccarico dell'utilizzo dei trigger.

Se in futuro potessi avere altre app che scrivono su questa tabella, tramite le loro interfacce, farei un trigger in modo da non ripetere quella logica da nessun'altra parte.

Se la tua app è praticamente uguale, o qualsiasi altra app accedesse al database tramite lo stesso datalayer, eviterei quell'incubo che i trigger possono indurre e mettere la logica direttamente nel tuo datalayer (SQL, ORM, processi memorizzati , eccetera.).

Ovviamente dovresti assicurarti che l'origine temporale (la tua app, i pc degli utenti, il tuo server SQL) sia accurata in entrambi i casi.


Per quanto riguarda il motivo per cui non mi piacciono i trigger:

Forse sono stato avventato chiamandoli un incubo. Come tutto il resto, sono appropriati con moderazione. Se li usi per cose molto semplici come questa, potrei salire a bordo.

È quando il codice del trigger diventa complesso (e costoso) che i trigger iniziano a causare molti problemi. Sono una tassa nascosta su ogni query di inserimento / aggiornamento / eliminazione eseguita (a seconda del tipo di trigger). Se tale imposta è accettabile, possono essere lo strumento giusto per il lavoro.

Altri suggerimenti

Non hai menzionato 3. Utilizzare una procedura memorizzata per aggiornare la tabella. La procedura può impostare i timestamp come desiderato.

Forse non è fattibile per te, ma non l'ho visto menzionato.

Direi trigger nel caso in cui qualcuno usi qualcosa oltre alla tua app per aggiornare la tabella, probabilmente vorrai anche avere un LastUpdatedBy e usare SUSER_SNAME (), in questo modo puoi vedere chi ha fatto l'aggiornamento

Fintanto che sto usando un DBMS di cui mi fido i trigger, andrei sempre con l'opzione trigger. Permette al DBMS di occuparsi del maggior numero di cose possibile, il che di solito è una buona cosa.

Funziona assicurandosi in ogni caso che la colonna timestamp abbia il valore corretto. Il sovraccarico sarebbe trascurabile.

L'unica cosa che sarebbe contro i trigger è la portabilità. Se questo non è un problema, non penso che ci sia una domanda su quale direzione andare.

Sono un sostenitore delle procedure memorizzate per tutto. Il tuo proc di aggiornamento potrebbe contenere un GETDATE () per la colonna.

E non mi piacciono i trigger per questo tipo di aggiornamento. La mancanza di visibilità dei trigger tende a creare confusione.

Mi sembra una logica aziendale ... Sarei più disposto a inserire questo nel codice. Consenti al database di gestire la memorizzazione dei dati ... Niente di più e niente di meno.

I trigger sono una benedizione e una maledizione.

Benedizione: puoi usarli per abilitare tutti i tipi di controllo personalizzato dei vincoli e la gestione dei dati senza conoscenza o modifiche dei sistemi di backend.

Maledizione: non sai cosa sta succedendo alle tue spalle. Problemi di concorrenza / deadlock causati da oggetti aggiuntivi portati in transazioni che non erano inizialmente previste. Comportamento fantasma tra cui modifiche dell'ambiente di sessione, conteggi delle righe inaffidabili. Innesco eccessivo di condizioni ... hotspot aggiuntivo / penalità di prestazione.

La risposta a questa domanda (Aggiorna le date implicitamente (trigger) o esplicitamente (codice)) di solito pesa pesantemente sul contesto. Ad esempio, se si utilizza la data dell'ultima modifica come campo informativo, è possibile che si desideri modificarla solo quando un "utente" in realtà apporta modifiche salienti a una riga rispetto a un processo automatizzato che aggiorna semplicemente una sorta di marker interno a cui non interessa .

Se si utilizza il trigger per la sincronizzazione delle modifiche o non si ha alcun controllo sul codice che esegue un trigger ha molto più senso.

Il mio consiglio sul grilletto lo usa per fare attenzione. La maggior parte dei sistemi consente di filtrare l'esecuzione in base all'operazione e ai campi modificati. L'uso corretto dei trigger "prima" vs "dopo" può avere un impatto significativo sulle prestazioni.

Infine, alcuni sistemi sono in grado di eseguire un singolo trigger su più modifiche (più righe effettuate all'interno di una transazione) il codice deve essere preparato per applicarsi come aggiornamento in blocco a più righe.

Normalmente direi lato database, ma dipende dalla tua applicazione. Se stai usando LINQ-to-SQL puoi semplicemente impostare il campo come Timestamp e far sì che il DAL utilizzi il campo Timestamp per la concorrenza. Lo gestisce automaticamente, quindi dover ripetere il codice non è un evento.

Se stai scrivendo il tuo DAL da solo, allora sarei più propenso a gestirlo sul lato del database in quanto rende la scrittura delle interfacce utente molto più flessibile - anche se, probabilmente lo farei in una procedura memorizzata che ha " pubblico " accesso e tabelle bloccate - non vuoi che arrivi alcun clown che ignori la tua procedura memorizzata scrivendo direttamente alle tabelle ... a meno che non preveda di rendere il DAL un componente autonomo che qualsiasi applicazione futura dovrà utilizzare per accedere al database, nel qual caso, potresti codificarlo direttamente nel DAL - ovviamente, dovresti farlo solo se puoi garantire che chiunque acceda al database lo stia facendo attraverso il tuo componente DAL.

Se hai intenzione di consentire " pubblico " accesso al database da inserire nelle tabelle, quindi dovrai usare il trigger perché altrimenti chiunque può inserire / aggiornare un singolo campo nella tabella e il campo aggiornato non potrebbe mai essere aggiornato.

Vorrei mantenere la data nel database, ovvero un trigger, una procedura memorizzata, ecc. Nella maggior parte delle applicazioni basate su database l'app utente non sarà l'unico mezzo con cui gli utenti aziendali ottengono i dati . Ci sono strumenti di reporting, estratti, SQL utente, ecc. Ci sono anche aggiornamenti e correzioni che vengono effettuati dal DBA per cui l'applicazione non fornirà anche la data.

Ma onestamente il motivo numero 1 non lo farei dall'applicazione è che non hai alcun controllo sulla data / ora sul computer client. Potrebbero tornare indietro per ottenere più giorni da una licenza di prova su qualcosa o potrebbero semplicemente voler fare cose cattive per il tuo programma.

Puoi farlo senza il trigger se il tuo database supporta i valori predefiniti nei campi. Ad esempio, in SQL Server 2005 ho una tabella con un campo creato in questo modo:

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

quindi il codice di inserimento lascia quel campo fuori dall'elenco dei campi di inserimento.

Ho dimenticato che ha funzionato solo per il primo inserimento - ho anche un trigger di aggiornamento, per aggiornare i campi della data e inserire una copia del record aggiornato nella mia tabella della cronologia - che pubblicherei ... ma l'editor continua a sbagliare sul mio codice ...

Infine:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top