开发者

Nhibernate, painfully slow query, am I doing it wrong?

开发者 https://www.devze.com 2023-03-23 03:21 出处:网络
I have some major performance issues when asking a specific nhibernate question. I have two tables, A and B where A has ~4000 rows and B has ~50 000 rows. The relation between A and B is one to many.

I have some major performance issues when asking a specific nhibernate question.

I have two tables, A and B where A has ~4000 rows and B has ~50 000 rows. The relation between A and B is one to many.

So the question that I ask needs to load all entites in A and then force load all entities in B because I want to aggregate over the entities in B.

I'm using fluenthibernate and have configured it to allow lazyloading, this works great for all other questions except this one where I have to load ~50000 entities, this number will likely grow with 50k a month. The question takes above a minute to ask now (probably even slower)

Obvious optimizations that I've already done: Only create one sessionfactory, lazyloading is not turned off.

So my question is this, will nhibernate be to slow in this aspect ? (that is, should I build my DAL with regular SQL questions rather than nhibernate?) or is there a way to improve the performance. This is a reporting application, so there won't be many concurrent users but I still would like to make this question atleast take less then 5-10 seconds.

EDIT Adding code:

public class ChatSessions
{
    public virtual int Id { get; set; }
    public virtual IList<ChatComments> Comments { get; set; }

    public ChatSessions()
    {
        Comments = new List<ChatComments>();
    }
}

public ChatCommentsMapping()
{
    Id(x => x.Id);
    References(x => x.ChatSession);
}

public class ChatComments
{
    public virtual int Id { get; set; }
    public virtual ChatSessions ChatSession{ get; set; }
    public virtual string Comment { get; set; }
    public virtual DateTime TimeStamp { get; set; }
    public virtual int CommentType { get; set; }
    public virtual bool Deleted { get; set; }
    public virtual string ChatAlias { get; set; }
}

public ChatSessionsMappi开发者_如何学运维ng()
{
        Id(x => x.Id);
    References(x => x.ChatRoom)
        .Not.LazyLoad();
    HasMany(x => x.Comments)
        .Table("chatcomments");
}

Then In my repo I use this query:

public IList<ChatComments> GetChatCommentsBySession(int chatsessionid)
{
    using(var session = _factory.OpenSession())
    {
        var chatsession = session.Get<ChatSessions>(chatsessionid);
        NHibernateUtil.Initialize(chatsession.Comments);
        return chatsession.Comments;
    }
}

And that method gets called once for every Chatsession.

The query that I aggregate with then looks something like this:

foreach (var hour in groupedByHour){
        var datetime = hour.Sessions.First().StartTimeStamp;
    var dp = new DataPoint<DateTime, double>
        {
        YValue = hour.Sessions.Select(x =>
                         _chatCommentsRepo.GetChatCommentsBySession(x.Id).Count)
                 .Aggregate((counter,item) => counter += item),
        XValue = new DateTime(datetime.Year, datetime.Month, datetime.Day, datetime.Hour, 0, 0)
};

                datacollection.Add(dp);
            }


Selecting 50,000 rows of any size is not ever going to be quick, but consider using a subselect fetching strategory - it should work a lot better in your scenerio. Also, make sure you have an index for the foreign key in your database.

There's an example of what could be happening at the NHProf site

EDIT: I'd thoroughly recommend NHProf if you're doing any work with NHibernate - it's a quick way to get to WIN.


I posted a comment then re-read your question and suspect that you are probably utilizing NHibernate in a manner for which it's not ideal. You say you're pulling the table B rows to aggregate over them. Are you doing this using LINQ or something on the collections after you've pulled the individual records via NH?

If so, you might want to consider utilizing NH's capability to create projections that will perform the aggregates for you. In this way, NH will generate the SQL to do the aggregations, which in most cases is going to be much faster than doing 4000 retrievals of related items then performing aggregates in code.

This SO question might get you started: What's the best way to get aggregate results from NHibernate?

UPDATE
Yeah, looking at your code you're disabling lazy-loading, which is firing off a separate query for each of your chat items in order to pull the comments. It's taking forever because you're essentially doing 8000 separate queries.

It appears that you're trying to return a count of comments by hour. You can either do some manual SQL to split your comment timestamp by grouping by a DATEPART SQL expression or incorporate the datepart eval in your criteria, like this SO question: How to use DatePart in an NHibernate Criteria Query.

0

精彩评论

暂无评论...
验证码 换一张
取 消