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

有帮助吗?

解决方案

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

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

其他提示

来自 文档

  

共享(S)锁允许并发事务在悲观并发控制下读取(SELECT)资源。有关更多信息,请参阅并发控制类型。当资源上存在 shared(S)锁时,没有其他事务可以修改数据。一旦读取操作完成,就会释放资源上的共享(S)锁,除非将事务隔离级别设置为可重复读取或更高,或者使用锁定提示来保留在事务持续期间共享(S)锁。

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

这意味着您的 SELECT 查询将阻止 UPDATE INSERT 查询,反之亦然。

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

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

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

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

但它会阻止 SELECT 查询被 UPDATE 锁定。

另请注意, SQL Server Oracle 不同,它使用锁管理器并将其锁定在内存链表中。

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

要执行脏读,您可以:

 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)

您可以设置交易级别阅读未提交的

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

SELECT * FROM table1  WITH (READPAST)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top