我不得不第一次在MSsql中使用触发器,一般来说是很好的触发器.阅读并自己测试后,我现在意识到触发器会触发每个命令,而不是每行插入,删除或更新.
整个事情是广告系统的一些统计数据.我们的主要统计表相当大,并且在大多数情况下不包含有意义的数据.它包含每个广告点击,查看等一行.作为用户,更倾向于想要查看它,因为日X具有Y点击量和Z量视图等等.到目前为止,我们完全基于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
存储过程相当大而且强烈,我不认为有必要避免以某种方式循环遍历Inserted表的记录(好吧,也许有,但我希望能够阅读代码也是: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,@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,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,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,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,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,[Views] = [Views] + ( SELECT COUNT(*) FROM Inserted s WHERE s.Approved = 1 AND s.PublisherCustomerId = i.PublisherCustomerId AND 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,Leads = Leads + ( SELECT COUNT(*) FROM Inserted s WHERE s.Approved = 1 AND s.[Unique] = 1 AND s.PublisherCustomerId = i.PublisherCustomerId AND 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,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,i.[Date]) AND s.AdvertId = i.AdvertId ),PublisherOrderValue = PublisherOrderValue + ISNULL(( SELECT SUM(PublisherEarning) FROM Inserted s WHERE s.Approved = 1 AND s.PublisherCustomerId = i.PublisherCustomerId AND CONVERT(Date,i.[Date]) AND s.AdvertId = i.AdvertId AND s.[Type] = 3 ),AdvertiserOrderValue = AdvertiserOrderValue + ISNULL(( SELECT SUM(AdvertiserCost) FROM Inserted s WHERE s.Approved = 1 AND s.PublisherCustomerId = i.PublisherCustomerId AND CONVERT(Date,i.[Date]) AND s.AdvertId = i.AdvertId AND s.[Type] = 3 ),PublisherCPC = CASE WHEN (Clicks + ( SELECT COUNT(*) FROM Inserted s WHERE s.Approved = 1 AND s.PublisherCustomerId = i.PublisherCustomerId AND 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,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,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,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,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
它现在看起来略有不同,因为我也必须为每个广告编制索引 – 但非常感谢帮助 – 从30小时到30秒加速所有内容从我自己的开发Stat表生成CachedStats