简体   繁体   English

Nhibernate,痛苦缓慢的查询,我做错了吗?

[英]Nhibernate, painfully slow query, am I doing it wrong?

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. 我有两个表,A和B,其中A具有〜4000行,B具有〜50,000行。 The relation between A and B is one to many. A和B之间的关系是一对多的。

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. 因此,我要提出的问题需要加载A中的所有实体,然后强制加载B中的所有实体,因为我想聚合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. 我正在使用fluenthibernate并将其配置为允许延迟加载,这对所有其他问题都非常有用,除了这个问题,我必须加载〜50000个实体,这个数字可能会以每月50k的速度增长。 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. 我已经完成的明显优化:仅创建一个sessionfactory,不会关闭延迟加载。

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. (也就是说,我应该使用常规SQL问题而不是nhibernate构建我的DAL?)还是有办法提高性能。 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. 这是一个报表应用程序,因此不会有很多并发用户,但是我仍然希望使这个问题至少花费5-10秒。

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 ChatSessionsMapping()
{
        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. 每次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. 选择50,000行任何大小的行永远不会很快,但是请考虑使用子选择获取策略-在您的场景中,它应该会更好地工作。 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 NHProf站点上可能发生的事有一个例子

EDIT : I'd thoroughly recommend NHProf if you're doing any work with NHibernate - it's a quick way to get to WIN. 编辑 :如果您正在使用NHibernate进行任何工作,我会彻底推荐NHProf-这是获得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. 我发表了评论,然后重新阅读了您的问题,并怀疑您可能以不理想的方式使用NHibernate。 You say you're pulling the table B rows to aggregate over them. 您说要拉表B行以对其进行汇总。 Are you doing this using LINQ or something on the collections after you've pulled the individual records via NH? 通过NH提取单个记录后,是否要使用LINQ或集合中的某些方法?

If so, you might want to consider utilizing NH's capability to create projections that will perform the aggregates for you. 如果是这样,您可能要考虑利用NH的功能来创建将为您执行聚合的投影。 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. 这样,NH将生成SQL进行聚合,在大多数情况下,这比进行4000次相关项目的检索然后在代码中执行聚合要快得多。

This SO question might get you started: What's the best way to get aggregate results from NHibernate? 这样的问题可能会让您入门: 从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. 因为您实际上要进行8000个单独的查询,所以这是永远的。

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 . 您可以通过按DATEPART SQL表达式分组来执行一些手动SQL来拆分注释时间戳记,也可以将datepart eval合并到您的条件中,例如SO这样的问题: 如何在NHibernate Criteria Query中使用DatePart

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM