Co to jest algorytm Hi / Lo?


464

Co to jest algorytm Hi / Lo?

Znalazłem to w dokumentacji NHibernate (jest to jedna metoda generowania unikalnych kluczy, sekcja 5.1.4.2), ale nie znalazłem dobrego wyjaśnienia, jak to działa.

Wiem, że Nhibernate sobie z tym poradzi i nie muszę znać wnętrza, ale jestem po prostu ciekawa.

Odpowiedzi:


540

Podstawową ideą jest to, że masz dwie liczby, które składają się na klucz podstawowy - „wysoką” i „niską” liczbę. Klient może w zasadzie zwiększyć sekwencję „wysoką”, wiedząc, że może bezpiecznie wygenerować klucze z całego zakresu poprzedniej „wysokiej” wartości z różnorodnością „niskich” wartości.

Załóżmy na przykład, że masz „wysoką” sekwencję o bieżącej wartości 35, a „niska” liczba mieści się w zakresie 0–1023. Następnie klient może zwiększyć sekwencję do 36 (aby inni klienci mogli generować klucze podczas korzystania z 35) i wiedzieć, że klucze 35/0, 35/1, 35/2, 35/3 ... 35/1023 wszystkie dostępne.

Może być bardzo przydatne (szczególnie w przypadku ORM), aby móc ustawić klucze podstawowe po stronie klienta, zamiast wstawiać wartości bez kluczy podstawowych, a następnie pobierać je z powrotem do klienta. Pomijając wszystko inne, to znaczy można łatwo relacji rodzic / dziecko i mam klucze wszystko na swoim miejscu, zanim zrobisz żadnych wkładek, co czyni je dozujący prostsze.


14
Czy mówisz, że „niskie zakresy” są koordynowane w kliencie, podczas gdy „wysoka sekwencja” odpowiada sekwencji DB?
Chris Noe

14
Czy wartości hi & lo zazwyczaj są następnie składane w jedną wartość całkowitą, czy jako dwuczęściowy klucz biznesowy?
Chris Noe

51
jak na przykład adres IP - ICANN daje ci wysoki numer „sieci”, a następnie masz tyle niskich numerów „hosta”, ile chcesz, w granicach podanego zakresu CIDR.
gbjbaanb

6
@Adam: Zasadniczo nic - potencjalnie taniej jest zwiększyć jedną wartość („wysoką” część) niż wygenerować kilka kluczy. (Jest to potencjalnie znacznie tańsze pod względem transferu danych - możesz „zarezerwować” ogromną liczbę kluczy przy minimalnej przepustowości.)
Jon Skeet

4
@Adam: To prawda, jeśli klucze są tylko cyframi. Nie tak bardzo dla GUIDów :) Ale tak, w przypadku prostych liczb, zrobi to każdy atomowy „przyrost o ustaloną kwotę”. To właśnie robi Hi-lo, jeśli pomyślisz o tym jako o jednej liczbie podzielonej na dwie części.
Jon Skeet,

157

Oprócz odpowiedzi Jona:

Służy do pracy bez połączenia. Klient może następnie poprosić serwer o numer hi i utworzyć obiekty zwiększające sam numer lo. Nie musi kontaktować się z serwerem, dopóki zakres lo nie zostanie wyczerpany.


1
Wolę to dla zwięzłości.
Deweloper Marius Žilėnas

34

Ponieważ jest to bardzo częste pytanie, napisałem ten artykuł , na którym opiera się ta odpowiedź.

Algorytmy hi / lo dzielą domenę sekwencji na grupy „hi”. Wartość „hi” jest przypisywana synchronicznie. Każda grupa „cześć” otrzymuje maksymalną liczbę „lo” wpisów, które można przypisać offline, nie martwiąc się o współbieżne duplikaty wpisów.

  1. Token „cześć” jest przypisywany przez bazę danych, a dwa równoczesne wywołania gwarantują unikalne kolejne wartości
  2. Po pobraniu tokenu „cześć” potrzebujemy tylko „incrementSize” (liczba wpisów „lo”)
  3. Zakres identyfikatorów określa następujący wzór:

    [(hi -1) * incrementSize) + 1, (hi * incrementSize) + 1)

    a wartość „lo” będzie w zakresie:

    [0, incrementSize)

    stosowane od wartości początkowej:

    [(hi -1) * incrementSize) + 1)
  4. Po zastosowaniu wszystkich wartości „lo”, pobierana jest nowa wartość „hi” i cykl jest kontynuowany

