NHibernate IsUpdateNeeded занимает огромное количество времени - PullRequest
0 голосов
/ 24 июля 2011

В моем приложении C # 3.5 используются SQL Server 2008 R2, NHibernate и CastleProject ActiveRecord. Приложение импортирует электронные письма в базу данных вместе с их вложениями. Сохранение электронных писем и вложений выполняется с помощью 50 электронных писем в новом сеансе и области транзакции, чтобы убедиться, что они не хранятся в памяти (в одном почтовом ящике может быть 100 тыс. Писем).

Изначально электронные письма сохраняются очень быстро. Тем не менее, ближе к 20К электронной почты производительность резко ухудшается. Используя dotTrace, я получил следующую картинку:

enter image description here

Очевидно, что когда я сохраняю вложение, NHibernate пытается определить, действительно ли оно должно его сохранить, и, вероятно, сравнивает его с другими вложениями в сеансе. Для этого он сравнивает их побайтно, что занимает почти 500 секунд (для снимка на картинке) и 600M операций перечислителя.

Все это выглядит безумно, особенно когда я точно знаю, что SaveAndFlush действительно должен сохранять вложение без каких-либо проверок: я точно знаю, что оно новое и его следует сохранить.

Однако я не могу понять, как дать команду NHibernate, чтобы избежать этой проверки (IsUpdateNeeded). Пожалуйста, сообщите.

P.S. Я не уверен, но может показаться, что снижение производительности ближе к 20К не связано с наличием в памяти некоторых старых писем: я заметил, что в почтовом ящике, с которым я работаю, большие письма хранятся позже, чем меньшие, поэтому проблема может быть только в сравнение вложений.

Обновление: Похоже, мне нужно что-то вроде StatelessSessionScope, но нет документации по этому вопросу даже на сайте CastleProject! Если я сделаю что-то вроде

using (TransactionScope txScope = new TransactionScope())
using (StatelessSessionScope scope = new StatelessSessionScope())
{
  mail.Save();
}

происходит сбой за исключением того, что Save не поддерживается сеансом без сохранения состояния. Я должен вставлять объекты в сеанс, но у меня нет никакого сеанса (только SessionScope, который добавляет в SessionScope только один метод OpenSession, который принимает странные параметры).

Ответы [ 2 ]

1 голос
/ 24 июля 2011

Похоже, я нашел простое решение: для моего класса Attachment, вызывающего наибольшее снижение производительности, я переопределил следующий метод:

protected override int[] FindDirty(
    object id, 
    System.Collections.IDictionary previousState, 
    System.Collections.IDictionary currentState, NHibernate.Type.IType[] types)
  {
    return new int[0];
  }

Таким образом, грязная проверка всегда считает ее грязной и не делает этого сумасшедшего сравнения байтов.

1 голос
/ 24 июля 2011

Может быть, я пропустил этот длинный текст, но используете ли вы сеанс без сохранения состояния для импорта данных?Использование этого предотвращает множество проверок, а также обходит кэш первого уровня, таким образом используя минимальные ресурсы.

...