2015-07-19 61 views
1

我有一個與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 

我們考慮從檢查約束切換到「而不是插入」觸發器,因爲檢查約束被檢查事實雖然記錄已經在數據庫中,但仍然 - 因爲我們從約束沒有得到任何錯誤,我們不確定是否我們不會看到與觸發器相同的問題(如果它是併發/隔離問題,它可能不會消失)。

任何線索?

+0

在select語句中使用'ROWLOCK,UPDLOCK'可能會有所幫助 – Arvind

回答

1

想象一下兩筆交易同時做相同的:

  1. 插入衝突行
  2. 運行檢查約束
  3. 提交

第2步沒有看到其他事務未提交的行。

將檢查約束函數的隔離級別提高到SERIALIZABLE,並確保查詢計劃觸及少數行,以便少量數據被鎖定。

+0

當然,請確保您的序列化查詢不會鎖定整個表! –