Как только HiLo используется, что произойдет, если вы измените емкость (максимальный Lo)? - PullRequest
8 голосов
/ 21 июня 2010

Если я начну использовать генератор HiLo для назначения идентификаторов для таблицы, а затем решу увеличить или уменьшить емкость (т. Е. Максимальное значение «lo»), это вызовет коллизии с уже назначенными идентификаторами?

Мне просто интересно, нужно ли мне поставить большой красный флажок вокруг числа, говорящего: «Никогда не меняй это!»

Примечание - не специфично для NHibernate, мне просто любопытно, как работает алгоритм HiLo.

Ответы [ 4 ]

20 голосов
/ 21 июня 2010

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

Хорошее объяснение того, как концептуально работает HiLo, дано в в этом предыдущем ответе SO

Изменение max_lo сохранит свойство, что ваша пара чисел будет уникальной.Однако убедится ли он в том, что сопоставленный идентификатор уникален и не содержит коллизий?

Давайте посмотрим на реализацию HiLo в Hibernate.Алгоритм, который они, похоже, используют (исходя из того, что я собрал) таков: (и я мог бы отказаться от технических соображений)

h = high sequence (starting at 0)
l_size = size of low block
l = low sequence (starting at 1)

ID = h*l_size + l

Итак, если ваш низкий блок, скажем, 100, ваш зарезервированныйИдентификационные блоки будут идти 1-100, 101-200, 201-300, 301-400 ...

Ваша последовательность High теперь равна 3. Теперь, что произойдет, если вы вдруг измените свой l_size на 10?Ваш следующий блок, ваш максимум увеличивается, и вы получите 4*10+1 = 41

Упс.Это новое значение определенно попадает в «зарезервированный блок» 1-100.Кто-то с высокой последовательностью 0 подумает: «Ну, у меня зарезервирован диапазон 1-100, поэтому я просто положу один на 41, потому что я знаю, что он безопасен».

Вероятность столкновения определенно очень и очень высока, когда понижает ваш l_max.

Как насчет противоположного случая, поднимая его?

Вернемся к нашему примеру, давайтеувеличьте наш l_size до 500, превратив следующую клавишу в 4*500+1 = 2001, зарезервировав диапазон 2001-2501.

Похоже, что в этой конкретной реализации HiLo будет предотвращено столкновение, когда поднимает your l_max.

Конечно, вы должны выполнить несколько собственных тестов, чтобы убедиться, что это фактическая реализация или близка к ней.Одним из способов было бы установить l_max на 100 и найти первые несколько ключей, затем установить его на 500 и найти следующие.Если есть огромный скачок, как упомянуто здесь, вы могли бы быть в безопасности.

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

Используйте свое усмотрение;Алгоритм HiLo не совсем тот, который создан с учетом переменной l_max, и ваши результаты могут оказаться непредсказуемыми в зависимости от вашей конкретной реализации.Возможно, кто-то, кто имел опыт поднятия l_max и обнаружения проблем, может доказать, что этот счет верен.

Итак, в заключение, хотя, теоретически, реализация HiLo в Hibernate, скорее всего, будет избегать коллизий, когда l_max повышается, вероятно,все еще не хорошая практика.Вы должны кодировать, как будто l_max не изменится со временем.

Но если вам повезет ...

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

См. Распределитель таблиц Linear Chunk - логически это более простой и правильный подход к той же проблеме.

Что такое алгоритм Hi / Lo?

Выделяя диапазонов из пространства номеров и непосредственно представляя NEXT, вместо того, чтобы усложнять логику старшими словами или умноженными числами, вы можете непосредственно видеть, какие ключи будут сгенерированы.

По сути, «Линейный распределитель чанков» использует сложение вместо умножение .Если NEXT равен 1000 и мы настроили диапазон размером 20, NEXT перейдет к 1020, и мы будем держать ключи 1000-1019 для распределения.

Диапазон размеров может быть настроен или перенастроен в любое время без потери целостности.Существует прямая связь между полем NEXT распределителя, сгенерированными ключами и MAX (ID), существующими в таблице.

(Для сравнения, "Hi-Lo" использует умножение .Если следующее значение равно 50, а множитель равен 20, то вы распределяете ключи в пределах 1000-1019. В таблице нет прямой корреляции между NEXT, сгенерированными ключами и MAX (ID), трудно безопасно настроить NEXT имножитель не может быть изменен без нарушения текущей точки выделения.)

С помощью «Линейного блока» вы можете настроить размер каждого диапазона / блока - размер 1 эквивалентен традиционному основанному на таблице «одиночному распределителю»."& попадает в базу данных для генерации каждого ключа, размер 10 в 10 раз быстрее, поскольку он выделяет диапазон 10 одновременно, размер 50 или 100 еще быстрее ..

Размер 65536 создает уродливый видключи, тратит огромное количество ключей при перезапуске сервера и эквивалентно оригинальному алгоритму HI-LO Скотта Амблера.

Короче говоря, Hi-Lo является ошибочно сложнымбывший и ошибочный подход к тому, что должно было быть концептуально тривиально простым - распределение диапазонов вдоль числовой линии.

2 голосов
/ 08 ноября 2012

Я попытался раскопать весь алгоритм HiLo с помощью простого приложения Hibernate с helloWrold.

Я попробовал пример гибернации с

<generator class="hilo">
<param name="table">HILO_TABLE</param>
<param name="column">TEST_HILO</param>
<param name="max_lo">40</param>
</generator>

Таблица с именем "HILO_TABLE", созданная с одним столбцом "TEST_HILO" Первоначально я установил значение столбца TEST_HILO равным 8.

update HILO_TABLE set TEST_HILO=8;

Я заметил, что шаблон для создания идентификатора

hivalue * lowvalue + hivalue

hivalue - это значение столбца в БД (т.е. выберите TEST_HILO из HILO_TABLE) низкое значение из конфигурации xml (40)

, поэтому в этом случае идентификаторы начинались с 8 * 40 + 8 = 328

В моем примере гибернации я добавил 200 строк за один сеанс. поэтому строки были созданы с идентификаторами от 328 до 527 А в БД значение hivalue было увеличено до 13. Логика приращения выглядит так: -

new hivalue in DB = inital value in DB + (rows_inserted/lowvalue + 1 )

= 8 + 200/40 = 8 + 5 = 13

Теперь, если я запускаю ту же самую программу гибернации для вставки строк, идентификаторы должны начинаться с 13 * 40 + 13 = 533

При запуске программы это подтвердилось.

1 голос
/ 21 июня 2010

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

Существует вероятность того, что увеличение не приведет к столкновениям. Но вам нужно либо попробовать, либо спросить кого-то, кто знает лучше, чем я, чтобы быть уверенным.

...