我可以在 EntityFramework 中的 ObjectSet 上使用多少个 Include 以保持性能?
我正在为我的个人资料页面使用以下 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;
它有一个很长的对象图并使用许多 Include。目前运行完美,但是当网站用户较多时,性能会不会受到很大影响?
我应该用其他方式来做吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
包含包含的查询返回单个结果集,包含的数量会影响大数据集从数据库服务器传输到 Web 服务器的方式。示例:
假设我们有一个实体
Customer (Id, Name, Address)
和一个实体Order (Id, CustomerId, Date)
。现在我们要查询客户的订单:生成的数据集将具有以下结构:
这意味着每个
Order
都会重复Cutomers
数据。现在让我们使用另一个实体扩展该示例 -“OrderLine (Id, OrderId, ProductId, Quantity)and
Product (Id, Name)”。现在我们要查询客户的订单、订单行和产品:生成的数据集将具有以下结构:
如您所见,数据变得相当多重复。通常,每个引用导航属性(示例中的
Product
)的包含都会添加新列,并且每个包含到集合导航属性(Orders
和OrderLines
> 在示例中)将为所包含集合中的每一行添加新列并复制已创建的行。这意味着您的示例可以轻松拥有数百列和数千行,这是需要传输的大量数据。正确的方法是创建性能测试,如果结果不能满足您的期望,您可以通过自己的查询或通过 LoadProperty 方法单独修改查询和加载导航属性。
单独查询的示例:
LoadProperty
示例:此外,您应该始终仅加载真正需要的数据。
编辑:我刚刚创建了关于 Data UserVoice 的提案,支持额外的急切加载策略,其中急切加载的数据将在附加结果集中传递(由同一数据库往返中的单独查询创建)。如果您发现此改进很有趣,请不要忘记投票支持该提案。
A query with includes returns a single result set and the number of includes affect how big data set is transfered from the database server to the web server. Example:
Suppose we have an entity
Customer (Id, Name, Address)
and an entityOrder (Id, CustomerId, Date)
. Now we want to query a customer with her orders:The resulting data set will have the following structure:
It means that
Cutomers
data are repeated for eachOrder
. Now lets extend the example with another entities - 'OrderLine (Id, OrderId, ProductId, Quantity)and
Product (Id, Name)`. Now we want to query a customer with her orders, order lines and products:The resulting data set will have the following structure:
As you can see data become quite a lot duplicated. Generaly each include to a reference navigation propery (
Product
in the example) will add new columns and each include to a collection navigation property (Orders
andOrderLines
in the example) will add new columns and duplicate already created rows for each row in the included collection.It means that your example can easily have hundreds of columns and thousands of rows which is a lot of data to transfer. The correct approach is creating performance tests and if the result will not satisfy your expectations, you can modify your query and load navigation properties separately by their own queries or by
LoadProperty
method.Example of separate queries:
Example of
LoadProperty
:Also you should always load only data you really need.
Edit: I just created proposal on Data UserVoice to support additional eager loading strategy where eager loaded data would be passed in additional result set (created by separate query within the same database roundtrip). If you find this improvement interesting don't forget to vote for the proposal.
(您可以通过从数据库创建 2 个或更多小数据请求来提高许多包含的性能,如下所示。
根据我的经验,只能为每个查询提供最多 2 个包含,例如超过这个数量将会带来非常糟糕的性能。
上面将通过使用更多的数据库访问来从数据库中带来小数据集。
(You can improve performance of many includes by creating 2 or more small data request from data base like below.
According to my experience,Only can give maximum 2 includes per query like below.More than that will give really bad performance.
Above will bring small data set from database by using more travels to the database.
是的,会的。如果使用 Include 扩展主表行上的多个详细信息行,请避免使用 Include。
我相信 EF 会将查询转换为一个大型联接而不是多个查询。因此,您最终将在详细信息表的每一行上复制主表数据。
例如:大师->细节。假设 master 有 100 行,Details 有 5000 行(每个 master 50 行)。
如果延迟加载详细信息,则会返回 100 行(大小:master)+ 5000 行(大小:详细信息)。
如果您使用 .Include("Details"),您将返回 5000 行(大小:主数据 + 详细信息)。本质上,主部分被复制了 50 多次。
如果包含多个表,它会向上增加。
检查EF生成的SQL。
Yes it will. Avoid using Include if it expands multiple detail rows on a master table row.
I believe EF converts the query into one large join instead of several queries. Therefore, you'll end up duplicating your master table data over every row of the details table.
For example: Master -> Details. Say, master has 100 rows, Details has 5000 rows (50 for each master).
If you lazy-load the details, you return 100 rows (size: master) + 5000 rows (size: details).
If you use .Include("Details"), you return 5000 rows (size: master + details). Essentially, the master portion is duplicated over 50 times.
It multiplies upwards if you include multiple tables.
Check the SQL generated by EF.
我建议您执行负载测试并测量网站在压力下的性能。如果您对每个请求执行复杂的查询,您可以考虑缓存一些结果。
I would recommend you to perform load tests and measure the performance of the site under stress. If you are performing complex queries on each request you may consider caching some results.
include 的结果可能会改变:它取决于调用 include 方法的实体。
就像 Ladislav Mrnka 提出的示例一样,假设我们有一个
实体Customer(Id、Name、Address)
映射到的 此表:
实体订单(Id、CustomerId、Total)
以及映射到此表的
:关系是一个客户与许多订单
示例 1:Customer = >订单
Linq 将转换为非常复杂的 SQL 查询。
在这种情况下,查询将生成两条记录,并且将复制有关客户的信息。
示例 2:订单 => Customer
Linq 将被转换为简单的 sql Join。
在这种情况下,查询将仅生成一条记录,没有重复的信息:
The result of include may change: it depend by the entity that call the include method.
Like the example proposed from Ladislav Mrnka, suppose that we have an entity
Customer (Id, Name, Address)
that map to this table:
and an entity Order (Id, CustomerId, Total)
that map to this table:
The relation is one Customer to many Orders
Esample 1: Customer => Orders
Linq will be translated in a very complex sql query.
In this case the query will produce two record and the informations about the customer will be replicated.
Esample 2: Order => Customer
Linq will be translated in a simple sql Join.
In this case the query will produce only one record with no duplication of informations: