为什么这个实体框架LINQ查询生成一个缓慢的where子句?



我被要求调查数据库中一个性能不佳的查询的原因。我确定它是由LINQ语句生成的,并跟踪它到源代码,并将其加载到linqpad中。在Linqpad中,我显示了生成的SQL,如下所示。正如您所看到的,WHERE子句的第一部分是不必要的,并且通过避免索引大大降低了查询速度。它应该只查询DocumentStorageId键,就是这样。没有指向IN()语句的点,产品表中的每一行都有这些值之一,并且不为空。关于我如何改变我的linq语句,使ID是第一个,并通过索引命中的想法?

void Main()
{
    var uow = new UnitOfWork(this);
    var repo = new Repository<Product>(this,uow);   
    var documentStorageId = new Guid("473BAE6B-A1A1-49BE-9FD5-AB6B870A82B1");
    var result = repo.Queryable()
                .Where(x => x.DocumentStorageId == documentStorageId)                
                .FirstOrDefault();
    result.Dump();              
}

生成SQL输出:

    SELECT    
        [Extent1].[AColumn],
        [Extent1].[BColumn]
    FROM [dbo].[Product] AS [Extent1]
    WHERE
          ([Extent1].[ProductType] IN      
                (N'Type1',N'Type2',N'Type3',N'Type4',N'Type5',N'Type6')) 
     AND ([Extent1].[DocumentStorageId] = @p__linq__0)

编辑:为了进一步澄清,模型是使用代码优先创建的。Product是一个基类。有6种衍生类型的产品(Type1, Type2等)。ProductType是标识符列。因此,EF似乎试图包括所有可能的产品类型,但为什么要这么做呢?包含all与不指定特定的all是一样的,并且IN()子句会使查询执行得很慢。

对于像您正在做的这样的TPH类型查询,EF需要找出您感兴趣的类型。它不知道它有一个完整的类型列表,只知道当您请求应用程序中的根类型时,派生类型列表如下所示。这意味着EF必须包含类型列表以避免问题。

有两种方法可以解决这个问题。

  1. 在你的上下文中绑定一个非tph DbSet并使用它。
  2. 在(ProductType, DocumentStorageId)上添加索引,以便在这里可以快速查找

产品有6种派生类型(Type1、Type2等)。ProductType是标识符列。

你知道这个…但是EF没有办法知道这一点。据它所知,你有20种产品类型,但只告诉EF这6种。想象一下,当你要了所有的时候,它却给了你20个,尽管你只为6个编程了。

为什么这个实体框架LINQ查询生成一个缓慢的where子句?

因此,为了使查询按预期返回,此处使用in子句。(这也是我更喜欢TPT而不是TPH的原因之一)。

相关内容

  • 没有找到相关文章

最新更新