2009-03-19 12 views
6

Per la prima volta devo utilizzare i trigger in MSSQL, in generale i trigger dei pozzetti. Dopo aver letto e provato questo, mi rendo conto ora che un trigger si attiva per comando e non per riga inserita, cancellata o aggiornata.Gestione di più record in un trigger MS SQL

L'intera cosa è alcune statistiche per un sistema pubblicitario. La nostra tabella stat principale è piuttosto grande e non contiene i dati in un modo che ha senso nella maggior parte dei casi. Contiene una riga per annuncio cliccato, visualizzato ed ecc. Come utente uno è più incline a voler vedere questo come giorno X ha quantità Y di clic e quantità Z di visualizzazioni e così via. Lo abbiamo fatto basandoci solo su una query SQL fino ad ora, ottenendo questo tipo di report dalla tabella principale, ma man mano che la tabella è cresciuta, anche il tempo per la query da eseguire. Per questo motivo abbiamo optato per l'uso dei trigger per mantenere aggiornata un'altra tabella e, quindi, semplificarla leggermente sul server SQL.

Il mio problema è ora di farlo funzionare con più record. Quello che ho fatto è creare 2 stored procedure, una per la gestione del funzionamento di un inserto e una per l'eliminazione. Il mio trigger di inserimento (scritto per funzionare con un singolo record), quindi cattura i dati dalla tabella inserita e li invia alla stored procedure. Il trigger di eliminazione funziona allo stesso modo e (ovviamente?) Il trigger di aggiornamento fa la stessa cosa di delete + un insert.

Il mio problema è ora come fare al meglio con più record. Ho provato ad usare un cursore, ma per quanto sono stato in grado di leggere e vedere me stesso, questo si comporta davvero male. Ho preso in considerazione di scrivere anche alcuni "controlli", come nel verificare se ci sono più record nei comandi e poi andare con il cursore, altrimenti semplicemente evitarlo. Comunque, ecco la mia soluzione con un cursore, e mi chiedo se c'è un modo per farlo meglio?

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @Date DATE 
    DECLARE @CampaignId BIGINT 
    DECLARE @CampaignName varchar(500) 
    DECLARE @AdvertiserId BIGINT 
    DECLARE @PublisherId BIGINT 
    DECLARE @Unique BIT 
    DECLARE @Approved BIT 
    DECLARE @PublisherEarning money 
    DECLARE @AdvertiserCost money 
    DECLARE @Type smallint 

    DECLARE InsertCursor CURSOR FOR SELECT Id FROM Inserted 
    DECLARE @curId bigint 

    OPEN InsertCursor 

    FETCH NEXT FROM InsertCursor INTO @curId 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     SELECT @Date = [Date], @PublisherId = [PublisherCustomerId], @Approved = [Approved], @Unique = [Unique], @Type = [Type], @AdvertiserCost = AdvertiserCost, @PublisherEarning = PublisherEarning 
     FROM Inserted 
     WHERE Id = @curId 

     SELECT @CampaignId = T1.CampaignId, @CampaignName = T2.Name, @AdvertiserId = T2.CustomerId 
     FROM Advert AS T1 
     INNER JOIN Campaign AS T2 on T1.CampaignId = T2.Id 
     WHERE T1.Id = (SELECT AdvertId FROM Inserted WHERE Id = @curId) 

     EXEC ProcStatInsertTrigger @Date, @CampaignId, @CampaignName, @AdvertiserId, @PublisherId, @Unique, @Approved, @PublisherEarning, @AdvertiserCost, @Type 

     FETCH NEXT FROM InsertCursor INTO @curId 
    END 

    CLOSE InsertCursor 
    DEALLOCATE InsertCursor 
END 

La stored procedure è piuttosto grande e intenso e non credo ci sia un modo di dover evitare il loop tra i record della tabella inserita in un modo o nell'altro (ok, forse c'è, ma io' Mi piacerebbe anche essere in grado di leggere il codice: p), quindi non ti annoierò con quello (a meno che non ti piaccia pensare diversamente). Quindi, praticamente, c'è un modo migliore per farlo, e se sì, come?

EDIT: Beh dopo la richiesta, ecco la sproc

CREATE PROCEDURE ProcStatInsertTrigger 
    @Date DATE, 
    @CampaignId BIGINT, 
    @CampaignName varchar(500), 
    @AdvertiserId BIGINT, 
    @PublisherId BIGINT, 
    @Unique BIT, 
    @Approved BIT, 
    @PublisherEarning money, 
    @AdvertiserCost money, 
    @Type smallint 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 
IF @Approved = 1 
     BEGIN 
      DECLARE @test bit 

      SELECT @test = 1 FROM CachedStats WHERE [Date] = @Date AND CampaignId = @CampaignId AND CustomerId = @PublisherId 

      IF @test IS NULL 
       BEGIN 
        INSERT INTO CachedStats ([Date], CustomerId, CampaignId, CampaignName) VALUES (@Date, @PublisherId, @CampaignId, @CampaignName) 
       END 

      SELECT @test = NULL 

        DECLARE @Clicks int 
        DECLARE @TotalAdvertiserCost money 
        DECLARE @TotalPublisherEarning money 
        DECLARE @PublisherCPC money 
        DECLARE @AdvertiserCPC money 

        SELECT @Clicks = Clicks, @TotalAdvertiserCost = AdvertiserCost + @AdvertiserCost, @TotalPublisherEarning = PublisherEarning + @PublisherEarning FROM CachedStats 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 

        IF @Type = 0 -- If click add one to the calculation 
         BEGIN 
          SELECT @Clicks = @Clicks + 1 
         END 

        IF @Clicks > 0 
         BEGIN 
          SELECT @PublisherCPC = @TotalPublisherEarning/@Clicks, @AdvertiserCPC = @TotalAdvertiserCost/@Clicks 
         END 
        ELSE 
         BEGIN 
          SELECT @PublisherCPC = 0, @AdvertiserCPC = 0 
         END 
      IF @Type = 0 
       BEGIN 

        UPDATE CachedStats SET 
         Clicks = @Clicks, 
         UniqueClicks = UniqueClicks + @Unique, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         PublisherCPC = @PublisherCPC, 
         AdvertiserCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 
       END 
      ELSE IF @Type = 1 OR @Type = 4 -- lead or coreg 
       BEGIN 
        UPDATE CachedStats SET 
         Leads = Leads + 1, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         AdvertiserCPC = @AdvertiserCPC, 
         PublisherCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 
       END 
      ELSE IF @Type = 3 -- Isale 
       BEGIN 
        UPDATE CachedStats SET 
         Leads = Leads + 1, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         AdvertiserCPC = @AdvertiserCPC, 
         PublisherCPC = @AdvertiserCPC, 
         AdvertiserOrderValue = @AdvertiserCost, 
         PublisherOrderValue = @PublisherEarning 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId     
       END 
      ELSE IF @Type = 2 -- View 
       BEGIN 
        UPDATE CachedStats SET 
         [Views] = [Views] + 1, 
         UniqueViews = UniqueViews + @Unique, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         PublisherCPC = @PublisherCPC, 
         AdvertiserCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId   
       END 
     END 
END 

