【发布时间】:2015-09-23 10:55:30
【问题描述】:
我很难在我的应用程序中调整我的Entity Framework 生成的查询之一。这是非常基本的查询,但出于某种原因,EF 使用了多个内部子查询,这些子查询似乎在DB 中执行得非常糟糕,而不是使用连接。
这是我的 LINQ 代码:
Projects.Select(proj => new ProjectViewModel()
{
Name = proj.Name,
Id = proj.Id,
Total = proj.Subvalue.Where(subv =>
subv.Created >= startDate
&& subv.Created <= endDate
&&
(subv.StatusId == 1 ||
subv.StatusId == 2))
.Select(c => c.SubValueSum)
.DefaultIfEmpty()
.Sum()
})
.OrderByDescending(c => c.Total)
.Take(10);
EF 生成具有多个子查询的非常复杂的查询,其查询性能非常糟糕,如下所示:
SELECT TOP (10)
[Project3].[Id] AS [Id],
[Project3].[Name] AS [Name],
[Project3].[C1] AS [C1]
FROM ( SELECT
[Project2].[Id] AS [Id],
[Project2].[Name] AS [Name],
[Project2].[C1] AS [C1]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
(SELECT
SUM([Join1].[A1]) AS [A1]
FROM ( SELECT
CASE WHEN ([Project1].[C1] IS NULL) THEN cast(0 as decimal(18)) ELSE [Project1].[SubValueSum] END AS [A1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent2].[SubValueSum] AS [SubValueSum],
cast(1 as tinyint) AS [C1]
FROM [dbo].[Subvalue] AS [Extent2]
WHERE ([Extent1].[Id] = [Extent2].[Id]) AND ([Extent2].[Created] >= '2015-08-01') AND ([Extent2].[Created] <= '2015-10-01') AND ([Extent2].[StatusId] IN (1,2)) ) AS [Project1] ON 1 = 1
) AS [Join1]) AS [C1]
FROM [dbo].[Project] AS [Extent1]
WHERE ([Extent1].[ProjectCountryId] = 77) AND ([Extent1].[Active] = 1)
) AS [Project2]
) AS [Project3]
ORDER BY [Project3].[C1] DESC;
EF生成查询的执行时间为~10 seconds。但是当我像这样手动编写查询时:
select
TOP (10)
Proj.Id,
Proj.Name,
SUM(Subv.SubValueSum) AS Total
from
SubValue as Subv
left join
Project as Proj on Proj.Id = Subv.ProjectId
where
Subv.Created > '2015-08-01' AND Subv.Created <= '2015-10-01' AND Subv.StatusId IN (1,2)
group by
Proj.Id,
Proj.Name
order by
Total DESC
执行时间接近即时;下面30ms。
问题显然在于我使用 LINQ 编写好的 EF 查询的能力,但无论我尝试做什么(使用 Linqpad 进行测试)我都无法像我一样使用 LINQ\EF 编写类似的高性能查询可以手写。我尝试查询 SubValue 表和 Project 表,但结果基本相同:多个无效的嵌套子查询而不是单个连接完成工作。
如何编写一个模仿上面显示的手写SQL 的查询?如何控制EF 生成的实际查询?最重要的是:我怎样才能让Linq2SQL 和Entity Framework 在我想使用Joins 而不是嵌套子查询时使用。
【问题讨论】:
-
使用 LINQ 你很可能使用
DataContext。看看DataContext.LoadOptions属性here.. -
设置 context.ObjectTrackingEnabled = false,你会得到很大的提升。
-
@JanUnld 感谢您的建议,但我不确定它对这个特定问题有何帮助?能详细解释一下吗?
-
@Nikita 问题未跟踪。问题是 EF 生成的查询非常无效,我想知道如何更好地控制 EF/ling2sql 生成的实际 SQL。那么我怎样才能让它使用连接而不是无效的子查询呢?
-
实体框架和 LINQ To SQL 不一样。生成的 SQL 看起来像是由实体框架生成的。如果这是正确的,我建议您删除 [linq-to-sql] 标记并添加 [entity-framework] 标记。
标签: c# sql-server entity-framework linq