Объяснение NHibernate HiLo
Я изо всех сил пытаюсь разобраться, как работает генератор HiLo в NHibernate. Я прочитал объяснение здесь, что сделало вещи немного яснее.
Я понимаю, что каждый SessionFactory извлекает большое значение из базы данных. Это повышает производительность, потому что у нас есть доступ к идентификаторам без попадания в базу данных.
Объяснение из приведенной выше ссылки также гласит:
Например, предположим, что у вас есть "высокая" последовательность с текущим значением 35, а "низкий" номер находится в диапазоне 0-1023. Затем клиент может увеличить последовательность до 36 (для других клиентов, чтобы иметь возможность генерировать ключи при использовании 35) и знать, что ключи 35/0, 35/1, 35/2, 35/3... 35/1023 являются все доступные.
Как это работает в веб-приложении, так как у меня нет только одного SessionFactory и, следовательно, одного hi-значения. Означает ли это, что в отключенном приложении вы можете получить двойные идентификаторы в таблице сущностей?
В моих тестах я использовал следующие настройки:
<id name="Id" unsaved-value="0">
<generator class="hilo"/>
</id>
Я провел тест, чтобы сохранить 100 объектов. Идентификаторы в моей таблице перешли от 32768 - 32868. Следующее значение hi было увеличено до 2. Затем я снова проверил свой тест и идентификаторы находились в диапазоне 65536 - 65636.
Во-первых, зачем начинать с 32768, а не с 1, а во-вторых, почему прыжок с 32868 до 65536?
Теперь я знаю, что мои суррогатные ключи не должны иметь никакого значения, но мы используем их в нашем приложении. Почему я не могу просто увеличить их, как поле идентификации SQL Server.
Наконец, кто-нибудь даст мне объяснение того, как работает параметр max_lo? Является ли это максимальным количеством низких значений (идентификаторы объектов в моей голове), которые могут быть созданы против большого значения?
Это одна из тем в NHibernate, с которой я изо всех сил пытался найти документацию. Я прочитал весь NHibernate в книге действий, и он все еще не понимает, как это работает в деталях.
Спасибо
Бен
Ответы
Ответ 1
Я считаю, что ваше понимание более или менее правильное.
Параметр max_lo просто используется для определения количества идентификаторов, доступных для любого заданного значения Hi.
Моя лучшая догадка заключается в том, что значение по умолчанию max_lo по умолчанию NHibernate равно 32768. Таким образом, значение Hi, равное 1, запустит ваши идентификаторы на 32768 и запустит вас до 65535. Значение Hi, равное 2, начнется с 65536 и запустит еще один идентификатор max_lo.
В основном вы используете значение max_lo для управления фрагментацией Id. 32768, вероятно, не является оптимальным значением для каждой ситуации.
Важно отметить, что это работает только в рамках SessionFactory. Если вы остановите/запустите свое приложение и заново инициализируете SessionFactory целую группу, он все равно увеличит значение Hi при запуске, и вы скоро увидите, как ваши Ids прыгают.
Ответ 2
Глядя на ключи, сгенерированные моими объектами Nhibernate 3 HiLo, алгоритм выглядит так:
(Hi * Lo) + Hi
Итак, с моим Hivalue в DB как 390 и с моей конфигурацией следующим образом:
<id name="TimeclockId" column="TimeclockId" type="Int64" unsaved-value="0">
<generator class="hilo">
<param name="where">TableId = 1</param>
<param name="table">HiValue</param>
<param name="column">NextValue</param>
<param name="max_lo">10</param>
</generator>
</id>
Я перезапускаю свой пул приложений и получаю (390 * 10) + 390 = 4290, диапазон 4290 - 4300.
Вот почему у вас появляются кажущиеся странными пробелы в ваших первичных ключах, потому что следующий сгенерированный ключ от значения hi 391 равен 4301, а диапазон - 4301 - 4311.
Ответ 3
NHibernate 3.1.1 делает это для генерации идентификатора с использованием HiLo
if (lo > maxLo)
{
long hival = <GetNextHiFromDB>
lo = hival == 0 ? 1 : 0;
hi = hival * (this.maxLo + 1L);
}
long result = hi + lo;
lo++;
return result;
В конфигурации NHibernate указывается maxLo. Если maxLo установлен в 100, вы получите 101 идентификатор для каждого значения hi.
Ответ 4
Для тех, кто задается вопросом, как выбрать хорошее значение max_lo
, компромисс по существу находится между:
- Частота, с которой вам нужно запросить новое значение
hi
из db.
- Максимальное количество уникальных чисел, которые вы на самом деле можете генерировать.
Нижняя max_lo
гарантирует, что нет "отхода" от id, что, в свою очередь, определяет момент, когда вы нажмете на неявный предел вашего типа данных (который, вероятно, будет int
). Цена, которую вы платите, заключается в том, что каждый клиент должен чаще запрашивать и увеличивать значение hi
.
Более высокий max_lo
полезен для уменьшения частоты запросов, которые получают и увеличивают hi
, но приводят к большему количеству отходов.
Метрики, которые необходимо учитывать для определения оптимального значения:
- Частота, с которой создаются новые сущности, и требуется идентификатор
- Частота, с которой приложение перезапускается/получает рециркуляцию (что-либо, что приводит к новому NHibernate SessionFactory)
Рассмотрим веб-приложение, размещенное в IIS, и перерабатывается каждые 24 часа. Объекты Customer
и Order
.
Теперь давайте предположим:
- 10000 новых заказов в сутки
- 10 новых клиентов в сутки
Тогда идеальный max_lo
равен 10000
для ордеров и 10
для Клиентов. Конечно, в реальном мире вы никогда не сможете определить это так четко и ясно, но вы должны получить эту идею здесь!
Теперь рассмотрим другой сценарий, где мы выбираем абсолютно неправильные (смешные) max_lo
:
- Предположим, что 10 клиентов делают заказы одновременно каждую секунду, а
max_lo
всего 10 на заказы, каждую секунду возникает избыточный запрос базы данных для увеличения hi
.
- Предположим, что ваше приложение является настольным приложением и установлено на 50 клиентов (обслуживающий персонал?), каждый из которых запускает его два раза в день. Вместе они создают около 100 билетов на помощь в день. Теперь скажем, что мы придерживаемся значения
max_lo
по умолчанию 32767. hi
увеличивается 100 раз в день (50 клиентов * 2), что означает, что вы достигнете максимального значения int
менее чем за 2 года, если вы забыли важный факт, что hi
увеличивается настолько часто. Хороший max_lo
здесь будет (100 билетов /50 клиентов) = всего 2.
Надеется, что это поможет с концептуализацией алгоритма HiLo и его последствиями в целом, а также дает вам математику, чтобы фактически зафиксировать число на max_lo
.