Dopo aiuto, ecco il mio risultato finale, pubblicato nel caso in cui gli altri hanno un problema simile

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 

    SET NOCOUNT ON 

    -- insert all missing "CachedStats" rows 
    INSERT INTO 
     CachedStats ([Date], AdvertId, CustomerId, CampaignId, CampaignName) 
    SELECT DISTINCT 
     CONVERT(Date, i.[Date]), i.AdvertId, i.[PublisherCustomerId], c.Id, c.Name 
    FROM 
     Inserted i 
     INNER JOIN Advert AS a ON a.Id = i.AdvertId 
     INNER JOIN Campaign AS c ON c.Id = a.CampaignId 
    WHERE 
     i.[Approved] = 1 
     AND NOT EXISTS (
       SELECT 1 
       FROM CachedStats as t 
       WHERE 
         [Date] = CONVERT(Date, i.[Date]) 
         AND CampaignId = c.Id 
         AND CustomerId = i.[PublisherCustomerId] 
         AND t.AdvertId = i.AdvertId 
     ) 

    -- update all affected records at once 
    UPDATE 
     CachedStats 
    SET 
     Clicks = 
      Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      ), 
     UniqueClicks = 
      UniqueClicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      ), 
     [Views] = 
      [Views] + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 2 
      ), 
     UniqueViews = 
      UniqueViews + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 2 
      ), 
     Leads = 
      Leads + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] IN (1,3,4) 
      ), 
     PublisherEarning = 
      CachedStats.PublisherEarning + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   

      ), 0), 
     AdvertiserCost = 
      CachedStats.AdvertiserCost + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
      ), 0), 
     PublisherOrderValue = 
      PublisherOrderValue + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 3    
      ), 0), 
     AdvertiserOrderValue = 
      AdvertiserOrderValue + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
       AND s.[Type] = 3 
      ), 0), 
     PublisherCPC = 
      CASE WHEN (Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      )) > 0 THEN 
       (CachedStats.PublisherEarning + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
      ), 0)) -- COST^
       /(
        Clicks + (
         SELECT COUNT(*) FROM Inserted s 
         WHERE s.Approved = 1 
         AND s.PublisherCustomerId = i.PublisherCustomerId 
         AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
         AND s.AdvertId = i.AdvertId 
         AND s.[Type] = 0 
        )    
       ) --- Clicks^
      ELSE 
       0 
      END,  
     AdvertiserCPC = 
      CASE WHEN (Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      )) > 0 THEN 
       (CachedStats.AdvertiserCost + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
      ), 0)) -- COST^
       /(
        Clicks + (
         SELECT COUNT(*) FROM Inserted s 
         WHERE s.Approved = 1 
         AND s.PublisherCustomerId = i.PublisherCustomerId 
         AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
         AND s.AdvertId = i.AdvertId 
         AND s.[Type] = 0 
        )    
       ) --- Clicks^
      ELSE 
       0 
      END  
    FROM 
     Inserted i 
    WHERE 
     i.Approved = 1 AND 
     CachedStats.Advertid = i.AdvertId AND 
     CachedStats.[Date] = Convert(Date, i.[Date]) AND 
     CachedStats.CustomerId = i.PublisherCustomerId 
    SET NOCOUNT OFF 
END 

Sembra leggermente diverso adesso perché ha dovuto indicizzarlo anche per annuncio - ma grazie mille per l'aiuto - ha accelerato tutto da 30 ore a 30 secondi per generare CachedStats dalla mia tabella Stat di sviluppo :)

+0

Puoi dirci cosa fa "ProcStatInsertTrigger"? (BTW: non dovresti nominare un "trigger" sproc, per ragioni piuttosto ovvie). Se non fa molto di più che inserire dati in una tabella, c'è un modo per semplificare notevolmente l'approccio. – Tomalak

+0

Grazie per aver pubblicato la versione finale. :) Tuttavia non sono sicuro che sia ottimale - si eseguono molti sottoselezioni apparentemente ridondanti che possono essere disegnati e calcolati dal risultato di join, IMHO. – Tomalak

+0

Mi piacerebbe tanto sbarazzarmi di quelli. Tuttavia, dato che non sono un Guru SQL, non ho idea di come. Se tu potessi indicarmi la strada, mi piacerebbe ottimizzarlo ulteriormente. Inoltre, sarebbe meglio che le prestazioni facciano un controllo per vedere se ci sono più file e se non farlo come prima? – kastermester

risposta

8

