NHibernate IsUpdateNeeded занимает огромное количество времени

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

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

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

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

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

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

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

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

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

2 ответа

Решение

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

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

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

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

Другие вопросы по тегам