实体框架生成的SQL缺少联接

时间:2018-11-01 19:36:32

标签: performance entity-framework linq

我们注意到此查询的读取次数很高:

var var1 = "535d1a11-1c2b-467a-3333-222aaa9b1fd4";
var var2 = 117;
var test = (from t1 in contextObj.Table1
    join t2 in contextObj.Table2
        on t1.Column2 equals t2.Column1
    join t3 in contextObj.Table3 on t2.Column2 equals t3.Column1
    where t3.Column1 == var1 && t2.Column3 == var2
                             && t2.Column2 == var1
    select t1).ToList();

这是因为Entity Framework生成的SQL缺少联接:

exec sp_executesql N'SELECT 
    [Extent1].[Column1] AS [Column1], 
    [Extent1].[Column2] AS [Column2], 
    [Extent1].[Column3] AS [Column3], 
    [Extent1].[Column4] AS [Column4], 
    [Extent1].[Column5] AS [Column5], 
    [Extent1].[Column6] AS [Column6]
    FROM  [dbo].[Table1] AS [Extent1]
    INNER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Column2] = [Extent2].[Column1]
    WHERE ([Extent2].[Column2] = @p__linq__0) AND ([Extent2].[Column3] = @p__linq__1) AND ([Extent2].[Column2] = @p__linq__2)',N'@p__linq__0 nvarchar(4000),@p__linq__1 int,@p__linq__2 nvarchar(4000)',@p__linq__0=N'535d5b16-1c2b-467a-9022-933ebf9b1fd4',@p__linq__1=117,@p__linq__2=N'535d5b16-1c2b-467a-9022-933ebf9b1fd4'

数据库创建脚本:https://gist.github.com/jbouwens/85e8840d799b8178ee30feb389fbc4ac

为什么EF不包括此联接/将来我该怎么做以防止这种情况?谢谢!

2 个答案:

答案 0 :(得分:2)

在您的查询中,where子句正在比较t3.Column1 == var1和t2.Column2 == var1,但是由于您的联接已经考虑到t3.Column1 == t2.Column2,因此EF会自动删除它假定是不需要的联接。由于表结构不是理想的,因此已确定解决方案是从table3返回一个列以强制EF联接到该表。

var test = (from t1 in contextObj.Table1new 
    join t2 in contextObj.Table2
        on t1.Column2 equals t2.Column1
    join t3 in contextObj.Table3 on t2.Column2 equals t3.Column1
    where t3.Column1 == var1 && t2.Column3 == var2
    select new { t1, t3.Column1 }).ToList()

答案 1 :(得分:1)

我对此表示赞同,并且EF在其查询生成中“信任”了您声明的外键,SQL Server也将这样做(如果您强制执行并检查了它们)。

由于您在查询中加入了这些列,EF会将谓词t3.Column1 == var1转换为[Extent2].[Column3] = @p__linq__1,并且外键保证该联接将更改行数。