我知道快照隔離可以解決這個問題,但我想知道在這種特殊情況下NOLOCK是否安全,這樣我可以避免開銷。在這種情況下讀取未提及/解鎖安全嗎?
我有一個表,看起來是這樣的:
drop table Data
create table Data
(
Id BIGINT NOT NULL,
Date BIGINT NOT NULL,
Value BIGINT,
constraint Cx primary key (Date, Id)
)
create nonclustered index Ix on Data (Id, Date)
有表中沒有更新,永遠。刪除可能發生,但他們不應該與SELECT競爭,因爲它們會影響表的另一個較舊的末端。插入是常規的,頁面拆分到(Id,Date)索引是非常普遍的。
我有一個標準的INSERT和SELECT看起來像這樣之間的死鎖情況:
select top 1 Date, Value from Data where Id = @p0 order by Date desc
因爲INSERT獲取關於CX鎖(日期,身份證;值),然後IX(ID,日期),但SELECT會獲取Ix(Id,Date)和Cx(Date,Id; Value)上的鎖定。這是因爲SELECT首先在Ix上尋找,然後加入到Cx上尋找。
交換聚集索引和非聚集索引會打破這個循環,但它不是一個可接受的解決方案,因爲它會引入具有其他(更復雜)SELECT的循環。
如果我將NOLOCK添加到SELECT,在這種情況下會出錯嗎?它可以返回:
- 不止一行,即使我問TOP 1?
- 沒有行,即使存在並已提交?
- 最糟糕的是,一行不符合WHERE子句?
我已經做了很多的閱讀有關本次網上,但過高或過低計數異常的唯一複製品我見過(one,two)涉及掃描。這隻涉及尋求。 Jeff Atwood has a post關於使用NOLOCK產生了一個很好的討論。我是由Rick湯森評論特別感興趣:
其次,如果你讀髒數據,運行 風險是讀 完全錯誤的行。例如,如果 您選擇讀取索引來查找 你行,則更新改變 位置的行(例如:由於 頁拆分或更新到 聚集索引),當你選擇 去讀取實際的數據行,它的 或者不再存在,或者完全不同的 行!
這是可能的只插入和沒有更新?如果是這樣,那麼我想即使我在一張只有插入的桌子上尋找也是危險的。
更新:
我試圖找出how snapshot isolation works。它似乎是基於行的,事務讀取表(不帶共享鎖!),找到他們感興趣的行,然後查看他們是否需要從tempdb中的版本存儲中獲取該行的舊版本。
但在我的情況下,沒有行將有多個版本,所以版本存儲似乎是沒有意義的。如果找到沒有共享鎖的行,那麼和使用NOLOCK有什麼不同呢?
啊,OUTPUT子句非常酷,謝謝。我不需要它在這個特定的桌子上,但我可以考慮一些未來的代碼,我可以使用它。 我明白你的觀點。我已經體驗過不同查詢計劃的影響 - 直到有足夠的行才能使這兩個查找比全面掃描更好,纔會發生死鎖。說實話,我已經傾向於快照隔離。但記錄無證行爲對我來說很有意思,即使我沒有在生產中利用它。 :) – 2010-06-08 22:27:28
用另一個問題更新原來的帖子,謝謝。 – 2010-06-08 23:39:46
好吧,所以我同意我們不想「讀取過時的非聚簇索引鍵並將其追加到聚簇索引中缺失的行」。問題是,這是否會在沒有任何行的UPDATE的情況下實際發生?我所做的只是插入,因此只有元數據將被更新,而不是任何行中的數據。我以爲SQL Server會有一些低級別的一致性機制來防止元數據損壞,即使使用NOLOCK(這是一個相當高層次的概念)..? – 2010-06-09 00:39:46