Il trucco con questo tipo di situazioni è di attivare l'operazione sequenziale (per ogni record fare xyz) in un'operazione basata su set (un'istruzione UPDATE).

Ho analizzato la procedura memorizzata e unito le istruzioni UPDATE separate in una singola. Questa singola istruzione può quindi essere trasformata in una versione che può essere applicata a tutti i record inseriti contemporaneamente, eliminando la necessità di una stored procedure e quindi della necessità di un cursore.

MODIFICA: di seguito è riportato il codice che finalmente abbiamo funzionato. Il tempo di esecuzione per l'intera operazione è passato da "praticamente per sempre" (per la soluzione originale) a qualcosa in meno di un secondo, in base al feedback dell'OP. Anche la dimensione complessiva del codice è diminuita in modo apprezzabile.

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON 

    -- insert all missing "CachedStats" rows 
    INSERT INTO 
    CachedStats ([Date], AdvertId, CustomerId, CampaignId, CampaignName) 
    SELECT DISTINCT 
    CONVERT(Date, i.[Date]), i.AdvertId, i.PublisherCustomerId, c.Id, c.Name 
    FROM 
    Inserted i 
    INNER JOIN Advert a ON a.Id = i.AdvertId 
    INNER JOIN Campaign c ON c.Id = a.CampaignId 
    WHERE 
    i.Approved = 1 
    AND NOT EXISTS ( 
     SELECT 1 
     FROM CachedStats 
     WHERE Advertid = i.AdvertId AND 
      CustomerId = i.PublisherCustomerId AND 
      [Date]  = CONVERT(DATE, i.[Date]) 
    ) 

    -- update all affected records at once 
    UPDATE 
    CachedStats 
    SET 
    Clicks    = Clicks    + i.AddedClicks, 
    UniqueClicks   = UniqueClicks   + i.AddedUniqueClicks, 
    [Views]    = [Views]    + i.AddedViews, 
    UniqueViews   = UniqueViews   + i.AddedUniqueViews, 
    Leads    = Leads    + i.AddedLeads, 
    PublisherEarning  = PublisherEarning  + ISNULL(i.AddedPublisherEarning, 0), 
    AdvertiserCost  = AdvertiserCost  + ISNULL(i.AddedAdvertiserCost, 0), 
    PublisherOrderValue = PublisherOrderValue + ISNULL(i.AddedPublisherOrderValue, 0), 
    AdvertiserOrderValue = AdvertiserOrderValue + ISNULL(i.AddedAdvertiserOrderValue, 0) 
    FROM 
    (
    SELECT 
     AdvertId, 
     CONVERT(DATE, [Date]) [Date], 
     PublisherCustomerId, 
     COUNT(*) NumRows, 
     SUM(CASE WHEN Type IN (0)      THEN 1 ELSE 0 END) AddedClicks, 
     SUM(CASE WHEN Type IN (0)  AND [Unique] = 1 THEN 1 ELSE 0 END) AddedUniqueClicks, 
     SUM(CASE WHEN Type IN (2)      THEN 1 ELSE 0 END) AddedViews, 
     SUM(CASE WHEN Type IN (2)  AND [Unique] = 1 THEN 1 ELSE 0 END) AddedUniqueViews, 
     SUM(CASE WHEN Type IN (1,3,4) AND [Unique] = 1 THEN 1 ELSE 0 END) AddedLeads, 
     SUM(PublisherEarning)          AddedPublisherEarning, 
     SUM(AdvertiserCost)          AddedAdvertiserCost, 
     SUM(CASE WHEN Type IN (3) THEN PublisherOrderValue ELSE 0 END) AddedPublisherOrderValue, 
     SUM(CASE WHEN Type IN (3) THEN AdvertiserOrderValue ELSE 0 END) AddedAdvertiserOrderValue 
    FROM 
     Inserted 
    WHERE 
     Approved = 1 
    GROUP BY 
     AdvertId, 
     CONVERT(DATE, [Date]), 
     PublisherCustomerId 
    ) i 
    INNER JOIN CachedStats cs ON 
     cs.Advertid = i.AdvertId AND 
     cs.CustomerId = i.PublisherCustomerId AND 
     cs.[Date]  = i.[Date] 

    SET NOCOUNT OFF 
END 

Le operazioni di tabella CachedStats sarà di grande beneficio da un indice a più colonne over (Advertid, CustomerId, [Date]) (come confermato dalla OP).

+0

Ok sembra che tu sia riuscito a prendere quello che pensavo sarebbe stato un disastro completo e trasformarlo in qualcosa di bello - lo sto testando al momento e tornerò con quello che mi aspetto di essere una risposta accettata molto presto :). – kastermester

+0

Ho provato questo ora, e ho apportato alcune modifiche ad esso (come il codice ovviamente non poteva sapere alcuni nomi di colonne sarebbero in conflitto e così via). Un problema però è nel tuo comando di aggiornamento dove si presume solo una cosa nuova di ciascuno verrà aggiornata. Tuttavia sto cercando di risolvere questo problema. – kastermester

+0

