为什么这个 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 必须包含类型列表以避免出现问题。
有两种方法可以解决这个问题。
- 在您的上下文中绑定一个非 tph DbSet 并使用它。
- 在 (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 的原因之一)。
我被要求调查我们数据库中查询性能不佳的原因。我确定它是由 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 必须包含类型列表以避免出现问题。
有两种方法可以解决这个问题。
- 在您的上下文中绑定一个非 tph DbSet 并使用它。
- 在 (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 的原因之一)。