這是一個多租戶應用程序。所有記錄都有一個客戶端ID來分隔客戶端數據。客戶可以在此表中插入他們自己的數據並設置他們自己的唯一約束。每個客戶可以對15個字段中的任何一個設置唯一的約束,或者不設置任何約束所以,在實際的表上設置一個唯一的約束是行不通的。如何在多租戶數據庫中設置唯一約束條件
當前,爲了檢查是否應插入記錄,我們查詢數據庫以查看記錄是否存在。如果是這樣,我們不插入,否則我們做插入。如果在檢查和插入之間插入重複記錄,則重複項將泄漏到數據庫中。有沒有辦法保證重複不被插入?
這是一個多租戶應用程序。所有記錄都有一個客戶端ID來分隔客戶端數據。客戶可以在此表中插入他們自己的數據並設置他們自己的唯一約束。每個客戶可以對15個字段中的任何一個設置唯一的約束,或者不設置任何約束所以,在實際的表上設置一個唯一的約束是行不通的。如何在多租戶數據庫中設置唯一約束條件
當前,爲了檢查是否應插入記錄,我們查詢數據庫以查看記錄是否存在。如果是這樣,我們不插入,否則我們做插入。如果在檢查和插入之間插入重複記錄,則重複項將泄漏到數據庫中。有沒有辦法保證重複不被插入?
正如評論中所提到的,避免因爲並行運行的進程之間的時間問題而插入重複項的一種方法是將使用WHERE
子句的行存在的測試與INSERT
語句組合起來。 我建議動態SQL是一種可能的解決方案,但如果客戶端的約束設置存儲在數據庫中,則可以使用位掩碼替代方法,該方法可能適用於您。我做了一些假設,所以這可能無助於你。
請注意,此代碼被簡化爲僅與三列(而不是OP中提到的十五)一起工作。如果決定製作它,最好將邏輯包裝在存儲過程中。
-- run this code for different values of @ClientId and @DataN to test the behaviour
DECLARE
@ClientId int = 103,
@Data1 int = 1,
@Data2 int = 2,
@Data3 int = 3
DECLARE @clientConstraint TABLE (ClientId int PRIMARY KEY, Data1 bit, Data2 bit, Data3 bit)
DECLARE @clientData TABLE (Id int IDENTITY PRIMARY KEY, ClientId int, Data1 int, Data2 int, Data3 int)
-- set up four clients with different constraints for testing purposes
INSERT @clientConstraint (ClientId, Data1, Data2, Data3)
VALUES
(100,0,0,0),
(101,1,0,0),
(102,0,1,0),
(103,1,0,1)
-- set up an existing row in the data table for each client
INSERT @clientData (ClientId, Data1, Data2, Data3)
VALUES
(100,1,2,3),
(101,1,2,3),
(102,1,2,3),
(103,1,2,3)
-- build a bitmask of the client's unique columns
DECLARE @ClientConstraintMask bigint = 0
SELECT @ClientConstraintMask = Data1 + (Data2 * 2) + (Data3 * 4)
FROM @clientConstraint
WHERE ClientId = @ClientId
-- insert the data, building a uniqueness bitmask and comparing to client's settings
INSERT @clientData (ClientId, Data1, Data2, Data3)
SELECT @ClientId,@Data1, @Data2, @Data3
WHERE (SELECT
CASE WHEN c1.Data1 = @Data1
THEN @ClientConstraintMask & 1
ELSE 0
END +
CASE WHEN c1.Data2 = @Data2
THEN @ClientConstraintMask & 2
ELSE 0
END +
CASE WHEN c1.Data3 = @Data3
THEN @ClientConstraintMask & 4
ELSE 0
END
FROM @clientData AS c1
WHERE c1.ClientId = @ClientId
) <> @ClientConstraintMask
-- view the results
SELECT * FROM @clientData
它可能還值得一提的是,這取決於客戶端的數據量,您可能很難有效索引客戶端的數據表,以保持插入表現良好。如果只有ClientId
上的索引表現不佳,請考慮對最常用的唯一列集編制索引。
你考慮過鎖嗎? –
@ PM77-1很好的建議。如果我對租戶ID進行鎖定,它是否會鎖定屬於租戶的所有記錄?如果是這樣,這是否會阻止來自其他會話的給定租戶ID插入記錄? – Luke101
獨特的過濾索引(過濾「客戶端ID」)如何? http://sqlmag.com/blog/whats-good-use-unique-filtered-index – mendosi