我之前已多次阅读并使用过(nolock)提示但我对特定案例有疑问。
在我的情况下,我有一组引用和更新一个数据库的代码 此代码旨在以单线程方式运行。 几个月前,他们决定在不更改代码的情况下使其成为多线程。他们采用的方式是让每个不同的“代码处理器”管理不同的商店组。
例如,processor1负责商店1到20,处理器2负责商店21到40等等。
在我们开始遇到僵局之前,一切似乎都很好。死锁始终在页面上...如果锁只在行上,我们永远不会出现死锁,因为来自一个处理器的数据永远不会与来自另一个处理器的数据冲突。基于这个理论,我决定在每个不需要锁定的选项上添加With(Nolock)提示(尚未投入)...这使我的死锁在我的实验室中消失。
直到我的同事带着THIS文章来找我时,一切看起来都很精致,让我害怕... 然后我读了THAT ...
在我的情况下使用With(Nolock)提示是否存在危险......处理器之间的数据永远不会冲突?
答案 0 :(得分:2)
撤回您的nolock提示并将您的数据库置于快照隔离级别。
READ_COMMITTED_SNAPSHOT数据库选项ON
有关详细信息,请参阅https://technet.microsoft.com/en-us/library/ms191242(v=sql.105).aspx。但是,请注意保存tempDB的磁盘在快照隔离中经历更高的I / O.
答案 1 :(得分:1)
是的,如果您收集的数据必须准确,那么很可能会出现问题 - 您可能会抓住"脏" /不正确的数据,然后坚持下去。您是否看过索引是否可以纠正死锁问题?通常可以通过控制数据页面的访问模式来解决死锁情况,数据页面由可用索引控制。
我喜欢做的是查看死锁图以查看冲突的位置,然后查看代码中的操作顺序,以及用于访问/修改数据的索引,看看我是否可以调整以消除死锁风险。
答案 2 :(得分:1)
看起来您的选择查询是死锁的原因。这可能是正在发生的事情。您可能稍后会选择并更新记录。因此,当更新记录超过5000时,sql server使用锁升级并锁定整个表而不是锁定行。
如果你的程序是 -
select .......
--some coding here----
update statement
如果另一个线程在更新语句之前使用select语句,则会因为共享锁而阻止update语句,并且update语句将等待释放共享锁,同时另一个进程发出update语句。由于您应用了共享锁,第二个进程更新语句将被阻止。因此,当两个线程都在等待彼此时,就会发生死锁。
解决方案 -
使用UPDLOCK提示 - 这将允许共享锁但不允许更新锁。将您的select语句转换为 - > select * from mytable with(UPDLOCK,ROWLOCK) RowLOCK提示将保持锁定在行级别而不是页面或表级别。这将减少死锁
使用快照隔离
请注意,不要在select语句中使用(NOLOCK),因为这会导致脏读取是未提交的数据,这可能是错误的。