Bardziej szczegółowe wyjaśnienie można znaleźć w tym artykule :

Ta wizualna prezentacja jest łatwa do naśladowania:

wprowadź opis zdjęcia tutaj

Podczas gdy optymalizator hi / lo nadaje się do optymalizacji generowania identyfikatorów, nie działa dobrze z innymi systemami wstawiającymi wiersze do naszej bazy danych, nie wiedząc nic o naszej strategii identyfikatorów.

Hibernate oferuje optymalizator pooled-lo , który oferuje zalety strategii generatora hi / lo, jednocześnie zapewniając interoperacyjność z innymi klientami zewnętrznymi, którzy nie są świadomi tej strategii alokacji sekwencji.

Optymalizator pooled-lo jest zarówno wydajny, jak i współpracuje z innymi systemami, jest znacznie lepszym kandydatem niż starsza strategia identyfikatora hi / lo.


Naprawdę nie rozumiem cię czasami hahaha, więc: Podczas gdy optymalizator hi / lo jest dobry do optymalizacji generowania identyfikatorów (Ok dobrze), nie działa dobrze z innymi systemami (co rozumiesz przez inne systemy? te?) wstawianie wierszy do naszej bazy danych (Czy generowanie identyfikatorów nie służy również do wstawiania wierszy?), nie wiedząc nic o naszej strategii identyfikatorów.
Adelin

Inne systemy, takie jak DBA próbująca uruchomić instrukcję INSERT. Jeśli odczytuje bieżące dane sekwencji, czy uważasz, że łatwo jest ustalić kolejną wartość identyfikatora, wiedząc, że używamy hilo w tej konkretnej tabeli DB?
Vlad Mihalcea,

Przepraszam, jeśli komentarz nie pasuje do twojej odpowiedzi, ale zastanawiałem się, który optymalizator jest domyślnie używany? Czy to zależy od DB (używam PostgreSQL)? Ponieważ nie mogę ustalić związku między bieżącą wartością sekwencji a wygenerowanymi identyfikatorami. Korzystam @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "name") @SequenceGenerator(name="name", sequenceName = "name_seq", allocationSize=100)z moich identyfikatorów.
Stefan Golubović

1
Od czasu Hibernacji 5 Pooled jest nowym Optymalizatorem, a nie Hi / lo. Sprawdź ten artykuł, aby uzyskać więcej informacji na temat optymalizatora puli.
Vlad Mihalcea

@VladMihalcea, uważam, że masz literówkę w punkcie trzecim, pierwszy fragment w , (hi * incrementSize) + 1)... powinien być , hi * incrementSize), prawda?
Huiagan

23

Lo to buforowany rozdzielacz, który dzieli przestrzeń klawiszy na duże fragmenty, zwykle oparte na pewnym rozmiarze słowa maszynowego, a nie na znacznych zakresach (np. Uzyskiwanie 200 kluczy jednocześnie), które człowiek mógłby rozsądnie wybrać.

Użycie Hi-Lo powoduje marnowanie dużej liczby kluczy przy ponownym uruchomieniu serwera i generowanie dużych wartości kluczy nieprzyjaznych dla człowieka.

Lepszym niż alokatorem Hi-Lo jest alokator „Linear Chunk”. Korzysta z podobnej zasady opartej na tabeli, ale przydziela małe porcje o dogodnej wielkości i generuje ładne wartości przyjazne dla człowieka.

create table KEY_ALLOC (
    SEQ varchar(32) not null,
    NEXT bigint not null,
    primary key (SEQ)
);

Aby przydzielić kolejne, powiedzmy, 200 kluczy (które są następnie przechowywane na serwerze i używane w razie potrzeby):

select NEXT from KEY_ALLOC where SEQ=?;
update KEY_ALLOC set NEXT=(old value+200) where SEQ=? and NEXT=(old value);

Pod warunkiem, że możesz zatwierdzić tę transakcję (użyj ponownych prób, aby obsłużyć spór), przydzieliłeś 200 kluczy i możesz wydać je w razie potrzeby.

Przy wielkości fragmentu wynoszącej zaledwie 20, ten schemat jest 10 razy szybszy niż przydział z sekwencji Oracle i jest w 100% przenośny we wszystkich bazach danych. Wydajność alokacji jest równoważna z hi-lo.

