2009-03-19 5 views
6

처음으로 MSSQL에서 트리거를 사용해야하는 중입니다. 전반적으로 잘 트리거됩니다. 읽었을 때마다 이것을 테스트 한 결과, 트리거가 명령마다 실행되고 행이 삽입되거나 삭제되거나 업데이트되지 않는다는 것을 알았습니다.MS SQL 트리거에서 여러 레코드 처리

전체가 광고 시스템에 대한 통계입니다. 우리의 주 통계 테이블은 다소 크고 대부분의 경우 의미있는 방식으로 데이터를 포함하지 않습니다. 클릭 한 광고, 볼 수있는 광고 당 하나의 행을 포함합니다. 사용자가 클릭 수와 Z보기 양 등의 Y 양을 갖는 것처럼이를보기를 더 선호하는 경향이 있습니다. 우리는 지금까지 순전히 SQL 쿼리를 기반으로 메인 테이블에서 이런 종류의 보고서를 얻었지만 테이블이 커짐에 따라 쿼리가 실행되는 시간도 길어졌습니다. 이 때문에 우리는 트리거를 사용하여 다른 테이블을 업데이트하여 SQL 서버에서 좀 더 쉽게 만들도록 선택했습니다.

내 문제는 이제 여러 레코드에서 작동하는 것입니다. 내가 한 일은 2 개의 저장 프로 시저 (삽입 작업을 처리하는 프로 시저와 삭제를위한 프로 시저)를 만드는 것입니다. 내 삽입 트리거 (하나의 레코드로 작업하도록 작성된)는 Inserted 테이블에서 데이터를 가져 와서 저장 프로 시저로 보냅니다. 삭제 트리거는 동일한 방식으로 작동하며, 업데이트 트리거는 삭제 + 삽입과 동일하게 작동합니다 (분명히?).

내 문제는 이제 여러 레코드에서이를 가장 효과적으로 처리하는 방법입니다. 나는 커서를 사용해 보았지만, 내가 읽을 수 있고 자신을 볼 수있는 한, 이것은 정말로 나쁜 결과를 낳는다. 필자는 명령에 여러 레코드가 있는지 확인한 다음 커서로 이동하는 방법을 확인하는 것과 마찬가지로 "검사"를 작성하는 것도 고려했습니다. 그렇지 않으면 단순히이 문제를 피하십시오. 어쨌든, 여기 커서로 내 솔루션을, 그리고 더 나은 방법이 있는지 궁금해?

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 

저장 프로 시저 오히려 크고 강한 내가 어떤 식 으로든 (에 삽입 된 테이블의 레코드를 반복하지 않도록해야하는 방법이 있다고 생각하지 않습니다 확인, 어쩌면있다,하지만 난 ' d 또한 코드를 읽을 수 있기를 바랍니다. p), 그렇게하지 않으면 (그렇지 않으면 생각하지 않는 한) 그 코드로 여러분을 지루하게하지 않을 것입니다. 그래서 꽤 많이,이 일을하는 더 좋은 방법이 있습니까? 그렇다면, 어떻게?

편집이 : 음 요청 후, 여기에 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 

이다, 여기 내 최종 결과입니다, 경우 다른 사람에 게시는 비슷한 문제 그것은 내가 때문에 지금은 약간 다른 모습

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 

에게 있습니다 광고별로도 색인을 생성해야했지만 - 덕분에 도움을받을 수있었습니다. - 내 개발 테이블 테이블에서 CachedStats를 생성하는 데 30 시간에서 30 초까지 모든 시간이 소요되었습니다.

+0

"ProcStatInsertTrigger"의 기능은 무엇입니까? (BTW : 당신은 sproc "Trigger"라는 이름을 사용하지 않아야합니다.) 일부 테이블에 데이터를 삽입하는 것 이상을 수행하지 않으면 접근 방식을 크게 단순화 할 수 있습니다. – Tomalak

+0

최종 버전을 게시 해 주셔서 감사합니다. :) 그러나 나는 이것이 최적이라고 확신하지 못합니다 - 당신은 겉으로보기에 중복 된 서브 선택을합니다.이 서브 선택은 조인 결과에서 계산되고 계산 될 수 있습니다. – Tomalak

+0

나는 그것들을 제거하는 것도 좋아할 것입니다. 그러나 나는 SQL 전문가가 아니기 때문에 나는 어떻게해야할지 모른다. 당신이 나에게 그 길을 보여줄 수 있다면 그것을 더 많이 최적화하고 싶다. 또한 여러 행이 있는지 확인하고 이전과 같이하지 않는 것이 좋을지 확인하는 것이 현명한 성능 향상 방법일까요? – kastermester

답변

8

이러한 상황에서의 트릭은 순차 조작 (각 레코드에 대해 xyz)을 설정 기반 조작 (UPDATE 문)으로 변환하는 것입니다.

저장 프로 시저를 분석하고 별도의 UPDATE 문을 하나의 항목으로 병합했습니다. 그런 다음이 단일 명령문을 삽입 된 모든 레코드에 한 번에 적용 할 수있는 버전으로 변환 할 수 있으므로 저장 프로 시저가 필요없고 커서가 필요하지 않습니다.

