web-dev-qa-db-fra.com

Quel est l'algorithme Hi / Lo?

Quel est l'algorithme Hi/Lo?

J'ai trouvé ceci dans la documentation NHibernate (c'est une méthode pour générer des clés uniques, section 5.1.4.2), mais je n'ai pas trouvé de bonne explication sur son fonctionnement.

Je sais que Nhibernate s'en occupe, et je n'ai pas besoin de connaître l'intérieur, mais je suis simplement curieux.

450
DiegoCofre

L'idée de base est que vous avez deux chiffres pour constituer une clé primaire: un nombre "élevé" et un nombre "faible". Un client peut en principe incrémenter la séquence "haut", sachant qu'il peut alors générer en toute sécurité des clés à partir de toute la plage de la valeur "haute" précédente avec la variété de valeurs "basses".

Par exemple, supposons que vous ayez une séquence "haute" avec une valeur actuelle de 35 et que le nombre "bas" se situe dans la plage 0-1023. Ensuite, le client peut incrémenter la séquence à 36 (pour que les autres clients puissent générer des clés alors qu’il utilise 35) et savoir que les clés 35/0, 35/1, 35/2, 35/3 ... 35/1023 sont tous disponibles.

Il peut être très utile (en particulier avec les ORM) de pouvoir définir les clés primaires côté client, au lieu d'insérer des valeurs sans clés primaires puis de les récupérer sur le client. En plus de toute autre chose, cela signifie que vous pouvez facilement établir des relations parent/enfant et avoir les clés en place avant de les insérer toute, ce qui simplifie leur traitement par lots.

512
Jon Skeet

En plus de la réponse de Jon:

Il est utilisé pour pouvoir travailler déconnecté. Un client peut alors demander au serveur un numéro hi et créer des objets augmentant le nombre lo lui-même. Il n'est pas nécessaire de contacter le serveur jusqu'à ce que la plage lo soit épuisée.

151
Stephan Eggermont

Les algorithmes hi/lo divisent le domaine des séquences en groupes "hi". Une valeur "hi" est attribuée de manière synchrone. Chaque groupe "hi" se voit attribuer un nombre maximal d'entrées "lo", qu'il est possible d'affecter hors ligne sans se soucier des entrées en double simultanées.

  1. Le jeton "hi" est attribué par la base de données et garantit que deux appels simultanés voient des valeurs consécutives uniques.
  2. Une fois qu'un jeton "hi" est récupéré, nous avons seulement besoin de "incrementSize" (le nombre d'entrées "lo")
  3. La plage d'identifiants est donnée par la formule suivante:

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

    et la valeur "lo" sera dans la plage:

    [0, incrementSize)
    

    en cours d'application à partir de la valeur de départ de:

    [(hi -1) * incrementSize) + 1)
    
  4. Lorsque toutes les valeurs "lo" sont utilisées, une nouvelle valeur "hi" est extraite et le cycle continue

Vous pouvez trouver une explication plus détaillée dans cet article :

Et cette présentation visuelle est également facile à suivre:

enter image description here

Alors que l'optimiseur hi/lo convient parfaitement pour optimiser la génération d'identifiants, il ne fonctionne pas bien avec d'autres systèmes insérant des lignes dans notre base de données, sans rien connaître de notre stratégie d'identifiants.

Hibernate propose l'optimiseur pooled-lo , qui associe une stratégie de générateur hi/lo à un mécanisme d'allocation de séquence d'interopérabilité. Cet optimiseur est à la fois efficace et interopérable avec d’autres systèmes, étant un meilleur candidat que la stratégie d’identification hi/lo existante.

24
Vlad Mihalcea

Lo est un allocateur mis en cache qui divise l'espace de clé en gros morceaux, généralement basés sur une taille de mot machine plutôt que sur des plages de taille significative (par exemple l'obtention de 200 clés à la fois) qu'un humain pourrait choisir judicieusement.

L'utilisation Hi-Lo a tendance à gaspiller un grand nombre de clés au redémarrage du serveur et à générer de grandes valeurs de clé non respectueuses de l'homme.

Mieux que l’allocateur Hi-Lo, c’est l’allocateur "Linear Chunk". Ceci utilise un principe similaire basé sur les tables mais alloue de petits morceaux de taille pratique et génère de belles valeurs respectueuses de l’homme.

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

Pour allouer la prochaine, disons, 200 clés (qui sont ensuite conservées sous forme de plage dans le serveur et utilisées selon les besoins):

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

Si vous pouvez valider cette transaction (utiliser des tentatives pour traiter les conflits), vous avez alloué 200 clés et pouvez les distribuer à votre guise.

Avec une taille de bloc de seulement 20, ce schéma est 10 fois plus rapide que l'allocation depuis une séquence Oracle et est 100% portable parmi toutes les bases de données. La performance d'allocation est équivalente à hi-lo.

Contrairement à l’idée d’Ambler, l’espace de clés est traité comme une droite numérique contiguë.

Cela évite l’élan des clés composites (ce qui n’a jamais été une bonne idée) et évite de gaspiller des mots entiers au redémarrage du serveur. Il génère des valeurs clés "conviviales", à taille humaine.

L'idée de M. Ambler, à titre de comparaison, attribue les valeurs élevées de 16 ou 32 bits et génère de grandes valeurs de clé non respectueuses de l'homme à mesure que l'incrémentation de mots-clés augmente.

Comparaison des clés allouées:

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

En ce qui concerne la conception, sa solution est fondamentalement plus complexe sur la ligne numérique (clés composites, gros produits hi_Word) que Linear_Chunk sans obtenir d’avantage comparatif.

La conception Hi-Lo est apparue tôt dans OO mapping et persistance. De nos jours, les frameworks de persistance tels que Hibernate proposent par défaut des allocateurs plus simples et de meilleure qualité.

20
Thomas W

J'ai trouvé que l'algorithme Hi/Lo est parfait pour plusieurs bases de données avec des scénarios de réplication basés sur mon expérience. Imagine ça. vous avez un serveur à New York (alias 01) et un autre à Los Angeles (alias 02), puis vous avez une table PERSONNE ... alors à New York quand une personne est créée ... vous utilisez toujours 01 comme valeur HI et la valeur LO est la suivante. par exemple.

  • 010000010 Jason
  • 010000011 David
  • 010000012 Theo

à Los Angeles, vous utilisez toujours le HI 02. Par exemple:

  • 020000045 Rupert
  • 020000046 Oswald
  • 020000047 Mario

Ainsi, lorsque vous utilisez la réplication de base de données (quelle que soit la marque), toutes les clés primaires et données se combinent facilement et naturellement sans se soucier des clés primaires en double, des collisions, etc.

C'est la meilleure façon de procéder dans ce scénario.

1
Theo