Каков наилучший способ повысить производительность NHibernate?

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

Ответ 1

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

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

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

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

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

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

Ответ 2

NHibernate SessionFactory - дорогостоящая операция, поэтому хорошей стратегией является создание 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();
}

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

Если вы еще не используете ленивую загрузку (соответственно), запустите. Приобретение коллекций, когда они вам не нужны, - это трата всего.

Глава Улучшение производительности описывает этот и другие способы повышения производительности.

Ответ 9

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

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

Ответ 10

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

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

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

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

Удачи:)

Ответ 11

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

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

Ответ 12

Что сказал многосолнечный.

Прочтите главу 19 документации "Повышение производительности".
NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
Hibernate: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

Используйте SQL Profiler (или эквивалент для используемой базы данных) для поиска долговременных запросов. Оптимизируйте эти запросы с помощью соответствующих индексов.

Для вызовов базы данных, используемых почти на каждой странице приложения, используйте CreateMultiQuery для возврата нескольких результирующих наборов из одного запроса к базе данных.

И, конечно, кеш. Директива OutputCache для страниц/элементов управления. Кэширование NHibernate для данных.