为什么这个 Entity Framework LINQ 查询生成一个缓慢的 where 子句?

Why is this Entity Framework LINQ query generating a slow where clause?

我被要求调查我们数据库中查询性能不佳的原因。我确定它是由 LINQ 语句生成的,并将其跟踪到源代码并将其加载到 linqpad 中。在 Linqpad 中,我显示了生成的 SQL,如下所示。如您所见,WHERE 子句的第一部分是不必要的,并且通过避免索引大大减慢了查询速度。它应该只是查询 DocumentStorageId 键,仅此而已。 IN() 语句没有意义,产品 table 中的每一行都具有这些值之一,并且不为空。关于如何更改我的 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)

编辑:为了进一步说明,该模型是使用代码优先创建的。产品是基础 class。有 6 种派生类型的产品(Type1、Type2 等)。 ProductType 是鉴别器列。所以看起来 EF 正在尝试包括所有可能的产品类型,但何必呢?包括所有与不指定特定的相同,并且 IN() 子句使查询执行缓慢。

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

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

  1. 在您的上下文中绑定一个非 tph DbSet 并使用它。
  2. 在 (ProductType, DocumentStorageId) 上添加索引,以便此处可以更快

There are 6 derived types of product (Type1, Type2, etc). ProductType is the discriminator column.

你知道这一点...但 EF 无法知道这一点。就其所知,你有 20 种产品类型,但只告诉 EF 关于这 6 种。想象一下当你要求所有这些时的混乱,它带回了 20 种,即使你只为 6 种编程。

Why is this Entity Framework LINQ query generating a slow where clause?

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