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];
}
Таким образом, грязная проверка всегда считает ее грязной и не делает этого сумасшедшего сравнения байтов.
Может быть, я пропустил этот длинный текст, но используете ли вы сеанс без сохранения состояния для импорта данных? Использование этого предотвращает много проверок, а также обходит кэш первого уровня, таким образом используя минимальные ресурсы.