entity-framework - EF6 SQL 生成 <where 可空列等于>

标签 entity-framework entity-framework-6

在尝试从 EF5 升级到 EF6 时,我遇到了按可空列搜索表的显着性能差距。这是一个示例:

public class Customer
{
    public int Id { get; set; }
    public int? ManagerId { get; set; }
    //public virtual Manager Manager { get; set; }
}

public class MyContext : DbContext
{
    public MyContext(string connstring): base(connstring){}
    public DbSet<Customer> Customers { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var db = new MyContext("CONNSTRING");
        var managerId = 1234;
        var q = from b in db.Customers
                where b.ManagerId == managerId
                select b.Id;
        var s = q.ToString();
    }
}

当 EF6 生成 SQL 时,它会添加一些用于 null 处理的逻辑:
SELECT 
[Extent1].[Id] AS [Id]
FROM [dbo].[Customers] AS [Extent1]
WHERE (([Extent1].[ManagerId] = @p__linq__0) 
AND ( NOT ([Extent1].[ManagerId] IS NULL OR @p__linq__0 IS NULL))) 
OR (([Extent1].[ManagerId] IS NULL) AND (@p__linq__0 IS NULL))

注意同样的 linq 在 EF5 下产生了更简单的 SQL:
SELECT 
[Extent1].[Id] AS [Id]
FROM [dbo].[Customers] AS [Extent1]
WHERE [Extent1].[ManagerId] = @p__linq__0

我可以理解开发人员试图实现的观点:如果您提供 null 作为参数,则 managerId = null 的查询将不会选择任何行。我感谢您的关心,但 99.9% 的搜索逻辑是分开的:一个用例查找 where ManagerId == null , 另一个搜索特定 id where ManagerId == managerId
问题在于性能影响很大:MS SQL 不使用 ManagerId 上的索引,并且发生了表扫描。我的项目有数百个类似的搜索,在升级到 EF6 后,数据库大小约为 100GB,整体性能减少了大约 10 个。

问题是有人知道在 EF6 中禁用此障碍并生成简单 sql 的某种配置或约定吗?

编辑:

我在我的项目中检查了十几个类似的选择,发现:
  • 在某些情况下,SQL SERVER 确实使用为字段 I 指定的索引
    搜索。即使在这种情况下也有轻微的性能损失:它
    两次使用索引:第一次查找我在中指定的值
    参数,第二次寻找空值
  • 当常量被精确指定为非空时,EF6 甚至会检查空值,例如:
                from p in db.PtnActivations
            where p.Carrier != "ALLTEL"
            where p.Carrier != "ATT"
            where p.Carrier != "VERIZON"
    

  • 生成 SQL
        WHERE ( NOT (('ALLTEL' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL))) AND ( NOT (('ATT' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL))) AND ( NOT (('VERIZON' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL)))
    

    没有利用我在运营商上的索引。 EF5 版本有
    ( NOT (('ALLTEL' = [Extent1].[Carrier]))) AND ( NOT (('ATT' = [Extent1].[Carrier]))) AND ( NOT (('VERIZON' = [Extent1].[Carrier]) ))
    

    那个利用了它。

    注意条件 ('ALLTEL' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL) .第二部分是 总是 false,但添加此部分会放弃索引。

    我的大约 170 万条记录(通常需要大约 30 分钟)的例行导入持续了 3 小时,进度约为 30%。

    最佳答案


    db.Configuration.UseDatabaseNullSemantics = true;
    

    获得您在 EF5 中的行为。此 workitem描述了 true 之间的区别和 false是并且应该帮助您决定您是否接受旧行为。

    关于entity-framework - EF6 SQL 生成 <where 可空列等于>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19672799/

    相关文章:

    c# - 具有 2 个外键 Entity Framework 的表

    c# - 构建仅包含字段名称的 linq 表达式

    c# - 按 Entity Framework 中的子表排序

    c# - ODP.Net 托管驱动程序 - ORA-12704 : character set mismatch in generated code

    asp.net - 如何在 ASP.NET Core 1.0 应用程序中使用 SqlServer.Types/空间类型

    c# - Entity Framework 代码优先 Fluent API

    c# - 插入迁移

    c# - 在 IIS 上部署时的数据库连接问题

    c# - 如何在 OfType() 之后使用 Include()?

    c# - Entity Framework 代码优先迁移