Accessing info from CommonPart is extremely slow?

不想你离开。 提交于 2019-12-11 16:57:21

问题


I'm new to Orchard and this must be something involving how the underlying data is stored.

The joining with CommonPart seems fast enough, like this:

var items = _contentManager.Query<MyUserPart, MyUserPartRecord>("someTypeName")
                           .ForVersion(VersionOptions.Published)
                           .Join<CommonPartRecord>().List().ToList();

That runs fairly fast. But whenever I try accessing some field in CommonPart, it runs extremely slow like this:

var items = _contentManager.Query<MyUserPart, MyUserPartRecord>("someTypeName")
                           .ForVersion(VersionOptions.Published)
                           .Join<CommonPartRecord>().List()
                           //access some field from commonpart
                           .Select(e => new {                               
                               User = e.As<CommonPart>().Owner.UserName
                            }).ToList();

The total data is just about 1200 items, and the time it needs is about 5 seconds, it cannot be slow like that. For a simple SQL query run in background, it should take a time of about 0.5 second or even less than.

I've tried investigating the Orchard's source code but found nothing that could be the issue. Everything seems to go into a blackbox at the accessing point of IContent. I hope someone here could give me some suggestion to diagnose and solve this hard issue. Thanks!

Update:

I've tried debugging a bit and seen that the following method is hit inside the DefaultContentManager:

ContentItem New(string contentType) { ... }

Well that's really interesting, the query is just asking for data without modifying, inserting and updating anything. But that method being hit shows that something's wrong here.

Update:

With @Bertrand Le Roy's comment, I've tried the following codes with QueryHint but looks like it does not change anything:

var items = _contentManager.Query<MyUserPart, MyUserPartRecord>("someTypeName")
                           .ForVersion(VersionOptions.Published)
                           .Join<CommonPartRecord>()
                           .WithQueryHints(new QueryHints().ExpandParts<CommonPart>())
                           .List()
                           //access some field from commonpart
                           .Select(e => new {                               
                               User = e.As<CommonPart>().Owner.UserName
                            }).ToList();

and this (without .Join)

var items = _contentManager.Query<MyUserPart, MyUserPartRecord>("someTypeName")
                           .ForVersion(VersionOptions.Published)
                           .WithQueryHints(new QueryHints().ExpandParts<CommonPart>())
                           .List()
                           //access some field from commonpart
                           .Select(e => new {                               
                               User = e.As<CommonPart>().Owner.UserName
                            }).ToList();

回答1:


Accessing the Owner property from your Select causes the lazy loader in CommonPartHandler to ask the content manager to load the user content item: _contentManager.Get<IUser>(part.Record.OwnerId). This happens once per content item result from your query, so results in a select n+1 where n = 1200 according to your question.

There are at least two ways of avoiding that:

  1. You can use HQL and craft a query that gives you everything you need up front in 1 operation.
  2. You can make a 1st content manager query to get the set of owner ids, and then make a second content manager query for those Ids and get everything you need with a total of 2 queries instead of 1201.


来源:https://stackoverflow.com/questions/55507342/accessing-info-from-commonpart-is-extremely-slow

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!