Sql server 用于更新insert和delete上的总记录的触发器
我正在编写一个触发器,将一个表的记录计数作为列存储在另一个表中,以加速大型数据库上的一些报告查询 这是我到目前为止得到的,它可以很好地处理删除操作,但我还需要处理插入操作。我需要使用单独的触发器吗?另外,使用光标是必要的还是有更有效的方法 谢谢Sql server 用于更新insert和delete上的总记录的触发器,sql-server,triggers,Sql Server,Triggers,我正在编写一个触发器,将一个表的记录计数作为列存储在另一个表中,以加速大型数据库上的一些报告查询 这是我到目前为止得到的,它可以很好地处理删除操作,但我还需要处理插入操作。我需要使用单独的触发器吗?另外,使用光标是必要的还是有更有效的方法 谢谢 ALTER TRIGGER [dbo].[updateSourceTotals] ON [dbo].imports AFTER INSERT, DELETE AS BEGIN SET NOCOUNT ON; DECLA
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
如果您真的选择了触发器方法,我不推荐使用它,那么这是您当前代码的一个更简单、可能更快的版本:
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
如果您还想覆盖插件,则应这样做:
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
作为一个额外的好处,它应该也适用于更新
需要澄清的是,在触发器中进行预聚合(即使在消除游标之后)的问题在于,不是在每个请求上重新计算查询,而是在每次修改时重新计算查询
即使在抽象的情况下,如果您执行了许多这样的请求,但没有对表进行太多修改,这也只是一个胜利。然而,在活动DBMS服务器的实际环境中,您甚至会失去这一小优势,因为如果您发出许多这样的请求,那么它们可能会得到非常有效的缓存,因为读缓存比写缓存有效得多。到底为什么您需要通过触发器更新计数?您总是可以在运行时获得该计数,并且它不依赖于带有游标的触发器,甚至更少。如果在选择时间获得计数是昂贵的,那么考虑索引视图。应该删除此触发器和totalImports列。通常,预先计算的聚合不是解决报告性能的一种可取方法,特别是考虑到它们的非关系性质。然而,如果你的报告是这样写的,那么我可以理解为什么它们写得慢。但是,解决方案并不是使用一个会使插入和删除速度极其缓慢的触发器。更可能的解决方案是优化报表及其表和索引。这是一个示例,其中还使用了更复杂的聚合,它们需要实时数据,因此我认为在底层记录更改时计算一次,而不是每次请求时计算一次是有意义的。不过,我完全支持其他方法,但它确实需要持久化,而不是在运行时计算。这不起作用-如果我运行一个简单的UPDATE sources SET label=label来更新所有行,它会计算totalImports,但数字都错了。我认为对于一个更新,它必须每行工作,或者至少每一个sourceId工作?这确实是每一个sourceId计算的,它只是以一种面向集合的方式进行的。至于更新的问题,我不知道为什么它不能正常工作。你能发布一些示例数据来证明或至少解释它是如何错误的吗?我发现了这个问题。对于具有导入的任何源,它在更新时都可以正常工作,但如果导入计数的结果为零,则它将返回表中的记录总数,而不考虑sourceId。选择id,totalImports,选择COUNT FROM imports WHERE imports.sourceId=sources.id AS-actualImports FROM sources 6 136037 0 7 136037 0 9 136037 0 10 136037 0 11 1873 1873 12 82 13 278 278 14 2762 2762 15 4509 4509抱歉,仍在尝试设置格式,请耐心等待@不要通过编辑你的原创文章并在文章末尾添加它来否定这样的东西。