SQL服务器 - 检查约束“不工作”
问题描述:
我有一个与SQL Server CHECK
约束问题的问题“不工作”:SQL服务器 - 检查约束“不工作”
我们使用SQL Server 2012 Enterprise实例。我们有一个描述实体(实体是与FK不同的表)的事件和时间范围(开始时间,结束时间)的表格。
我们不允许在部分重叠的时间范围内的同一个实体上发生两个事件,为此我们在DB中添加了一个检查约束,在这种情况下应该失败。
这是检查约束功能:
CREATE FUNCTION [dbo].[DoesConflictingEventExist]
(
@existing_event_id int,
@entity_id bigint,
@start_time datetime,
@end_time datetime
)
RETURNS bit
AS
BEGIN
return case
when exists (select * from Events er1
where
er1.EntityId = @entity_id
and not (er1.EndTime <= @start_time
or @end_time <= er1.StartTime)
and er1.Id <> @existing_event_id) then 1
else 0
end
END
有时候,也许当大量并发负载的是在DB,不知何故事件记录与同entityId
和重叠的时间内就设法得到添加到DB并且不会引发错误。
当我们运行上面的函数内的查询,它确实找到那些重复的事件......
这里是被添加到数据库重复的事件的例子:
Event1(id 2691604):
entityID 8095119352335255831, starttime 2015-07-05 15:02:43.000 endtime 2016-06-30 13:28:41.000
Event2(id 2691605):
entityID 8095119352335255831, starttime 2015-07-05 15:03:19.000 endtime 2016-06-30 13:28:41.000
我们考虑从检查约束切换到“而不是插入”触发器,因为检查约束被检查事实虽然记录已经在数据库中,但仍然 - 因为我们从约束没有得到任何错误,我们不确定是否我们不会看到与触发器相同的问题(如果它是并发/隔离问题,它可能不会消失)。
任何线索?
答
想象一下两笔交易同时做相同的:
- 插入冲突行
- 运行检查约束
- 提交
第2步没有看到其他事务未提交的行。
将检查约束函数的隔离级别提高到SERIALIZABLE
,并确保查询计划触及少数行,以便少量数据被锁定。
+0
当然,请确保您的序列化查询不会锁定整个表! –
在select语句中使用'ROWLOCK,UPDLOCK'可能会有所帮助 – Arvind