我有一个查询,它联接约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秒。
此数据是只读的。我不需要更新这些记录。
我可以将其转换为存储过程吗?
这很难吗?
我将能够获得明显的性能提升吗?
答案 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
基本上,您将按照以下步骤操作。
var results = myContext.myProcedure(param1, param2);
这里有一些屏幕截图在上面的链接上。