【发布时间】: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_Id和ConfigFeedItem_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