J. *_* Ed 2 sql-server triggers sql-server-2008 database-deadlocks
我在我的实时应用程序中遇到了死锁错误,并将它们(使用sql server profiler的"死锁图")跟踪到after insert我的表上定义的触发器.
基本上情况是这样的 - 我想跟踪插入到某些表中的记录,按时间范围分组.(即在12:00-12:10之间,插入了7条记录Users).
我实现它的方法是after insert在这些表上创建触发器,因此当插入记录时,我将更新统计表中的相应记录.(见下文).
正如我所说,这似乎造成了僵局.发生的事情(我认为,我还没有找到确定的方法)是每个事务可以在提交之前在几个表中插入/更新几个记录.
因此事务1出现,更新统计表中的某个记录(从而锁定它),然后继续更新表B中的记录.
同时,事务2将记录插入表B(从而锁定它),并尝试更新统计信息表中的记录 - 导致死锁.
(这当然是可能发生的事情的简化版本.实际上我还不是100%肯定).
现在我最初的想法是看看是否可以在提交后执行触发器,以便事务不再持有任何锁.
但是,据我所知,没有这样的选择.
另一个解决方案是完全消除触发器,并使用某种批处理作业.
关于首选解决方案的任何其他想法/想法都会受欢迎.
触发代码:
SELECT @TimeIn = I.TimeIn,
@TimeOut = I.[TimeOut],
FROM Inserted AS I
SET @NoOfPAX = 1
SET @Day = DATEADD(dd,0,DATEDIFF(dd,0,@TimeOut))
SET @HourOfTheDay = DATEPART (HOUR, @TimeOut)
SET @MinuteOfTheHour = DATEPART (MINUTE, @TimeOut)
SELECT @HourlyStatsExists = COUNT(*)
FROM dbo.DataWarehouse_HourlyStats
WHERE [Day] = @Day
AND HourOfTheDay = @HourOfTheDay
AND MinuteOfTheHour = @MinuteOfTheHour
IF @HourlyStatsExists = 0
BEGIN
INSERT INTO dbo.DataWarehouse_HourlyStats
(
HourOfTheDay,
MinuteOfTheHour,
[Day],
Total
)
VALUES (
@HourOfTheDay,
@MinuteOfTheHour,
@Day,
@NoOfPAX
)
END
ELSE
BEGIN
UPDATE DataWarehouse_HourlyStats
SET Total = Total + @NoOfPAX,
LastUpdate = GetDate()
WHERE [Day] = @Day
AND HourOfTheDay = @HourOfTheDay
AND MinuteOfTheHour = @MinuteOfTheHour
END
Run Code Online (Sandbox Code Playgroud)
你做的最糟糕的事情是获得一个非常昂贵的计数只是为了测试存在.这是昂贵且不必要的 - 特别是因为您使用它来决定是否要更新或插入.在多行插入案例中,您可能需要同时执行这两种操作.
步骤1.更新存在的那些
;WITH x AS
(
SELECT d = DATEADD(DAY, 0, DATEDIFF(DAY, 0, i.TimeOut)),
h = DATEPART(HOUR, i.TimeOut),
m = DATEPART(MINUTE, i.Timeout)
FROM inserted
),
y AS
(
SELECT d, h, m, Total = COUNT(*)
FROM x GROUP BY d, h, m
)
UPDATE h
SET Total += y.Total,
LastUpdate = CURRENT_TIMESTAMP
FROM dbo.DataWarehouse_HourlyStats AS h
INNER JOIN y
ON h.[Day] = y.d
AND h.HourOfTheDay = y.h
AND h.MinuteOfTheHour = y.m;
Run Code Online (Sandbox Code Playgroud)
步骤2.插入没有的
;WITH x AS
(
SELECT d = DATEADD(DAY, 0, DATEDIFF(DAY, 0, i.TimeOut)),
h = DATEPART(HOUR, i.TimeOut),
m = DATEPART(MINUTE, i.Timeout)
FROM inserted
),
y AS
(
SELECT d, h, m, Total = COUNT(*)
FROM x WHERE NOT EXISTS
(
SELECT 1 FROM dbo.DataWarehouse_HourlyStats
WHERE [Day] = x.d
AND HourOfTheDay = x.h
AND MinuteOfTheHour = x.m
)
GROUP BY d, h, m
)
INSERT dbo.DataWarehouse_HourlyStats
(
HourOfTheDay,
MinuteOfTheHour,
[Day],
Total
)
SELECT h,m,d,Total
FROM y;
Run Code Online (Sandbox Code Playgroud)
它看起来像更多代码,但我向您保证,这比现有版本更高效,更准确.
也就是说,无论你有很多插件,它都会是一个非常昂贵的触发器.我希望至少在日,小时,分钟栏目上有一个很好的支持指数.
也许最好使用每小时或每日批处理作业来编译统计数据.根据定义,触发器本身是事务的一部分,因此您不能延迟提交,除非您只是将数据填充到队列或后台表中并进行其他工作修复它.
| 归档时间: |
|
| 查看次数: |
6907 次 |
| 最近记录: |