EF6 SQL生成<其中可为空的列等于>

Ben

尝试从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时,会添加一些用于空值处理的逻辑:

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,另一个寻找特定IDwhere ManagerId == managerId

问题在于对性能的影响很大:MS SQL不对ManagerId使用索引,并且发生表扫描。我的项目有数百个类似的搜索,并且在升级到EF6后,数据库大小的整体性能约为100GB,大约减少了10%。

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

编辑:

我检查了项目中的十几个类似选择,发现:

  • 在某些情况下,SQL SERVER会使用为我搜索的字段指定的索引。即使在这种情况下,也会有轻微的性能损失:它两次使用索引:第一次寻找参数中指定的值,第二次寻找null
  • 当常量被精确地指定为非空值时,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)第二部分总是错误的,但是添加这部分将放弃索引。

我的常规导入大约170万条记录(通常需要大约30分钟)最多需要3个小时,并且进度约为30%。

帕维尔

db.Configuration.UseDatabaseNullSemantics = true;

获得您在EF5中的行为。工作项描述了和之间的区别truefalse并应帮助您确定您是否同意旧的行为。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

EF6为可为空的外键生成空子实体

来自分类Dev

为什么EF6 LINQ无法为空字符串变量比较生成正确的“是否为空” SQL?

来自分类Dev

在代码优先EF6中使用SqlGeography不生成列

来自分类Dev

EF6 生成不需要的 SQL 查询

来自分类Dev

通过 EF6 在方法链上获取生成的 sql

来自分类Dev

EF6和预生成的视图

来自分类Dev

EF6代码首先使用数据注释来填充有关SQL表和列的描述

来自分类Dev

阻止EF6生成导航属性

来自分类Dev

无法使用EF6和MYSQL生成实体

来自分类Dev

EF6 Code First预生成的C#视图

来自分类Dev

EF6并不总是生成FK参考

来自分类Dev

Firebird主键和EF6存储生成的模式

来自分类Dev

阻止在EF6中为特定实体生成表

来自分类Dev

EF6:在SQL Server DB的模型生成中无法识别外键

来自分类Dev

EF6 MySql:Update-Database -Script生成不带分号的SQL

来自分类Dev

通用EF6存储库方法无法生成正确的SQL

来自分类Dev

EF6:在SQL Server DB的模型生成中无法识别外键

来自分类Dev

EF6获取记录,其中来自两个不同表的信息等于x

来自分类Dev

我应该从SQL CLR函数使用EF6吗

来自分类Dev

在EF6中执行复杂的原始SQL查询

来自分类Dev

EF6中的方法链接无法输出正确的SQL

来自分类Dev

EF6升级后的额外SQL调用

来自分类Dev

我应该从SQL CLR函数使用EF6吗

来自分类Dev

EF6中的方法链接无法输出正确的SQL

来自分类Dev

使用EF6将两列的var变量合并

来自分类Dev

EF为可为空的实体生成了不需要的SQL

来自分类Dev

在具有EF Core 3.1的SQL Server上生成不可为空的rowversion

来自分类Dev

从EF4升级后,在EF6中查询数据的空引用异常

来自分类Dev

向EF6生成的实体类添加属性

Related 相关文章

热门标签

归档