2010-01-25 89 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