편집 : 아래는 마침내 우리가 작업 한 코드입니다. OP의 피드백에 따르면 전체 작업의 실행 시간은 "사실상 영원히"(원래 솔루션의 경우)에서 1 초 미만으로 떨어졌습니다. 전반적인 코드 크기도 상당히 줄었습니다. (영업에 의해 확인 됨) CachedStats 테이블을 포함

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 

동작 크게 (Advertid, CustomerId, [Date]) 위에 하나의 다중 컬럼 인덱스 이점 것이다.

+0

좋아, 내가 완벽하게 엉망이 될거라 생각한 것을 가져다가 아름다운 것으로 바꿔 버린 것 같다. 나는이 순간을 시험하고 있으며 곧 받아 들여지는 대답으로 기대하고있다. – kastermester

+0

나는 이것을 지금 시도해 보았고, 약간의 조정을했다. (당신의 코드가 분명히 어떤 컬럼 이름을 알지 못해 충돌 등이있을 수있다.) 문제는 업데이트 명령에 있지만 각 업데이트의 새로운 것은 하나만 업데이트된다고 가정합니다. 나는 이것을 atm에서 정렬하려고 노력하고있다. – kastermester

+0

나는이 일의 일부를 지금 받았고 나머지는 끝내기를 기대하고있다. 내 테이블 레이아웃을 약간 변경해야하지만 솔루션을 무력화시킬 것은 없습니다. 한 번 완료되면 마지막 삽입 트리거를 게시하여 다른 사람들이 내가 한 일을 볼 수 있도록 할 계획입니다. 도와 줘서 고마워! : D – kastermester

0

내가 할 첫 번째 일은 FAST_FORWARD 커서를 대신 사용하는 것입니다. 한 레코드에서 다음 레코드로 이동하고 업데이트를 수행하지 않으므로 성능이 훨씬 향상됩니다.

DECLARE CURSOR syntax

+0

좋은 시작입니다. 감사합니다. 얼마나 많은 이득이 있는지 보려면 지금 접근하고 있습니다. – kastermester

1

은 실행중인 MSSQL의 버전에 따라, 당신은 또한뿐만 아니라 이것에 대한 인덱싱 된 뷰를 사용하는 것이 좋습니다. 이는 보고서 쿼리가 어떻게 생겼는지에 따라 트리거보다 간단한 접근법이 될 수 있습니다. 자세한 내용은 here을 참조하십시오.

또한 트리거에서 구체화 된 결과 테이블에 갱신 사항을 커서가 아닌 세트 기반 조작으로 작성해야합니다. 커서 기반 트리거를 작성하면 잠재적으로 문제를 보고서 쿼리에서 테이블 삽입으로 옮길 수 있습니다.

+0

인덱스 된 제안을 두 번째로 제안하고 커서에서 집합 기반 작업을 사용합니다. 더 복잡한 SQL 일 수 있지만로드가 더 효율적입니다. – mwigdahl

0

커서의 FAST_FORWARD, READ_ONLY 및 LOCAL 옵션을 사용하여 커서 변형을 약간 최적화 할 수 있습니다. 또한 ID를 커서로 가져온 다음 다시 루프하여 값을 가져옵니다. CURRENT_OF를 사용하거나 변수에 모두 던져 넣으십시오. 그러나, 나는이 변화가 너를 많이 사기를 기대하지 않을 것이다.

정말 집합 기반 방식으로 이동해야합니다. 저장 프로 시저는 셋 기반 모델에서 확실히 실행 가능합니다. 그러나 3 개 또는 4 개의 다른 업데이트 문이 필요할 수 있습니다. 그러나 3 ~ 4 개의 다른 트리거 (보기의 경우 1 개, 클릭의 경우 1 개 등)가 커서 접근 방식보다 낫습니다.

0

가장 좋은 방법은 트리거에서 집합 기반 작업으로 이동하는 것입니다. 100 % 당신을 위해이 글을 쓰지는 않겠지 만, 시작하도록하겠습니다. 우리가 어디에서부터 시작하는지 알 수 있습니다. 테이블/스키마가 없으면이 글을 쓰고 있으므로 유효성을 검사하지 않을 것임을 명심하십시오. 오타가 예상됩니다 :-)

먼저 업데이트 구문을 살펴 보겠습니다. 동일한 차이가있는 동일한 테이블을 동일한 테이블에서 업데이트한다고 말할 수 있습니다. 나는이 추한 얻을 수 있다는 당신과 함께 aggree 않습니다하지만 당신이 만들어야 할 것이다 결정의

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  

: 당신처럼이보고 통합 할 수 있습니다.

insert 절에 대해서는 이미 존재하지 않는 것이 든 Inserted 테이블의 테이블에 삽입하는 것과 같은 방식으로 처리 할 것입니다.

+0

하나의 UPDATE 문을 사용하지 않아도됩니다. 트리거에서 3 또는 4 개의 UPDATE 문을 실행하기 만하면됩니다. 성능은 커서 + 단일 UPDATE 문보다 나쁠 수는 없으며 단일 CASEified UPDATE보다 훨씬 나빠질 수 있습니다. –

관련 문제