SQL Server - 检查约束“不工作”

时间:2015-07-19 13:04:00

标签: sql-server-2012

我对SQL Server CHECK约束“无法正常工作”的问题有疑问:

我们正在使用SQL Server 2012 Enterprise实例。我们有一个表来描述实体上的事件(其中实体是具有FK的不同表)和时间帧(开始时间,结束时间)。

我们不允许同一实体上的两个事件与时间框架部分重叠,为此我们在数据库中添加了一个检查约束,在这种情况下应该失败。

这是检查约束功能:

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

有时候,当数据库上有很多并发负载时,不管怎样,具有相同entityId和重叠时间的事件记录都会设置为添加到数据库中,并且不会抛出任何错误。

当我们在上面的函数中运行查询时,它确实找到了那些重复的事件......

以下是添加到数据库的重复事件的示例:

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

我们正在考虑从检查约束切换到“而不是插入”触发器,因为在事件之后检查约束,而记录已经在DB中,但仍然 - 因为我们没有来自约束的错误,我们不确定我们是否会看到触发器的相同问题(如果它是并发/隔离问题,它可能不会消失)。

任何线索?

1 个答案:

答案 0 :(得分:1)

想象两个事务同时执行相同的操作:

  1. 插入有冲突的行
  2. 运行检查约束
  3. 提交
  4. 第2步没有看到其他交易的未提交行。

    将检查约束函数的隔离级别提升到SERIALIZABLE,并确保查询计划触及几行,以便锁定少量数据。