Entity Framework Core 3.0 查询导致“SqlException: 'Execution Timeout Expired'”和 tempdb 变满。适用于 EF Core 2.2.6

Ogg*_*las 7 c# sql-server entity-framework entity-framework-core entity-framework-core-3.0

我正在 Microsoft Entity Framework Core 3.0 中运行一个相当简单的查询,如下所示:

var dbProfile = db.Profiles.Where(x => x.SiteId == Int32.Parse(id))
    .Include(x => x.Interests)
    .Include(x => x.Pets)
    .Include(x => x.Networks)
    .Include(x => x.PersonalityTraits)
    .SingleOrDefault();
Run Code Online (Sandbox Code Playgroud)

它在 EF Core 2.2.6 上运行良好,但是当升级到 EF Core 3.0 时,此查询会立即针对 721 个配置文件运行,但对于至少一个配置文件,查询超时:

Microsoft.Data.SqlClient.SqlException: '执行超时已过期。
操作完成之前超时时间已过或服务器没有响应。

然后我记录了发送到数据库服务器的实际查询:

/sf/answers/4084371161/

SELECT [t].[Id], [t].[Age], [t].[City], [t].[Country], [t].[County], [t].[DeactivatedAccount], [t].[Gender], [t].[HasPictures], [t].[LastLogin], [t].[MemberSince], [t].[PresentationUpdated], [t].[ProfileName], [t].[ProfilePictureUrl], [t].[ProfileText], [t].[SiteId], [t].[VisitorsCount], [i].[Id], [i].[Name], [i].[ProfileId], [p0].[Id], [p0].[Description], [p0].[Name], [p0].[ProfileId], [n].[Id], [n].[Name], [n].[NetworkId], [n].[ProfileId], [p1].[Id], [p1].[Name], [p1].[ProfileId]
FROM (
    SELECT TOP(2) [p].[Id], [p].[Age], [p].[City], [p].[Country], [p].[County], [p].[DeactivatedAccount], [p].[Gender], [p].[HasPictures], [p].[LastLogin], [p].[MemberSince], [p].[PresentationUpdated], [p].[ProfileName], [p].[ProfilePictureUrl], [p].[ProfileText], [p].[SiteId], [p].[VisitorsCount]
    FROM [Profiles] AS [p]
    WHERE ([p].[SiteId] = '123') AND '123' IS NOT NULL
) AS [t]
LEFT JOIN [Interests] AS [i] ON [t].[Id] = [i].[ProfileId]
LEFT JOIN [Pets] AS [p0] ON [t].[Id] = [p0].[ProfileId]
LEFT JOIN [Networks] AS [n] ON [t].[Id] = [n].[ProfileId]
LEFT JOIN [PersonalityTraits] AS [p1] ON [t].[Id] = [p1].[ProfileId]
ORDER BY [t].[Id], [i].[Id], [p0].[Id], [n].[Id], [p1].[Id]
Run Code Online (Sandbox Code Playgroud)

然后我尝试在 SSMS 中运行实际的 SQL 并最终出现以下错误:

消息 1105,级别 17,状态 2,第 1 行
无法为数据库“tempdb”中的对象“dbo.SORT 临时运行存储:140737692565504”分配空间,因为“PRIMARY”文件组已满。通过删除不需要的文件、删除文件组中的对象、向文件组添加其他文件或为文件组中的现有文件设置自动增长来创建磁盘空间。

tempdb现在已经完全填满了数据库磁盘。我尝试了 10 个其他 ID,并且立即运行了相同的查询。

我试图用命令再次缩小 tempdb DBCC SHRINKDATABASE(tempdb, 10);,它工作正常。然而,当我再次尝试运行查询时,同样的事情发生了。如果我跳过包括表格一切正常。这里可能有什么问题,我该如何解决?这是 EF Core 3.0 中的已知错误吗?查看 EF Core 2.2.6 中的查询,它对所有表执行这样的单独选择:

SELECT [x.Interests].[Id], [x.Interests].[Name], [x.Interests].[ProfileId]
FROM [Interests] AS [x.Interests]
INNER JOIN (
    SELECT TOP(1) [x0].[Id]
    FROM [Profiles] AS [x0]
    WHERE [x0].[SiteId] = '123'
    ORDER BY [x0].[Id]
) AS [t] ON [x.Interests].[ProfileId] = [t].[Id]
ORDER BY [t].[Id]
Run Code Online (Sandbox Code Playgroud)

Dav*_*oft 6

这是 EF Core 3 中记录的重大更改:相关实体的急切加载现在发生在单个查询中

新行为类似于 EF6 中的查询生成,其中多个包含可以创建非常大且昂贵的查询。这些查询也可能由于超时、查询计划生成成本或查询执行资源耗尽而失败。

因此,就像在 EF6 中一样,您需要避免包含多个不相关的实体包含路径,因为它们会创建非常昂贵的查询。

相反,您可以使用延迟加载,或在单独的查询中显式加载实体图的一部分,并让更改跟踪器修复导航属性。

EF 5 添加了一个选项来关闭一个名为Split Queries的大查询生成。

  • 我们似乎偶然发现了同样的问题。我只是想确认一下是否是同一个问题。从 2.2 升级到 3.1 后,我们还会遇到查询超时的情况,但似乎并不是每次都会发生这种情况。19/20 查询将在 100 毫秒内运行,1/20 将运行 5 分钟并且永远不会完成。这就是这件事的奇怪之处。我可以理解性能下降,但我不明白的是缺乏一致性。 (3认同)