具有多个表联接的Entity Framework中的长时间运行查询

时间:2018-11-05 21:57:31

标签: entity-framework

我有一个查询,它联接约10个表,其中一些是自引用表。我对最上面的表的ID列(索引)使用条件“ IN”语句。

var aryOrderId = DetermineOrdersToGet(); //Logic to determine what orderids to get
var result = dbContext.Orders.Where(o=>aryOrderId.Contains(o.id)
    .Include(o=>o.Customer)
    .Include(o=>o.Items.Select(oi=>oi.ItemAttributes))
    .Include(o=>o.Items.Select(oi=>oi.Dimensions))
    .Include(o=>o.CustomOptions.Select(oc => oc.CustomOptions1))
.....A Bunch more.....
    .ToList();

我想找到一种加快速度的方法,而无需重新设计表并弄平结构。当前50-200条记录需要10-20秒。

此数据是只读的。我不需要更新这些记录。

  1. 我可以将其转换为存储过程吗?

  2. 这很难吗?

  3. 我将能够获得明显的性能提升吗?

3 个答案:

答案 0 :(得分:1)

正如jtate所提到的,如果不需要联接表中的所有内容,则不要包含它们。相反,利用.Select()仅从实体及其关联关系中检索所需的数据。

var query = dbContext.Orders
  .Where(x => aryOrderId.Contains(x => x.OrderId))
  .Select(x => new 
  {
     x.OrderId,
     x.OrderNumber,
     OrderItems = x.Items.Select(i => new 
     {
       i.ItemId,
       Attributes = i.Attributes.Select(a => a.AttributeName).ToList(),
       Dimensions = i.Dimensions.Select(d => new {d.DimensionId, d.Name}).ToList(),
     }).ToList(),
     // ...
   }).ToList();

您可以构建查询,也可以根据自己的喜好找到最佳结果。

或者,您可以考虑利用数据库上的视图并将实体绑定到该视图。该选项适用于数据的只读视图。只要提供了相关ID,您就可以随时随时检索适用的“真实”实体,以加载详细信息页面或对该实体执行操作/更新。

答案 1 :(得分:1)

数据库查询的最慢部分之一是将所选数据从DBMS传输到本地进程。因此,只选择您实际打算使用的属性是明智的。

例如,看来Order具有零个或多个ItemAttributes。 Evey ItemAttribute使用外键Order恰好属于一个OrderId

如果您在Orders中获取所有带有ID的ArryOrderId,则每个订单及其千个ItemAttributes都将使您知道,每个ItemAttribute都会有一个外键{{1} },其值与其所属的订单ID相同。发送相同值的1000倍很浪费。

  

使用实体框架查询数据时,请始终使用Select。仅选择您实际打算使用的属性。仅在打算更改获取的对象时才使用“包含”。

OrderId

如果仅选择了您打算实际使用的属性后,查询仍然花费了很长时间,请再考虑一遍:我真的需要所有这些属性吗?

另一种限制执行时间的解决方案是使用“跳过/获取”来获取日期“每页”。危险当然是,当您查看第10页时,第1页的数据可能会以不同的方式解释第10页的方式更改。

答案 2 :(得分:1)

回答您的3个问题。是的,您可以使用存储过程,这就是我在这种情况下要执行的操作。一点也不难。 EF使它非常简单。您可以让它返回新的复杂类型,也可以将其映射到实体。因为您说的数据是只读的,所以您可以使用基本函数import返回复杂类型(EF的默认行为)的方法。无论哪种方式,您都会获得明显的性能提升。

对于数据库优先,请参见http://www.entityframeworktutorial.net/stored-procedure-in-entity-framework.aspx

基本上,您将按照以下步骤操作。

  1. 在数据库上创建存储过程
  2. 从数据库更新模型。当它询问要包括哪些对象时,您应该能够选择存储过程。
  3. 单击完成。 EF会生成一个复杂类型,该类型具有存储过程返回的所有属性,并且会为执行存储过程的上下文添加一个签名,因此可以这样称呼:var results = myContext.myProcedure(param1, param2);这里有一些屏幕截图在上面的链接上。
  4. 您还可以进入并修改模型以自定义详细信息,例如复杂类型的名称和函数的名称(默认情况下,该函数将与SP的名称匹配,并返回{{1 }},其中T是您的复杂类型,它将是过程的名称,后缀为“ _Result”。