【问题标题】:Entity Framework SQL Timeout after x number of WCF requestsx 次 WCF 请求后实体框架 SQL 超时
【发布时间】:2014-10-16 13:06:47
【问题描述】:

每十分钟大约有 300 个客户端向 WCF 服务发出请求。他们并非都在完全相同的时间提出请求。

Service 类中的此 LINQ 查询试图获取客户端尚未收到的 configFeedItems(注意:我正在使用 Ninject 将存储库注入到我的 Service 类中):

     var configFeedItems = (from feedItem in configFeedItemRepository.All
                            where feedItem.Id > lastReceivedFeedItemId &&
                            (feedItem.TargetUserId == userId || feedItem.TargetUserId == null) &&
                            !feedItem.ConfigFeedItemReceipts.Any(x => x.User.Id == userId)
                            select feedItem)
                            .ToList();

导致抛出此异常的原因:

[SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.]

这是生成的 SQL:

exec sp_executesql N'SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Action] AS [Action], 
[Extent1].[TargetId] AS [TargetId], 
[Extent1].[TargetCommand] AS [TargetCommand], 
[Extent1].[CreatedOn] AS [CreatedOn], 
[Extent1].[TargetUserId] AS [TargetUserId], 
[Extent1].[ChannelToUpdate] AS [ChannelToUpdate], 
[Extent1].[CreatedBy_Id] AS [CreatedBy_Id]
FROM [dbo].[ConfigFeedItem] AS [Extent1]
WHERE ([Extent1].[Id] > @p__linq__0) AND ([Extent1].[TargetUserId] = @p__linq__1 OR [Extent1].[TargetUserId] IS NULL) AND ( NOT EXISTS (SELECT 
1 AS [C1]
FROM [dbo].[ConfigFeedItemReceipt] AS [Extent2]
WHERE ([Extent1].[Id] = [Extent2].[ConfigFeedItem_Id]) AND ([Extent2].[User_Id] = @p__linq__2)))',N'@p__linq__0 int,@p__linq__1 uniqueidentifier,@p__linq__2 uniqueidentifier',@p__linq__0=0,@p__linq__1='E3D4044F-497E-4EEC-890C-021F72826505',@p__linq__2='E3D4044F-497E-4EEC-890C-021F72826505'

如果我在 IIS 中停止并重新启动 AppPool,大约五分钟就可以了,然后再次发生。

如果我更改 LINQ 查询以使其不引入 ConfigFeedItemReceipts,则不会出现任何超时。 它似乎只在我尝试查询子集合时发生。 我尝试使用连接,EF 使用简单的 LEFT OUTER JOIN 生成查询,但我仍然超时。 好像有锁什么的,或者连接被刷爆了。

我在执行 LINQ 查询之前尝试了SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;,但这并没有什么不同

任何想法是什么导致 SQL 超时?

更新:并非所有请求都会导致超时,有些工作有些不会,即使它是同一个查询。

【问题讨论】:

  • 其余代码在哪里?您在哪里打开和关闭连接/事务?你处理上下文吗?执行计划是什么?第二个表在User_Id 上有索引吗?在 SQL Server 的 Management Studio 中打开活动监视器以查看发生阻塞时的活动连接和查询。不要
  • 查询相同但数据不同。如果User_IdConfigFeedItem_Id 上没有索引,服务器将必须扫描所有相关的提要项目,然后计算它们。查询的执行计划是什么?这张桌子有多大?
  • DBContext 对象的生命周期由 Ninject 处理,并指定为 InRequestScope()。查看执行计划中最昂贵的 95% 是 ConfigFeedItemReceipt(即子集合)上的 Key LookUp(集群)。是的,第二个表 ConfigFeedItemReceipt 在 User_Id 和 ConfigFeedItem_Id 上有一个索引。
  • 父表ConfigFeedItem有756行,数据空间0.078MB。子表 ConfigFeedItemReceipt 有 405030 行,数据空间为 27MB。
  • 那么是否在 SQL Server 上打开了任何连接/事务?您是关闭了交易还是将其留给了 NInject 来关闭它?打开的事务将保持连接打开,直到上下文被释放,事务外的查询将立即关闭连接

标签: sql linq entity-framework wcf


【解决方案1】:

我假设您使用的是带有代码优先方法的 sql server。如果是这样,请尝试在启动 dbcontext 实例期间更改默认命令超时值,如下所述。您的数据库操作可能需要比默认超时时间更长的时间。

public class YourContext : DbContext
{
    public YourContext()
        : base("YourConnectionStringName")
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
    }
}

【讨论】:

  • 我认为这不会有帮助,因为对于某些 WCF 请求,相同的查询可能会超时,但对于其他请求则不会。
猜你喜欢
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 2016-11-18
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多