我们在Stack Overflow SQL Server 2005数据库中看到了一些有害但罕见的死锁情况。
我附加了事件探查器,并使用这篇有关解决死锁的出色文章来建立跟踪配置文件,并捕获了许多示例。奇怪的是,死锁写入总是相同的:
UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0
其他死锁语句有所不同,但通常是对posts表的一些琐碎,简单的读取。这个总是在僵局中被杀死。这是一个例子
SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount],
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId],
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0
确切地说,我们没有看到写/写死锁,而是看到了读/写。
目前,我们混合使用LINQ和参数化SQL查询。我们已经添加with (nolock)
了所有的SQL查询。这可能有所帮助。我昨天还修复了一个(非常)写得不好的徽章查询,每次都要花费20秒以上的时间,而且每分钟都在运行。我希望这是一些锁定问题的根源!
不幸的是,大约2小时前,我又遇到了一个死锁错误。同样的症状,同样的罪魁祸首。
真正奇怪的是,您在上面看到的锁定write SQL语句是非常特定的代码路径的一部分。仅在将新答案添加到问题时才执行它-它使用新答案计数和最后日期/用户来更新父问题。显然,相对于我们正在进行的大量读取,这不是那么普遍!据我所知,我们并未在应用程序中的任何地方进行大量写入操作。
我意识到NOLOCK有点像大锤子,但是我们在这里运行的大多数查询不需要那么精确。您是否会担心用户配置文件过时几秒钟?
正如Scott Hanselman在这里讨论的那样,与Linq一起使用NOLOCK更加困难。
我们正在调情使用
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
在基础数据库上下文上运行,以便我们所有的LINQ查询都具有此设置。否则,我们将必须将我们进行的每个LINQ调用(很简单的读取代码,占绝大多数)包装在3-4行的事务代码块中,这很丑陋。
我想我对SQL 2005中的琐碎读取会在写入时陷入僵局感到有些沮丧。我可以看到写/写死锁是一个很大的问题,但是读吗?我们不在这里运行银行网站,我们每次都不需要完美的准确性。
有想法吗?有什么想法吗?
您要为每个操作实例化一个新的LINQ to SQL DataContext对象,还是为所有调用共享相同的静态上下文?
杰里米(Jeremy),在大多数情况下,我们在基本控制器中共享一个静态数据上下文:
private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
get
{
if (_db == null)
{
_db = new DBContext() { SessionName = GetType().Name };
//_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}
return _db;
}
}
您是否建议我们为每个控制器,每个页面或..更频繁地创建一个新的上下文?