W przeciwieństwie do pomysłu Amblera, traktuje przestrzeń klawiszy jako ciągłą liniową linię numeryczną.

Pozwala to uniknąć impulsu dla kluczy kompozytowych (które nigdy nie były tak naprawdę dobrym pomysłem) i pozwala uniknąć marnowania całych słów po ponownym uruchomieniu serwera. Generuje „przyjazne” kluczowe wartości na skalę ludzką.

Dla porównania pomysł Amblera przydziela wysokie 16- lub 32-bitowe i generuje duże nieprzyjazne człowiekowi kluczowe wartości jako przyrostowe słowa.

Porównanie przydzielonych kluczy:

Linear_Chunk       Hi_Lo
100                65536
101                65537
102                65538
.. server restart
120                131072
121                131073
122                131073
.. server restart
140                196608

Pod względem projektowym jego rozwiązanie jest zasadniczo bardziej złożone na linii liczbowej (klucze złożone, duże produkty hi_word) niż Linear_Chunk, nie osiągając przy tym żadnych korzyści porównawczych.

Projekt Hi-Lo powstał na wczesnym etapie mapowania i trwałości OO. Obecnie systemy utrwalania, takie jak Hibernacja, oferują domyślnie prostsze i lepsze alokatory.


4
Niezły post, ale nie odpowiadasz na pytanie.
orbfish

1
+1 za interesującą odpowiedź. Zgadzam się, że zdecydowana większość aplikacji nie zyskuje przewagi Hi-Lo nad prostszym podejściem; jednak myślę, że Hi-Lo lepiej nadaje się do specjalnego przypadku wielu alokatorów w aplikacjach o wysokiej współbieżności.
richj

1
Dzięki @richj! Chodzi mi o to, że z „liniowym przydziałem bloku” można używać wielu alokatorów lub dużych bloków, ale - w przeciwieństwie do Hi / Lo - zachowuje on liniową zgodność alokatora NEXT_VAL z kluczami w tabeli i jest dostrajany. W przeciwieństwie do HiLo, mnożenie nie jest potrzebne - po prostu nie jest konieczne! Mnożnik i przechowywanie NEXT_HI sprawia, że ​​HiLo jest bardziej złożony i przerywa dostrajanie, ponieważ zmiana wielkości bloków arbitralnie zmieni następny klucz, który zostanie wydany. Zobacz: literatejava.com/hibernate/...
Thomas W

2
Interesuje mnie wielu niezależnych dystrybutorów. W przypadku Hi-Lo oczywiste jest, że wysoką wartość można podzielić na identyfikator alokatora / identyfikator bloku. Dla mnie nie było od razu oczywiste, że to samo podejście można zastosować do kawałka liniowego, ale w zasadzie jest to ten sam problem dzielenia całkowitego zakresu między przydzielającymi. Mam to teraz. Dzięki.
richj

1
Och, po przemyśleniu, myślę, że kolumna SEQ jest odwzorowana na nazwę tabeli. Na przykład istnieje alokator tabela Klienci, jeden dla tabeli Zamówienia i tak dalej. Wybacz mi, czasem jestem powolny.
Rock Anthony Johnson

1

Odkryłem, że algorytm Hi / Lo jest idealny dla wielu baz danych ze scenariuszami replikacji opartymi na moim doświadczeniu. Wyobraź to sobie. masz serwer w Nowym Jorku (alias 01) i inny serwer w Los Angeles (alias 02), a następnie masz tabelę PERSON ... więc w Nowym Jorku, gdy osoba jest tworzona ... zawsze używasz 01 jako wartości HI a wartość LO jest następną sekwencją. przykład por.

  • 010000010 Jason
  • 010000011 David
  • 010000012 Theo

w Los Angeles zawsze używasz HI 02. na przykład:

  • 020000045 Rupert
  • 020000046 Oswald
  • 020000047 Mario

Kiedy więc korzystasz z replikacji bazy danych (bez względu na markę), wszystkie klucze podstawowe i dane łączą się łatwo i naturalnie, nie martwiąc się o duplikaty kluczy podstawowych, kolizje itp.

To najlepszy sposób na przejście w tym scenariuszu.


Nie działa w trybie hibernacji. HiLo algrotirm otrzymuje nową wartość sekwencji w każdej transakcji, więc licznik HI zwiększa się odpowiednio. Ale w twoim przykładzie licznik HI jest zawsze stały dla jednego DB.
Dmitry1405
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.