没有锁定运行相同的查询

时间:2012-10-10 20:35:55

标签: sql sql-server-2008

                if exists (select 1 from schema.TableName (nolock) where Id = @id) 
                update schema.TableName set DocumentXML = @documentXml, ClientDocumentGUID=@clientDocGuid, Incomplete = @incomplete where Id = @id
                else
                insert into schema.TableName
                select @id, @templateId, @clientVisitGuid, @clientGuid, @chartGuid, @scmDocumentGuid, @clientDocGuid, @incomplete, getdate(), @createdByGuid, @documentXml

我有一个运行上述查询的C#程序。我有情况出现两次插入行的情况。我认为问题是这个问题。我们的想法是,在相同@Id的情况下,查询可以运行两次。第一次应该是插入,第二次应该是更新。

请注意,查询中包含(no lock)。这是否意味着查询不一定以FIFO方式运行?我相信只有异步运行此查询时才会出现两行问题。

2 个答案:

答案 0 :(得分:0)

取决于事务隔离级别查询可以并行运行...

答案 1 :(得分:0)

使用NOLOCK提示会导致SQL Server忽略所有锁定。这意味着查询可能最终会在更改中间读取值,这会导致返回完全垃圾。

但是,删除NOLOCK提示是不够的。您需要确保所有语句都在调用应用程序或过程中的事务中执行。如果您首先使用程序进行审核:How to rollback in procedures

在事务中包装语句之后,还需要确保IF EXISTS语句对该行进行更新或独占锁定以防止其他人在您的语句之间插入一行,因此您需要一个UPDLOCK或XLOCK提示。由于该行可能尚不存在,因此只能在可序列化的事务隔离级别中使用。

实施了所有这些之后,您仍然在使用此设置浪费读取。这可能会在以后成为一个性能问题。

-

长话短说:正如JoshBerke建议的那样,在这种情况下你应该真正使用MERGE语句。这样可以更快,更轻松地维护您的问题。但是,它需要2008年或更晚。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/bb510625.aspx