问题
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:
- You can use HQL and craft a query that gives you everything you need up front in 1 operation.
- 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