我正在编写一个触发器,将一个表的记录计数存储为另一个表中的列,以加快大型数据库上的某些报告查询。
这是我到目前为止所做的,它在删除时工作正常,但我也需要在插入上工作。我需要使用单独的触发器吗?是否必须使用光标或是否有更有效的方法?
谢谢!
ALTER TRIGGER [dbo].[updateSourceTotals]
ON [dbo].imports
AFTER INSERT, DELETE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sourceId int;
DECLARE deleteCursor CURSOR FOR SELECT DISTINCT sourceId FROM deleted
OPEN deleteCursor
FETCH NEXT FROM deleteCursor INTO @sourceId
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE sources
SET totalImports = (
SELECT COUNT(*)
FROM imports
WHERE sourceId = @sourceId
)
WHERE id = @sourceId
FETCH NEXT FROM deleteCursor INTO @sourceId
END
CLOSE deleteCursor
DEALLOCATE deleteCursor
END
GO
答案 0 :(得分:2)
如果您确实设置了Trigger方法(并且 NOT 推荐它),那么这是当前代码的一个更简单且可能更快的版本:
ALTER TRIGGER [dbo].[updateSourceTotals]
ON [dbo].imports
AFTER INSERT, DELETE
AS
BEGIN
UPDATE s
SET totalImports = (
SELECT COUNT(*)
FROM imports i
WHERE i.sourceId = s.Id
)
FROM sources s
WHERE s.id IN(SELECT sourceId FROM deleted)
END
如果你想覆盖INSERT
,也应该这样做:
ALTER TRIGGER [dbo].[updateSourceTotals]
ON [dbo].imports
AFTER INSERT, DELETE
AS
BEGIN
UPDATE s
SET totalImports = (
SELECT COUNT(*)
FROM imports i
WHERE i.sourceId = s.id
)
FROM sources s
WHERE s.id IN(
SELECT sourceId FROM deleted
UNION
SELECT sourceId FROM inserted
)
END
作为额外的奖励,它也适用于UPDATE
。
为了澄清一下,即使在消除Cursor之后,在Trigger中进行预聚合的问题是,不是在每个请求上重新计算查询,而是在每个上重新计算它们。修改。
即使在摘要中,如果你做了很多这样的请求,这只是一个胜利,但不要非常修改表。但是,在活动DBMS服务器的真实环境中,你甚至失去了大部分甚至这个小优势,因为如果你做了很多这样的请求,那么它们可能非常有效地被缓存(反过来,因为读取更多缓存 - 有效而不是写作。)