导致阻塞的SQL Server SELECT语句
我们正在使用SQL Server 2005数据库(无行版本控制)和大量select语句,并且我们看到它阻止了其他运行语句(使用sp_who2
)。我没有意识到SELECT语句可能会导致阻塞 - 有什么我可以做的,以减轻这一点?导致阻塞的SQL Server SELECT语句
SELECT可以阻止更新。正确设计的数据模型和查询只会造成最小的阻塞,而不是问题。 “常用”WITH NOLOCK提示几乎总是错误的答案。正确的答案是调整您的查询,以便它不扫描巨大的表。
如果查询是不可调节,那么你应该首先考虑SNAPSHOT ISOLATION level,第二你应该考虑使用DATABASE SNAPSHOTS和最后的选择应该是脏读(并且更好的改变isolation level,而不是使用NOLOCK提示)。请注意,如名称明确指出的那样,脏读将返回不一致的数据(例如,您的总表可能不平衡)。
Shared (S)
锁允许并发事务读取(SELECT)
悲观并发控制下的资源。有关更多信息,请参阅Types of Concurrency Control
。没有其他事务可以修改数据,而shared (S)
锁存在资源上。只要读取操作完成,资源上的锁就会被释放,除非事务隔离级别设置为可重复读取或更高级别,或者在事务持续期间使用锁定提示来保留shared (S)
锁。
A shared lock
与另一个共享锁或更新锁兼容,但不是与exlusive锁。
这意味着您的SELECT
查询将阻止UPDATE
和INSERT
查询,反之亦然。
A SELECT
查询将在从表中读取一个值块时放置临时共享锁,并在完成读取操作后将其删除。
当锁存在时,您将无法对锁定区域中的数据执行任何操作。
两个SELECT
查询不会阻塞对方(除非他们是SELECT FOR UPDATE
)
您可以在数据库上启用SNAPSHOT
隔离级别,并使用它,但请注意,它不会阻止UPDATE
查询由SELECT
查询被锁定(这似乎是你的情况)。
但是,它会阻止SELECT
查询被锁定UPDATE
。
另请注意,与Oracle
不同,SQL Server
使用锁定管理器并将其锁定在内存中的链接列表中。
这意味着在重负载下,放置和移除锁定的事实可能会很慢,因为链接列表本身应该被事务线程锁定。
要执行脏读,您可以:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
或每个表后要脏
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
记住,你必须与(NOLOCK)写读
你也可能会导致死锁:
和或不正确的结果:
“看了下选择提交,重复读取可能会返回不正确的结果”
你任何机会,如重复读或可序列化使用更高隔离级别?某些ADO和CLR组件在没有您的明确同意的情况下偷偷进入可搜索状态...(密钥,范围,表格)上的阻塞资源是什么? – 2009-06-19 10:09:14
我没有指定隔离级别。有没有办法找出正在使用什么隔离级别? – 2009-06-19 10:15:31
是的,请查看sys.dm_exec_sessions。 transaction_isolation_level列。 – 2009-06-19 10:27:05