Feb 19, 2010

Ado net batch size и идентификаторы

Для оптимизации большого количества 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);
} 

Какое количество запросов будет сделано к базе данных? Ответ зависит от двух условий:

  1. Установлен ли параметр ado net batch size
  2. Какой алгоритм используется для генерирования Id сущностей

Ну по поводу первого в общем то ясно – этот параметр отвечает за то, сколько запросов NHibernate объеденит в один и выполнит в один заход.

А вот о Id стоит сказать немного больше. Лично я до последнего времени во всех приложениях использовал автоинкрементные поля в Sql Server. Делалось это как наиболее простой выход для генерирования Id – в маппинге достаточно было указать GenearatedBy.Native() и все. В общем то мне никогда этот поход не мешал и вполне выполнял нужные мне задачи.

Такой же подход применялся в проекте Sharp Arhitecture… До релиза в третьем квартале 2009года :). Там алгоритмом по умолчанию установлен алгоритм hilo. Подробности этого алгоритма можно почитать по соответствующей ссылке. Основная идея заключается в следующем, когда надо получить происходит примерно следующее:

  1. В базе данных существует спец. таблица, которая хранит hi величину, это обычное число. NHiberante получает его.
  2. Nhibernate в зависимости от настроек выбирает следующую hi величину. Предположим текущее hi – 1000, а следующее 2000.
  3. Получив 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.

No comments:

Post a Comment