我有一個問題,爲什麼有些SQL(在SQL Server 2005上運行)的行爲是這樣的。具體來說,我在更新期間進行了一次更改以減少鎖爭用,並且在我認爲不會的情況下似乎正在工作。爲什麼SQL更新頂部顯然減少鎖定,即使沒有記錄更新?
原始代碼:
我們有這樣的更新語句,這是被應用到表300多萬條記錄:
UPDATE USER WITH (ROWLOCK)
SET Foo = 'N', Bar = getDate()
WHERE ISNULL(email, '') = ''
AND Foo = 'Y'
正如你可能已經猜到,這似乎鎖定USER表一段時間。即使使用ROWLOCK提示,針對USER運行查詢和更新的其他作業也會阻塞,直到完成此操作。這對於這個特定的應用程序來說是不可接受的,所以我認爲我會通過讓update語句一次只更新100條記錄來應用我讀到的一個技巧。這會讓其他查詢有機會偶爾進入桌面。
改進代碼:
DECLARE @LOOPAGAIN AS BIT;
SET @LOOPAGAIN = 1;
WHILE @LOOPAGAIN = 1
BEGIN
UPDATE TOP (100) USER WITH (ROWLOCK)
SET Foo = 'N', Bar = getDate()
WHERE ISNULL(email, '') = ''
AND Foo = 'Y'
IF @@ROWCOUNT > 0
SET @LOOPAGAIN = 1
ELSE
SET @LOOPAGAIN = 0
END
這並獲得成功。我們的更新完成了其工作,其他查詢能夠獲得表格。一切都是幸福與光明。
謎:
我明白這是如何提高性能時有它不得不更新表中的許多記錄。每完成100次更新後,通過循環快速運行,就可以讓其他查詢有機會進入桌面。神祕的是,即使沒有受到更新影響的記錄,此循環也具有相同的效果!
第二次運行我們的原始查詢時,它只會運行一小部分時間(比如說30秒左右),但是在那段時間內它會鎖定表,即使沒有記錄被更改。但是,將查詢放在循環中的「TOP(100)」子句中,儘管無需執行任務就花了很長時間,但是它爲其他查詢釋放了空間!
我對此很驚訝。誰能告訴我:
- 如果我剛纔說的是,在所有的清晰,
- 爲什麼第二個代碼塊允許其他的查詢在表中獲取,即使沒有被更新的記錄?
我認爲在它意識到沒有要更新的行之前,仍然需要對錶進行「SELECT」操作。 – 2009-11-10 20:32:43
在什麼事務隔離級別下? – 2009-11-10 21:18:25