У меня есть приложение, которое использует NHibernate в качестве ORM, и иногда у него возникают проблемы с производительностью из-за того, как оно обращается к данным. Что можно сделать для повышения производительности NHibernate? (Пожалуйста, ограничьтесь одной рекомендацией на ответ)





Не вдаваясь в подробности о том, какие проблемы с производительностью вы наблюдаете, я могу предложить только обобщение: по моему опыту, большинство проблем с производительностью запросов к базе данных возникает из-за отсутствия надлежащих индексов. Поэтому я предлагаю в качестве первого действия проверить ваши планы запросов на наличие неиндексированных запросов.
Первая и наиболее серьезная проблема производительности, с которой вы можете столкнуться с NHibernate, - это создание новой фабрики сеансов для каждого создаваемого сеанса. Для каждого выполнения приложения должен создаваться только один экземпляр фабрики сеансов, и все сеансы должны создаваться этой фабрикой.
Таким образом, вы должны продолжать использовать один и тот же сеанс до тех пор, пока это имеет смысл. Это зависит от приложения, но для большинства веб-приложений рекомендуется один сеанс на запрос. Если вы часто выбрасываете сеанс, вы не получаете преимуществ от его кеширования. Интеллектуальное использование кеша сеанса может изменить процедуру с линейным (или худшим) числом запросов на постоянное число без особых усилий.
Не менее важно убедиться, что вы лениво загружаете ссылки на объекты. В противном случае графы объектов могут быть загружены даже для самых простых запросов. Есть только определенные причины не делать этого, но всегда лучше начинать с ленивой загрузки и при необходимости переключаться обратно.
Это приводит нас к активной загрузке, противоположной ленивой загрузке. Во время обхода иерархий объектов или циклов по коллекциям можно легко потерять счет, сколько запросов вы делаете, и вы получите экспоненциальное количество запросов. Активная выборка может выполняться для каждого запроса с помощью FETCH JOIN. В редких случаях, например, если есть определенная пара таблиц, которые вы всегда выбираете для соединения, рассмотрите возможность отключения отложенной загрузки для этой связи.
Как всегда, SQL Profiler - отличный способ найти запросы, которые выполняются медленно или выполняются повторно. На моей последней работе у нас была функция разработки, которая также подсчитывала запросы на запрос страницы. Большое количество запросов к рутине - самый очевидный показатель того, что ваша рутина не работает с NHibernate. Если количество запросов на подпрограмму или запрос выглядит хорошо, вы, вероятно, дошли до настройки базы данных; убедитесь, что у вас достаточно памяти для хранения планов выполнения и данных в кеше, правильно индексируя ваши данные и т. д.
Одна маленькая хитрая проблема, с которой мы столкнулись, была с SetParameterList (). Функция позволяет легко передать список параметров в запрос. NHibernate реализовал это, создав по одному параметру для каждого переданного элемента. Это приводит к разному плану запроса для каждого количества параметров. Наши планы выполнения почти всегда удалялись из кеша. Кроме того, большое количество параметров может значительно замедлить выполнение запроса. Мы сделали специальный хак NHibernate, чтобы отправлять элементы в виде списка с разделителями в одном параметре. Список был разделен в SQL Server функцией табличного значения, которую наш хакер автоматически вставил в предложение IN запроса. В зависимости от вашего приложения могут быть и другие подобные мины. SQL Profiler - лучший способ их найти.
@sydneyos Если вы используете Fluent NHibernate, вы можете просто добавить DefaultLazy.Always () в качестве соглашения в вашу конфигурацию Fluent NHibernate. Я не уверен, как это работает с сопоставлениями .hbm, но полагаю, вы можете довольно легко добавить это в конфигурацию NH.
NHibernate генерирует довольно быстрый SQL прямо из коробки. Я использую его в течение года, и мне еще не приходилось писать с ним голый SQL. Все мои проблемы с производительностью были из-за Нормализация и отсутствия индексов.
Самое простое решение - изучить планы выполнения ваших запросов и создать правильные индексы, особенно для столбцов внешнего ключа. Если вы используете Microsoft SQL Server, советник по настройке ядра СУБД очень поможет в этом.
Если вы еще не используете отложенную загрузку (соответственно), начните. Получение коллекций, когда они вам не нужны, - это пустая трата времени.
Глава Повышение производительности описывает этот и другие способы повышения производительности.
Профилирование - это первый шаг - даже простые временные модульные тесты - чтобы выяснить, где можно получить наибольшую выгоду.
Для коллекций рассмотрите возможность установки размера пакета, чтобы уменьшить количество выдаваемых операторов выбора - подробности см. В разделе Повышение производительности.
Мне разрешено ограничить свой ответ одним вариантом? В этом случае я бы выбрал, что вы реализуете механизм кеширования второго уровня NHibernate.
Таким образом, для каждого объекта в вашем файле сопоставления вы можете определить стратегию кеширования. Кэш второго уровня будет хранить уже извлеченные объекты в памяти и, следовательно, не будет выполнять еще один обход базы данных. Это огромный ускоритель производительности.
Ваша цель - определить объекты, к которым ваше приложение постоянно обращается. Среди них будут общие настройки и тому подобное.
Существует много информации о кэше второго уровня nhibernate и о том, как его реализовать.
Удачи :)
Кэширование, кэширование, кэширование - правильно ли вы используете кеширование первого уровня [преждевременное закрытие сеансов или использование StatelessSession для обхода кэширования первого уровня]? Вам нужно настроить простой кеш второго уровня для редко меняющихся значений? Можете ли вы кэшировать наборы результатов запросов, чтобы ускорить запросы, которые меняются нечасто?
[Также конфигурация - можно ли сделать элементы неизменяемыми? Можете ли вы реструктурировать запросы, чтобы вернуть только нужную информацию и преобразовать их в исходную сущность? Сможет ли Бэтмен остановить Загадочника до того, как он доберется до плотины? ... ой, извини увлекся.]
SessionFactory NHibernate - дорогостоящая операция, поэтому хорошей стратегией является создание синглтона, который гарантирует, что в памяти будет только ОДИН экземпляр SessionFactory:
public class NHibernateSessionManager
{
private readonly ISessionFactory _sessionFactory;
public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager();
private NHibernateSessionManager()
{
if (_sessionFactory == null)
{
System.Diagnostics.Debug.WriteLine("Factory was null - creating one");
_sessionFactory = (new Configuration().Configure().BuildSessionFactory());
}
}
public ISession GetSession()
{
return _sessionFactory.OpenSession();
}
public void Initialize()
{
ISession disposeMe = Instance.GetSession();
}
}
Затем в вашем Global.Asax Application_Startup вы можете инициализировать его:
protected void Application_Start()
{
NHibernateSessionManager.Instance.Initialize();
}
+1 за простой рабочий пример и объяснение. Я бы хотел, чтобы была возможность дать больше 1 за хороший ответ!
Избегайте и / или минимизируйте Выберите задачу N + 1, распознавая, когда переключаться с ленивой загрузки на активную выборку для медленно выполняющихся запросов.
Не согласен с решением. Сохраните ленивую загрузку, но включите пакетная выборка ленивой загрузки. Это устраняет проблему N + 1 с минимальным влиянием на код. Я написал об этом больше в своем ответе на другой вопрос здесь.
Это не рекомендация, а инструмент, который поможет вам: NH Prof (http://nhprof.com/) кажется многообещающим, он может оценить ваше использование структуры ORM. Это может быть хорошей отправной точкой для настройки NHibernate.
Ага. Заставьте его работать, ЗАТЕМ заставьте его работать быстро. А профилировщик, такой как NH Prof, может показать вам узкие места.
Что сказал много свободного времени.
Прочтите главу 19 документации «Повышение производительности» .
NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
Спящий режим: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
Используйте SQL Profiler (или эквивалент для используемой базы данных), чтобы найти долго выполняющиеся запросы. Оптимизируйте эти запросы с помощью соответствующих индексов.
Для вызовов базы данных, используемых почти на каждой отдельной странице приложения, используйте CreateMultiQuery для возврата нескольких наборов результатов из одного запроса к базе данных.
Ну и конечно же кеш. Директива OutputCache для страниц / элементов управления. Кеширование данных NHibernate.
Только «Одна рекомендация на ответ»? Тогда я бы выбрал вот это:
Избегайте объединения дубликатов (AKA декартовы произведения) из-за объединений по двум или более параллельным ко многим ассоциациям; вместо этого используйте Exists-subqueries, MultiQueries или FetchMode «подзапрос».
NH не ленивая загрузка ссылок на объекты по умолчанию? Если нет, что вы делаете, чтобы это заставить?