简体   繁体   English

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

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

I was asked to investigate the cause of a poorly performing query in our database. 有人要求我调查数据库中查询效果不佳的原因。 I determined it was generated by a LINQ statement and tracked it to the source code and loaded that into linqpad. 我确定它是由LINQ语句生成的,并将其跟踪到源代码并将其加载到linqpad中。 In Linqpad I displayed the generated SQL, shown below. 在Linqpad中,我显示了生成的SQL,如下所示。 As you can see, the first part of the WHERE clause is unnecessary and greatly slows down the query by avoiding indexes. 正如您所看到的,WHERE子句的第一部分是不必要的,并且通过避免索引大大减慢了查询速度。 It should just be querying on the DocumentStorageId key and that's it. 它应该只是查询DocumentStorageId键,就是这样。 There is no point to the IN() statement, every row in the product table has one of those values, and is not null. IN()语句没有意义,product表中的每一行都有其中一个值,并且不为null。 Any ideas on how I can change my linq statement so the ID is first and hit by indexes? 关于如何更改我的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();              
}

Generated SQL Output: 生成的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)

EDIT: TO clarify further, the model is created using Code First. 编辑:为了进一步澄清,模型是使用Code First创建的。 Product is a base class. 产品是基类。 There are 6 derived types of product (Type1, Type2, etc). 有6种派生类型的产品(Type1,Type2等)。 ProductType is the discriminator column. ProductType是鉴别器列。 So it seems like EF is trying to include every possible type of Product, but why bother? 所以似乎EF试图包含所有可能的产品类型,但为什么要这么麻烦? Including all is the same as not specifying a particular one, and the IN() clause makes the query perform slowly. 包括all与未指定特定的一个相同,IN()子句使查询执行缓慢。

With TPH typed queries like the one you are doing EF needs to work out which types you are interested in. It does not know it has a complete list of types, only that when you request the root type in your application the list of derived types is as follows. 使用TPH类型的查询,例如你正在做的EF,你需要找出你感兴趣的类型。它不知道它有完整的类型列表,只有当你在应用程序中请求根类型时才会得到派生类型的列表如下。 That means that EF must include the list of types to avoid issues. 这意味着EF必须包含类型列表以避免问题。

There are two ways to resolve this. 有两种方法可以解决这个问题。

  1. Bind a non-tph DbSet in your context and use that. 在您的上下文中绑定非tph DbSet并使用它。
  2. Add an index on (ProductType, DocumentStorageId) so that the in here can be fast 在(ProductType,DocumentStorageId)上添加索引,以便在此处可以快速

There are 6 derived types of product (Type1, Type2, etc). 有6种派生类型的产品(Type1,Type2等)。 ProductType is the discriminator column. ProductType是鉴别器列。

You know this... but there is no way for EF to know this. 你知道这个......但是EF没有办法知道这一点。 For all it knows, you have 20 product types in there, but only told EF about those 6. Imagine the confusion when you asked for all of them, and it brought back 20, even though there are only 6 you programmed for. 据他所知,你有20种产品类型,但只告诉EF关于那些6.想象一下当你要求所有这些产品时的混乱,并且它带回了20,即使你只编程了6个。

Why is this Entity Framework LINQ query generating a slow where clause? 为什么此Entity Framework LINQ查询生成一个缓慢的where子句?

Therefore, in order for a query to return as expected, the in clause is used here. 因此,为了使查询按预期返回,此处使用in子句。 (Also one of the reasons I prefer TPT over TPH). (也是我更喜欢TPT而不是TPH的原因之一)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM