Nhibernate,非常慢的查询,我做错了吗?

本文关键字:错了 查询 非常 Nhibernate | 更新日期: 2023-09-27 18:03:25

在询问一个特定的nhibernate问题时,我遇到了一些主要的性能问题。

我有两个表,A和B,其中A有~4000行,B有~ 50000行。A和B之间的关系是一对多。

所以我问的问题需要加载A中的所有实体然后强制加载B中的所有实体因为我想聚合B中的实体

我正在使用fluenthibernate,并将其配置为允许惰性加载,这对于所有其他问题都非常有效,除了这个问题,我必须加载~50000个实体,这个数字可能会以每月50k的速度增长。现在问这个问题需要一分钟以上(可能更慢)

我已经做过的明显优化:只创建一个sessionfactory,不关闭lazyloading

所以我的问题是,nhibernate在这方面会变慢吗?(也就是说,我应该用常规的SQL问题而不是hibernate来构建我的DAL吗?)或者是否有一种方法可以提高性能。这是一个报表应用程序,所以不会有很多并发用户,但我仍然希望这个问题至少花5-10秒。

编辑添加代码:

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 ChatSessionsMapping()
{
        Id(x => x.Id);
    References(x => x.ChatRoom)
        .Not.LazyLoad();
    HasMany(x => x.Comments)
        .Table("chatcomments");
}
在我的repo中,我使用这个查询:
public IList<ChatComments> GetChatCommentsBySession(int chatsessionid)
{
    using(var session = _factory.OpenSession())
    {
        var chatsession = session.Get<ChatSessions>(chatsessionid);
        NHibernateUtil.Initialize(chatsession.Comments);
        return chatsession.Comments;
    }
}

这个方法在每次Chatsession中调用一次。

我聚合的查询看起来像这样:

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);
            }

Nhibernate,非常慢的查询,我做错了吗?

选择任意大小的50,000行永远不会很快,但是考虑使用子选择抓取策略—它在您的场景中应该工作得更好。此外,请确保在数据库中为外键设置了索引。

这是NHProf网站可能发生的事情的一个例子

EDIT:如果你正在使用NHibernate,我强烈推荐使用NHProf -这是一个快速进入WIN的方法。

我发表了一个评论,然后重新阅读了你的问题,并怀疑你可能以一种不理想的方式使用NHibernate。你说你要拉表B行来对它们进行聚合。您是否使用LINQ或在之后的集合上的其他东西来执行此操作,您已经通过NH提取了单个记录?

如果是这样,您可能需要考虑利用NH的功能来创建将为您执行聚合的预测。通过这种方式,NH将生成SQL来进行聚合,在大多数情况下,这将比在代码中执行相关项的4000次检索快得多。

这个问题可能会让你开始:从NHibernate获得聚合结果的最佳方式是什么?


是的,看看你的代码,你禁用了延迟加载,它会为每个聊天项目触发一个单独的查询,以便拉出评论。这需要花很长时间,因为你基本上要做8000个单独的查询。

看起来你想返回一个按小时计数的注释数。您可以通过DATEPART SQL表达式分组来分割您的注释时间戳,或者将datepart eval合并到您的标准中,如以下问题:如何在NHibernate标准查询中使用datepart