Что произойдет после использования HiLo, если вы измените емкость (максимальное Lo)?

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

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

Примечание - не конкретно для NHibernate, мне просто интересно узнать об алгоритме HiLo в целом.


person Jon M    schedule 21.06.2010    source источник


Ответы (5)


Алгоритмы 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 столкновения удастся избежать при повышении вашего l_max.

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

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

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

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

Но если тебе повезет ...

person Justin L.    schedule 21.06.2010

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

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

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

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

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

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

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

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

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

person Thomas W    schedule 08.11.2013

Я попытался выяснить поведение алгоритма HiLo с помощью простого приложения для гибернации, похожего на 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) lowvalue - из config 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

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

person Kaushik Lele    schedule 08.11.2012

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

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

person Stefan Steinegger    schedule 21.06.2010

Старый вопрос, я знаю, но стоит ответить "да, можно"

Вы можете увеличивать или уменьшать nex_hi в любой момент, если вы пересчитываете свою таблицу hibernate_unique_key на основе текущих номеров Id ваших таблиц.

В нашем случае у нас есть таблица идентификаторов объектов hibernate_unique_key с двумя столбцами:

  • next_hi
  • Имя сущности.

Next_hi для любого заданного идентификатора рассчитывается как

SELECT MAX(Id) FROM TableName/(@max_lo + 1) + 1

Приведенный ниже скрипт проходит через каждую таблицу со столбцом Id и обновляет наши значения nex_hi.

DECLARE @scripts TABLE(Script VARCHAR(MAX))
DECLARE @max_lo VARCHAR(MAX) = '100';
    
INSERT INTO @scripts
SELECT '
INSERT INTO hibernate_unique_key (next_hi, EntityName)
SELECT
(SELECT ISNULL(Max(Id), 0) FROM ' + name + ')/(' + @max_lo + ' + 1) + 1, ''' + name + ''' 
'
FROM sys.tables WHERE type_desc = 'USER_TABLE' 
AND COL_LENGTH(name, 'Id') IS NOT NULL
AND NOT EXISTS (select next_hi from hibernate_unique_key k where name = k.EntityName)


DECLARE curs CURSOR FOR SELECT * FROM @scripts
DECLARE @script VARCHAR(MAX)

OPEN curs 
FETCH NEXT FROM curs INTO @script

WHILE @@FETCH_STATUS = 0
BEGIN
    --PRINT @script 
    EXEC(@script)
    FETCH NEXT FROM curs INTO @script
END
CLOSE curs
DEALLOCATE curs
person Yosoyadri    schedule 17.11.2020