Nhibernate, мучительно медленный запрос, я делаю это неправильно? - PullRequest
1 голос
/ 26 июля 2011

У меня возникают серьезные проблемы с производительностью при задании конкретного вопроса nhibernate.

У меня есть две таблицы, A и B, где A имеет ~ 4000 строк, а B имеет ~ 50 000 строк. Соотношение между А и В одно ко многим.

Итак, вопрос, который я задаю, должен загрузить все объекты в A, а затем принудительно загрузить все объекты в B, потому что я хочу агрегировать по объектам в B.

Я использую fluenthibernate и настроил его так, чтобы разрешить отложенную загрузку, это прекрасно работает для всех остальных вопросов, кроме этого, где мне нужно загрузить ~ 50000 сущностей, это число, вероятно, будет расти с 50 тыс. В месяц. Вопрос занимает больше минуты, чтобы задать его сейчас (возможно, даже медленнее)

Очевидные оптимизации, которые я уже сделал: создайте только один сеанс, ленивая загрузка не отключена.

Так что мой вопрос в том, будет ли nhibernate замедляться в этом аспекте? (то есть я должен создать свой DAL с обычными вопросами SQL, а не с помощью nhibernate?) или есть способ повысить производительность. Это приложение для составления отчетов, поэтому одновременных пользователей не будет, но я все же хотел бы, чтобы этот вопрос занимал не менее 5-10 секунд.

EDIT Добавляем код:

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

Тогда В моем репо я использую этот запрос:

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

И этот метод вызывается один раз для каждой беседы.

Запрос, с которым я агрегирую, выглядит примерно так:

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

Ответы [ 2 ]

3 голосов
/ 26 июля 2011

Я разместил комментарий, затем перечитал ваш вопрос и подозреваю, что вы, вероятно, используете NHibernate таким образом, для которого он не идеален. Вы говорите, что тянете строки таблицы B, чтобы агрегировать их. Вы делаете это, используя LINQ или что-то в коллекциях после , когда вы извлекали отдельные записи через NH?

Если это так, вы можете рассмотреть возможность использования возможности NH для создания прогнозов, которые будут выполнять агрегаты для вас. Таким образом, NH сгенерирует SQL для выполнения агрегации, что в большинстве случаев будет намного быстрее, чем 4000 запросов на поиск связанных элементов и выполнение агрегирования в коде.

Этот SO вопрос может помочь вам начать: Каков наилучший способ получения совокупных результатов от NHibernate?

UPDATE
Да, глядя на ваш код, вы отключаете ленивую загрузку, которая запускает отдельный запрос для каждого из ваших элементов чата, чтобы получить комментарии. Это занимает вечность, потому что по сути вы выполняете 8000 отдельных запросов.

Похоже, вы пытаетесь вернуть количество комментариев по часам. Вы можете выполнить какой-либо ручной SQL-запрос, чтобы разделить метку времени вашего комментария, сгруппировав его по выражению SQL DATEPART, или включить в свои критерии значение datepart, например, такой вопрос SO: Как использовать DatePart в запросе критериев NHibernate .

3 голосов
/ 26 июля 2011

Выбор 50000 строк любого размера не всегда будет быстрым, но рассмотрите возможность использования стратегии выборки после выбора - она ​​должна работать намного лучше в вашем сценарии. Также убедитесь, что в вашей базе данных есть индекс для внешнего ключа.

Есть пример того, что может происходить на сайте NHProf

РЕДАКТИРОВАТЬ : я бы настоятельно рекомендовал NHProf , если вы работаете с NHibernate - это быстрый способ получить WIN.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...