使用ANY时,实体框架生成了非常糟糕的SQL

时间:2017-04-28 15:38:23

标签: sql-server entity-framework

我正在分析在数据库(Azure Sql Server V12)中运行的查询,我发现实体框架(EF 6.0)生成的一些查询对我来说毫无意义。它们对性能非常不利,我找不到它们的生成位置。

(@p__linq__0 nvarchar(4000))SELECT 
    CASE WHEN ( EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[SellerPhone] AS [Extent1]
        WHERE [Extent1].[Phone] = @p__linq__0
    )) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[SellerPhone] AS [Extent2]
        WHERE [Extent2].[Phone] = @p__linq__0
    )) THEN cast(0 as bit) END AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]

解决方案:如果你有这样的查询,这意味着你有EF 6.0或更早版本,而你正在做一个简单的dbContext.SellerPhones.Any(p => xxx)。只需升级到6.1,生成的查询就会好得多。

2 个答案:

答案 0 :(得分:1)

要查找生成查询的位置,请启用EF日志记录(控制台或日志记录框架。)启用后,尝试查找部分查询(如[dbo].[SellerPhone] AS [Extent2])您的日志以及查询周围的其他日志,您应该知道自己的位置。

这可以帮助您启用日志记录:

public MyContext : DbContext
{
    private static ILog log = LogManager.GetCurrentClassLogger();

    public MyContext(string connectionString)
        : base(connectionString)
    {
        this.Database.Log = (msg) => log.Trace(msg);
    }
}

答案 1 :(得分:0)

我做了Tipx描述的内容,但我还添加了堆栈跟踪,以便能够知道生成每个查询的方法:

Database.Log = (sql => 
            {
                System.Diagnostics.Debug.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);
                System.Diagnostics.Debug.WriteLine(sql);
            });

在EF 6.0中,像dbContext.SellerPhones.Any(p => condition)之类的简单查询将生成一个丑陋的查询,该查询具有CASE并调用两次EXISTS。

升级到EF 6.1后,查询只有一个EXESTS并且执行得更好(我在下面突出显示了已更新的生成查询的部分)。

选择     情况(存在(选择         1 AS [C1]         FROM [dbo]。[SellerPhone] AS [Extent1]         在哪里[Extent1]。[电话] = @ p__linq__0     ))然后施放(1比特)ELSE 施放(0比特)结束AS [C1]     FROM(SELECT 1 AS X)AS [SingleRowTable1]