Ho una parte di questo lavoro ora e sono più che mi aspetto di fare il resto. Dovrò apportare lievi modifiche al mio layout di tabella, ma nulla che possa infrangere la tua soluzione. Ho intenzione di pubblicare il trigger finale dell'inserto una volta fatto, così gli altri possono vedere cosa ho fatto. Grazie per l'aiuto! : D – kastermester

0

La prima cosa che farei è utilizzare un cursore FAST_FORWARD. Dato che stai passando da un record all'altro e non eseguendo alcun aggiornamento, questo sarà molto meglio per le prestazioni.

DECLARE CURSOR syntax

+0

Beh, questo è un ottimo inizio, grazie, sto provando questo approccio ora per vedere quanto guadagno c'è :) – kastermester

1

A seconda di quale versione di MSSQL si esegue, si dovrebbe anche considerare l'utilizzo di viste indicizzate per questo pure. Potrebbe essere un approccio più semplice rispetto ai trigger, a seconda di come appare la query del report. Vedi here per maggiori informazioni.

Inoltre, nel trigger, si dovrebbe provare a scrivere gli aggiornamenti sulla tabella dei risultati materializzati come un'operazione basata su set, non su un cursore. Scrivere un trigger basato sul cursore potrebbe invece semplicemente spostare il problema dalla query del report agli inserimenti della tabella.

+0

Vorrei secondo il suggerimento delle viste indicizzate, e quello di usare le operazioni basate su set nel cursore. Può essere SQL più complesso ma sarà molto più efficiente. – mwigdahl

0

È possibile ottimizzare leggermente la variazione del cursore eseguendo le opzioni FAST_FORWARD, READ_ONLY e LOCAL sul cursore. Inoltre, stai inserendo l'Id nel tuo cursore, quindi esegui il loopback per ottenere i valori. Utilizza CURRENT_OF o gettali tutti in variabili. Ma non mi aspetto che questi cambiamenti ti comprino molto.

È davvero necessario passare a un approccio basato su set. Quel proc memorizzato è sicuramente fattibile in un modello basato su set - anche se potrebbero essere necessarie 3 o 4 diverse dichiarazioni di aggiornamento. Ma anche 3 o 4 diversi trigger (1 per le visualizzazioni, 1 per i clic, ecc.) Sarebbero migliori dell'approccio del cursore.

0

La soluzione migliore è passare a un'operazione basata sul trigger nel trigger. Non ho intenzione di scrivere questo per te al 100%, ma lascia che ti dia inizio, e possiamo vedere dove andiamo da lì. Tieni presente che sto scrivendo questo senza tabelle/schemi e quindi non vado convalidato. Aspettatevi gli errori di battitura :-)

Guardiamo prima le vostre dichiarazioni di aggiornamento, Da quello che posso dire che state aggiornando la stessa tabella con la stessa clausola where l'unica differenza sono le colonne. È possibile consolidare questo per assomigliare:

UPDATE CachedStats SET 
     /* Basically we are going to set the counts based on the type inline in the update clause*/ 

    Leads= CASE WHEN (@Type = 1 OR @Type = 4 OR @Type=3) THEN Leads + 1 ELSE LEADS END, 
     Clicks=CASE WHEN (@Type=0) THEN Clicks+1 ELSE Clicks END, 
    Views=CASE WHEN (@Type=4) THEN Views+1 ELSE Views END, 
     PublisherEarning = @PublisherEarning + PublisherEarning, 
     AdvertiserCost = @AdvertiserCost +AdvertiserCost, 
FROM CachedStats CS 
INNER JOIN Inserted INS 
    ON CS.Date=Inserted.Date AND CS.CustomerId=Ins.PublisherId AND CS.CampaignId=Ins.CampaignId  

io aggree con voi che questo potrebbe diventare brutto ma questa è una decisione che dovrà fare.

Come per la clausola di inserimento, la gestirò nello stesso modo in cui si è già inseriti nella tabella dalla tabella Inserita, ma ciò che non esiste già.

+0

Non è necessario provare e inserirlo in una singola istruzione UPDATE. Basta eseguire 3 o 4 istruzioni UPDATE nel trigger. Le prestazioni non possono essere peggiori del cursore + singole istruzioni UPDATE e probabilmente non sono molto peggiori di un singolo UPDATE CASEified. –