Для оптимизации большого количества insert-update команд NHiberante содержит специальную настройку – Ado net batch size. Рассмотрим следующий код:
for (int i = 0; i < 5000; i++) { var testIncrement = new SomeEntity { Field1 = "field" + i, Field2 = i }; session.SaveOrUpdate(testIncrement); }
Какое количество запросов будет сделано к базе данных? Ответ зависит от двух условий:
- Установлен ли параметр ado net batch size
- Какой алгоритм используется для генерирования Id сущностей
Ну по поводу первого в общем то ясно – этот параметр отвечает за то, сколько запросов NHibernate объеденит в один и выполнит в один заход.
А вот о Id стоит сказать немного больше. Лично я до последнего времени во всех приложениях использовал автоинкрементные поля в Sql Server. Делалось это как наиболее простой выход для генерирования Id – в маппинге достаточно было указать GenearatedBy.Native() и все. В общем то мне никогда этот поход не мешал и вполне выполнял нужные мне задачи.
Такой же подход применялся в проекте Sharp Arhitecture… До релиза в третьем квартале 2009года :). Там алгоритмом по умолчанию установлен алгоритм hilo. Подробности этого алгоритма можно почитать по соответствующей ссылке. Основная идея заключается в следующем, когда надо получить происходит примерно следующее:
- В базе данных существует спец. таблица, которая хранит hi величину, это обычное число. NHiberante получает его.
- Nhibernate в зависимости от настроек выбирает следующую hi величину. Предположим текущее hi – 1000, а следующее 2000.
- Получив hi=1000 и выставив в базе данных next hi = 2000 Nhibernate в праве создавать сущности в id = 1001, 1002, 1003 и т.д.
Соответственно если каждый клиент будет обновлять hi величину, то никто из клиентов не получит одинаковые id для объектов. Для Oracle хранилищем hi значений возможно могут быть последовательности, которых нет в Sql Server.
Все это длинное описание ради того, чтобы было понятно происходящее в примере в строке 9. Как только NHibernate выполнит команду SaveOrUpdate сущность testIncrement должна получить Id. Если в качестве id используется автоинкрементное поле, то каждое такое сохранение необходимо фиксировать в базе, т.е. выполнять запрос Insert (иначе нельзя получить id). В случае же использования hilo алгоритма NHiberante может сохранить нужное количество объектов, при этом самостоятельно генерируя Id.
В общем выставив ado net batch size = 40 и выполнив код, приведенный в начале получил следующие результаты:
- autoincrement – 5000 запросов (как и ожидалось),
- hilo – 225.