将数据插入SQL Server会锁定整个表吗?

时间:2011-09-13 01:40:48

标签: sql-server entity-framework

我正在使用Entity Framework,我正在将记录插入到包含blob字段的数据库中。 blob字段最多可以包含5 MB的数据。

将记录插入此表时,是否会锁定整个表?

因此,如果您要查询表中的任何数据,它是否会阻塞直到插入完成(我意识到有解决方法,但我默认说话)?

它会导致死锁需要多长时间?这个时间是否取决于服务器上的负载量,例如如果没有太多负载,是否需要更长时间才能造成死锁?

有没有办法监控并查看在任何特定时间锁定的内容?

如果每个线程都在对单个表进行查询,那么是否存在可能发生阻塞的情况?那么只有当你的查询有一个连接并且作用于多个表时,才会发生死锁吗?

考虑到我的大多数代码只是一堆select语句,而不是长时间运行的事务或类似的事情。

4 个答案:

答案 0 :(得分:115)

圣牛,你在这里有很多问题,呵呵。这里有几个答案:

在此表中插入记录时,是否会锁定整个表格?

不是默认情况下,但如果您使用TABLOCK提示或者您正在进行某些类型的批量加载操作,那么是。

所以,如果你要查询表中的任何数据,它会一直阻塞,直到插入完成(我意识到有办法解决这个问题,但我默认说话)?

这个有点棘手。如果某人试图从您已锁定的表格中的页面中选择数据,那么是的,您将阻止他们。您可以使用select语句上的NOLOCK提示或使用Read Committed Snapshot Isolation来解决这个问题。有关隔离级别如何工作的起点,请查看Kendra Little's isolation levels poster

导致死锁需要多长时间?这个时间是否取决于服务器上的负载量,例如如果没有太多负载会导致死锁需要更长的时间吗?

死锁不是基于时间 - 它们基于依赖性。假设我们遇到这种情况:

  • 查询A持有一堆锁,为了完成查询,他需要被查询B锁定的内容
  • 查询B也持有一堆锁,为了完成查询,他需要被查询A锁定的东西

任何一个查询都无法继续前进(想想墨西哥的僵局),所以SQL Server将其称为平局,在后面发出某人的查询,释放他的锁,并让其他查询继续进行。 SQL Server根据回滚的成本较低来选择受害者。如果你想获得花哨,你可以在特定查询上使用SET DEADLOCK_PRIORITY LOW来绘制背面的目标,SQL Server将首先拍摄它们。

有没有办法监控并查看在任何特定时间锁定的内容?

绝对 - 您可以像sys.dm_tran_locks一样查询动态管理视图(DMV),但最简单的方法是使用Adam Machanic's free sp_WhoIsActive stored proc。它是sp_who的一个非常光滑的替代品,你可以像这样调用:

sp_WhoIsActive @get_locks = 1

对于每个正在运行的查询,您将获得一个描述它所拥有的所有锁的XML。还有一个阻止列,所以你可以看到谁阻止了谁。要解释所持有的锁,您需要检查Books Online descriptions of lock types

如果每个线程都对单个表进行查询,那么是否存在可能发生阻塞的情况?那么只有当你的查询有一个连接并且作用于多个表时,才会发生死锁吗?

信不信由你,a single query can actually deadlock itself,是的,查询只能在一张桌子上死锁。要了解有关死锁的更多信息,请查看The Difficulty with Deadlocks by Jeremiah Peschka

答案 1 :(得分:3)

如果您可以直接控制SQL,则可以使用以下方法强制执行行级锁定:

INSERT INTO MyTable(Id, BigColumn) WITH (ROWLOCK)
VALUES(...)

这两个答案可能会有所帮助:

Is it possible to force row level locking in SQL Server?

Locking a table with a select in Entity Framework

要在Management Studio中查看当前保持的锁定,请在服务器下查看,然后在“管理/活动监视器”下查找。它有一个按对象锁定的部分,因此您应该能够看到插入是否真的导致了问题。

答案 2 :(得分:0)

我能想出的最佳答案是:这取决于。

检查的最佳方法是找到您的连接SPID并使用sp_lock SPID检查TAB类型上的锁定模式是否为X.您还可以使用SELECT OBJECT_NAME(objid)验证表名称。我还想使用以下查询来检查锁定。

    SELECT RESOURCE_TYPE,RESOURCE_SUBTYPE,DB_NAME(RESOURCE_DATABASE_ID) AS 'DATABASE',resource_database_id DBID,
    RESOURCE_DESCRIPTION,RESOURCE_ASSOCIATED_ENTITY_ID,REQUEST_MODE,REQUEST_SESSION_ID,
    CASE WHEN RESOURCE_TYPE = 'OBJECT' THEN OBJECT_NAME(RESOURCE_ASSOCIATED_ENTITY_ID,RESOURCE_DATABASE_ID) ELSE '' END OBJETO
    FROM SYS.DM_TRAN_LOCKS (NOLOCK)
    WHERE REQUEST_SESSION_ID = --SPID here

在SQL Server 2008(及更高版本)中,您可以禁用表上的锁升级,并在insert子句中强制执行WITH(ROWLOCK),从而有效地强制执行rowlock。这不能在SQL Server 2008之前完成(您可以编写WITH ROWLOCK,但SQL Server可以选择忽略它。)

我在这里讲通用,我对BLOB没有多少经验,因为我通常建议开发人员避免使用它们,特别是如果大于1 MB。

答案 3 :(得分:0)

死锁错误通常会很快恢复。由于在等待锁定时发生超时错误,不会发生死锁状态。 SQL Server通过查找锁定请求中的周期来检测死锁。

相关问题