导致阻塞的SQL Server SELECT语句

时间:2009-06-19 09:50:09

标签: sql-server performance blocking

我们正在使用带有巨大select语句的SQL Server 2005数据库(没有行版本控制),我们看到它阻止其他语句运行(使用sp_who2看到)。我没有意识到SELECT语句可能导致阻塞 - 我有什么办法可以缓解这个问题吗?

6 个答案:

答案 0 :(得分:29)

SELECT可以阻止更新。正确设计的数据模型和查询只会导致最小的阻塞而不是问题。 “通常”WITH NOLOCK提示几乎总是错误的答案。正确的答案是调整查询,使其不扫描大表。

如果查询无法解决,那么您应首先考虑SNAPSHOT ISOLATION level,其次应考虑使用DATABASE SNAPSHOTS,最后一个选项应该是DIRTY READS(最好更改isolation level而不是{{3}}使用NOLOCK HINT)。请注意,如名称所示,脏读将返回不一致的数据(例如,您的总表单可能不平衡)。

答案 1 :(得分:14)

来自documentation

  

Shared (S)锁允许并发事务在悲观并发控制下读取(SELECT)资源。有关更多信息,请参阅Types of Concurrency Control。当资源上存在shared (S)锁时,没有其他事务可以修改数据。读取操作完成后,将立即释放资源上的Shared (S)锁,除非将事务隔离级别设置为可重复读取或更高,或者使用锁定提示在持续时间内保留shared (S)锁定交易。

shared lock与另一个共享锁或更新锁兼容,但不与exlusive锁兼容。

这意味着您的SELECT次查询会阻止UPDATEINSERT次查询,反之亦然。

SELECT查询在从表中读取值块时会放置一个临时共享锁,并在读完后将其删除。

对于存在锁定的时间,您将无法对锁定区域中的数据执行任何操作。

两个SELECT个查询永远不会相互阻止(除非它们是SELECT FOR UPDATE

您可以在数据库上启用SNAPSHOT隔离级别并使用它,但请注意,它不会阻止UPDATE查询被SELECT查询锁定(这似乎是您的情况) )。

但是,它会阻止SELECT UPDATE锁定SQL Server个查询。

另请注意,与Oracle不同,{{1}}使用锁管理器并将其锁定在内存中的链接列表中。

这意味着在负载很重的情况下,放置和删除锁定这一事实可能会很慢,因为链接列表本身应该被事务线程锁定。

答案 2 :(得分:2)

要执行脏读,您可以:

 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) ..."

请记住,您必须在每个要脏读的表

之后编写WITH(NOLOCK)

答案 3 :(得分:0)

您可以将transaction level设置为Read Uncommitted

答案 4 :(得分:0)

你可能也会陷入僵局:

“仅涉及一个表的死锁” http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx

和/或结果不正确:

“在READ COMMITTED和REPEATABLE READ下选择可能会返回错误的结果。”

http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return-incorrect-results.aspx

答案 5 :(得分:0)

您可以使用WITH(READPAST)表提示。它与WITH(NOLOCK)不同。它会在事务开始之前获取数据,并且不会阻止任何人。想象一下,您在事务开始之前就运行了该语句。

SELECT * FROM table1  WITH (READPAST)