Каков наилучший способ улучшить производительность NHibernate? - PullRequest
61 голосов
/ 16 сентября 2008

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

Ответы [ 12 ]

53 голосов
/ 16 сентября 2008

Первая и наиболее существенная проблема с производительностью, с которой вы можете столкнуться с NHibernate, - это если вы создаете новую фабрику сеансов для каждого сеанса, который вы создаете. Для каждого выполнения приложения должен быть создан только один экземпляр фабрики сеансов, и все фабрики должны быть созданы этой фабрикой.

Вдоль этих строк вы должны продолжать использовать тот же сеанс, если это имеет смысл. Это зависит от приложения, но для большинства веб-приложений рекомендуется один сеанс на запрос. Если вы часто выбрасываете сеанс, вы не получаете преимуществ от его кэша. Интеллектуальное использование кеша сеанса может изменить процедуру с линейным (или хуже) числом запросов на постоянное число без особой работы.

Не менее важно, что вы хотите убедиться, что лениво загружаете ссылки на свои объекты. Если нет, можно загрузить целые графы объектов даже для самых простых запросов. Есть только определенные причины не делать этого, но всегда лучше начинать с отложенной загрузки и переключаться обратно по мере необходимости.

Это приводит нас к страстному желанию, противоположному ленивой загрузке. Обходя иерархии объектов или просматривая коллекции, можно легко потерять счет того, сколько запросов вы делаете, и в результате вы получите экспоненциальное количество запросов. Стремительное извлечение может быть сделано для каждого запроса с помощью FETCH JOIN. В редких случаях, например, при наличии определенной пары таблиц, к которым вы всегда получаете соединение, рассмотрите возможность отключения отложенной загрузки для этих отношений.

Как всегда, SQL Profiler - отличный способ найти запросы, которые выполняются медленно или выполняются неоднократно. На моей последней работе у нас была функция разработки, которая также подсчитывала количество запросов на страницу. Большое количество запросов для подпрограммы является наиболее очевидным показателем того, что ваша подпрограмма плохо работает с NHibernate. Если количество запросов на подпрограмму или запрос выглядит хорошо, вы, вероятно, приступили к настройке базы данных; убедитесь, что у вас достаточно памяти для хранения планов выполнения и данных в кеше, правильной индексации данных и т. д.

Одна хитрая маленькая проблема, с которой мы столкнулись, была с SetParameterList (). Функция позволяет легко передавать список параметров в запрос. NHibernate реализовал это, создав один параметр для каждого переданного элемента. Это приводит к разному плану запросов для каждого количества параметров. Наши планы выполнения почти всегда выходили из кеша. Кроме того, многочисленные параметры могут значительно замедлить запрос. Мы сделали собственный хакер NHibernate для отправки элементов в виде списка с разделителями в виде одного параметра. Список был разделен в SQL Server функцией табличных значений, которую наш хак автоматически вставил в предложение IN запроса. Могут быть и другие наземные мины в зависимости от вашего применения. SQL Profiler - лучший способ их найти.

26 голосов
/ 27 октября 2008

SessionFactory NHibernate является дорогостоящей операцией, поэтому хорошей стратегией является создание Singleton, который гарантирует, что в памяти есть только ОДИН экземпляр 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();
}
11 голосов
/ 02 декабря 2008

Избегайте и / или минимизируйте проблему Select N + 1 , распознавая, когда переключаться с отложенной загрузки на активную выборку для медленно выполняющихся запросов.

10 голосов
/ 02 февраля 2009

Нет рекомендаций, но есть инструмент, который вам поможет: NH Prof (http://nhprof.com/) выглядит многообещающе, он может оценить ваше использование платформы ORM. Это может быть хорошей отправной точкой для настройки NHibernate.

4 голосов
/ 16 сентября 2008

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

3 голосов
/ 08 ноября 2011

Только "одна рекомендация за ответ"? Тогда я бы пошел на это:

Избегайте дубликатов соединений (декартовых продуктов АКА) из-за объединений по двум или более параллельным-многим ассоциациям; используйте взамен Exists-subqueries, MultiQueries или FetchMode "subselect".

Взято из: Советы по настройке производительности Hibernate

3 голосов
/ 19 сентября 2008

NHibernate генерирует довольно быстрый SQL прямо из коробки. Я использую его в течение года, и мне еще предстоит написать голый SQL с ним. Все мои проблемы с производительностью были связаны с нормализацией и отсутствием индексов.

Самое простое решение - проверить планы выполнения ваших запросов и создать правильные индексы, особенно для столбцов внешнего ключа. Если вы используете Microsoft SQL Server, «Помощник по настройке ядра СУБД» очень поможет в этом.

1 голос
/ 09 октября 2008

Кэширование, Кэширование, Кэширование. Правильно ли вы используете кэширование первого уровня [преждевременное закрытие сеансов или использование StatelessSession для обхода кэширования первого уровня]? Вам нужно настроить простой кэш второго уровня для значений, которые меняются редко? Можете ли вы кэшировать наборы результатов запросов, чтобы ускорить запросы, которые изменяются нечасто?

[Также конфигурация - вы можете установить элементы как неизменяемые? Можете ли вы реструктурировать запросы, чтобы вернуть только необходимую вам информацию и преобразовать их в исходную сущность? Сможет ли Бэтмен остановить Риддлера до того, как он доберется до плотины? ... о, извини, увлекся.]

1 голос
/ 24 сентября 2008

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

Таким образом, для каждого объекта в вашем файле сопоставления вы можете определить кеш-стратегию. Кэш второго уровня сохранит уже извлеченные объекты в памяти и, следовательно, не сделает еще одного обращения к базе данных. Это огромный усилитель производительности.

Ваша цель - определить объекты, к которым ваше приложение постоянно обращается. Среди них будут общие настройки и тому подобное.

Существует много информации для кэша второго уровня nhibernate и о том, как его реализовать.

Удачи:)

1 голос
/ 23 сентября 2008

Профилирование - это первый шаг - даже простые синхронизированные модульные тесты - чтобы определить, где можно получить наибольшую прибыль

Для коллекций рассмотрите возможность установки размера пакета для уменьшения количества выпущенных операторов выбора - см. Раздел Повышение производительности для получения подробной информации

...