2010-01-25 130 views
8

我需要先選擇(比方說)10000行數據庫並返回它們。可能有更多的客戶一次執行此操作。我想出了這個查詢:更新嵌套選擇原子操作?

update v set v.batch_Id = :batchId 
    from tblRedir v 
    inner join (
     select top 10000 id 
      from tblRedir 
      where batch_Id is null 
      order by Date asc 
    ) v2 on v.id=v2.id 

這是一個從更新和嵌套選擇組成的操作。兩個查詢都在同一個表上工作(tblRedir)。我們的想法是,該行首先由唯一batchId標記,然後通過

select * from tblRedir where batch_id = :batchId 

返回(在batchid是唯一標識符對於每個該更新(例如時間戳或GUID))

我的問題:

我認爲與嵌套選擇操作更新是原子的 - 這意味着,每一個客戶端收到自己的一套數據,這是唯一的(沒有其他客戶端收到他的數據的一個子集)。

但是它看起來是我錯了 - 在某些情況下是沒有收到數據的客戶,因爲他們很可能首先執行SELECT和那麼這兩個執行更新(所以第一個客戶端沒有標記行)。

該操作是否爲原子操作?


我與SQL Server 2005工作查詢通過NHibernate的這樣

session.CreateSQLQuery('update....') 

回答

5

SELECT地方上的行共享鎖讀,然後在READ COMMITED隔離模式被取消運行。

UPDATE將更新鎖稍後提升爲獨佔鎖。在交易結束之前它們不會被解除。

你應該儘快鎖定它們。

您可以通過使事務隔離級別爲REPEATABLE READ來實現,它將保留共享鎖直到事務結束,並且將阻止UPDATE部分鎖定這些行。

或者,你可以重寫查詢,因爲這:

WITH q AS 
     (
     SELECT TOP 10000 * 
     FROM mytable WITH (ROWLOCK, READPAST) 
     WHERE batch_id IS NULL 
     ORDER BY 
       date 
     ) 
UPDATE q 
SET  batch_id = @myid 

,這將只是跳過鎖定行。

+0

Thx爲您的答案。我已經嘗試過替代方案('with q as ...'),看起來READPAST不能與HOLDLOCK一起使用。 我試過隔離級別'read committed','repeatable read',並且在這兩種情況下sql server抱怨'你只能在READ COMMITTED或REPEATABLE READ隔離級別中指定READPAST鎖。即使沒有HOLDLOCK,查詢是否正確? – stej 2010-01-26 07:16:30

+0

'@ stej':在這種情況下,我不認爲'SQL Server'會分裂'SELECT'和'UPDATE'部分,所以是的,更新鎖將自動放置。你可以刪除'HOLDLOCK'。 – Quassnoi 2010-01-26 10:12:47

+0

謝謝。我試過了,它似乎有效。在某些情況下,有很多死鎖,但突然間沒有 - 很難重現它。如果我能夠以某種方式描述它,我會提交一個新問題。 – stej 2010-01-26 14:02:57