EntityFramework中的ObjectSet包含多less个可用于保持性能?
我正在使用以下的LINQ查询我的个人资料页面:
var userData = from u in db.Users .Include("UserSkills.Skill") .Include("UserIdeas.IdeaThings") .Include("UserInterests.Interest") .Include("UserMessengers.Messenger") .Include("UserFriends.User.UserSkills.Skill") .Include("UserFriends1.User1.UserSkills.Skill") .Include("UserFriends.User.UserIdeas") .Include("UserFriends1.User1.UserIdeas") where u.UserId == userId select u;
它有一个很长的对象图,并使用许多包括。 它现在运行的很完美,但是当网站有很多用户时,会不会影响性能呢?
我应该以其他方式做吗?
带有包含的查询返回单个结果集,包含的数量会影响数据集从数据库服务器传输到Web服务器的大小。 例:
假设我们有一个实体Customer (Id, Name, Address)
和一个实体Order (Id, CustomerId, Date)
。 现在我们想用她的订单来查询客户:
var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == 1);
结果数据集将具有以下结构:
Id | Name | Address | OrderId | CustomerId | Date --------------------------------------------------- 1 | A | XYZ | 1 | 1 | 1.1. 1 | A | XYZ | 2 | 1 | 2.1.
这意味着每个Order
重复Cutomers
数据。 现在让我们用另一个实体 – “OrderLine(Id,OrderId,ProductId,Quantity) and
Product(Id,Name)`来扩展这个例子。 现在我们要用她的订单,订单行和产品来查询客户:
var customer = context.Customers .Include("Orders.OrderLines.Product") .SingleOrDefault(c => c.Id == 1);
结果数据集将具有以下结构:
Id | Name | Address | OrderId | CustomerId | Date | OrderLineId | LOrderId | LProductId | Quantity | ProductId | ProductName ------------------------------------------------------------------------------------------------------------------------------ 1 | A | XYZ | 1 | 1 | 1.1. | 1 | 1 | 1 | 5 | 1 | AA 1 | A | XYZ | 1 | 1 | 1.1. | 2 | 1 | 2 | 2 | 2 | BB 1 | A | XYZ | 2 | 1 | 2.1. | 3 | 2 | 1 | 4 | 1 | AA 1 | A | XYZ | 2 | 1 | 2.1. | 4 | 2 | 3 | 6 | 3 | CC
正如你所看到的,数据变得相当重复。 通常每个都包含一个参考导航样本(示例中的Product
)将添加新列,并且每个列都包含一个集合导航属性(示例中的Orders
和OrderLines
)将添加新列并复制已包含集合中每行的已创build行。
这意味着你的例子可以很容易地有数百列和数千行,这是很多数据传输。 正确的方法是创build性能testing,如果结果不能满足您的期望,您可以通过自己的查询或LoadProperty
方法分别修改查询和加载导航属性。
单独查询的示例:
var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == 1); var orderLines = context.OrderLines .Include("Product") .Where(l => l.Order.Customer.Id == 1) .ToList();
LoadProperty
示例:
var customer = context.Customers .SingleOrDefault(c => c.Id == 1); context.LoadProperty(customer, c => c.Orders);
你也应该只加载你真正需要的数据。
编辑:我刚刚在Data UserVoice上创build提案,以支持额外的预先加载策略,其中预先加载的数据将被传递到附加结果集中(由同一数据库往返中的单独查询创build)。 如果你觉得这个改进有趣,不要忘了投票。
您可以通过创build2个或更多来自下面的数据库的小数据请求来提高许多包括的性能。
根据我的经验, 每个查询最多只能给出2个以下的结果,这样会给性能带来不好的影响。
var userData = from u in db.Users .Include("UserSkills.Skill") .Include("UserIdeas.IdeaThings") .FirstOrDefault(); userData = from u in db.Users .Include("UserFriends.User.UserSkills.Skill") .Include("UserFriends1.User1.UserSkills.Skill") .FirstOrDefault();
以上将通过使用更多的旅行到数据库从数据库中带来小的数据集。
我已经用自己的经验写了博客文章
我希望这对你有帮助。
是的,它会。 如果在主表行上展开多个详细信息行,请避免使用“包含”。
我相信EF将查询转换成一个大的联接,而不是几个查询。 因此,您最终将在详细信息表的每一行上复制主表数据。
例如:Master – > Details。 说,主人有100行,详细信息有5000行(每个主人50)。
如果您延迟加载细节,则返回100行(size:master)+ 5000行(size:details)。
如果使用.Include(“Details”),则返回5000行(size:master + details)。 基本上,主部分被复制超过50次。
如果包含多个表格,它会向上扩展。
检查EF生成的SQL。
我build议你进行负载testing,并测量压力下的网站性能。 如果你对每个请求执行复杂的查询,你可能会考虑caching一些结果。
包含的结果可能会改变:它由调用include方法的实体来决定。
就像Ladislav Mrnka提出的例子一样,假设我们有一个实体
客户(身份证,姓名,地址)
映射到这个表格:
Id | Name | Address ----------------------- C1 | Paul | XYZ
和实体订单(Id,CustomerId,Total)
映射到这个表格:
Id | CustomerId | Total ----------------------- O1 | C1 | 10.00 O2 | C1 | 13.00
关系是一个客户对许多订单
示例1:客户=>订单
var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == "C1");
Linq将被翻译成一个非常复杂的SQL查询。
在这种情况下,查询将产生两条logging,关于客户的信息将被复制。
Customer.Id | Customer.Name | Order.Id | Order.Total ----------------------------------------------------------- C1 | Paul | O1 | 10.00 C1 | Paul | O2 | 13.00
示例2:Order => Customer
var order = context.Orders .Include("Customers") .SingleOrDefault(c => c.Id == "O1");
Linq将在一个简单的sqljoin中进行翻译。
在这种情况下,查询将只产生一个没有重复信息的logging:
Order.Id | Order.Total | Customer.Id | Customer.Name ----------------------------------------------------------- O1 | 10.00 | C1 | Paul