Hi / Lo algoritması nedir?


464

Hi / Lo algoritması nedir?

Bunu NHibernate belgelerinde buldum (benzersiz anahtarlar oluşturmak için bir yöntem, bölüm 5.1.4.2), ancak nasıl çalıştığına dair iyi bir açıklama bulamadım.

Nhibernate'in bunu hallettiğini biliyorum ve içini bilmeme gerek yok, ama sadece merak ediyorum.

Yanıtlar:


541

Temel fikir, birincil anahtarı oluşturmak için iki numaranızın olması - "yüksek" bir sayı ve "düşük" bir sayıdır. Bir istemci temel olarak "yüksek" diziyi, daha sonra "düşük" değer çeşitliliği ile önceki "yüksek" değerin tüm aralığından güvenli bir şekilde üretebileceğini bilerek arttırabilir.

Örneğin, geçerli değeri 35 olan bir "yüksek" diziniz olduğunu ve "düşük" sayının 0-1023 aralığında olduğunu varsayalım. Daha sonra istemci sekansı 36'ya yükseltebilir (diğer istemciler 35 kullanırken anahtar üretebilir) ve 35/0, 35/1, 35/2, 35/3 ... 35/1023 anahtarlarının hepsi mevcut.

Birincil anahtarlar olmadan değerler eklemek ve daha sonra istemciye geri getirmek yerine, birincil anahtarları istemci tarafında ayarlayabilmek çok yararlı olabilir (özellikle ORM'lerde). Başka herhangi bir şey dışında, herhangi bir ekleme yapmadan önce ebeveyn / çocuk ilişkilerini kolayca yapabileceğiniz ve anahtarları yerleştirebileceğiniz anlamına gelir , bu da onları toplu hale getirmeyi kolaylaştırır.


14
"Düşük aralıkların" istemci içinde koordine edildiğini mi söylüyorsunuz, "yüksek sıra" ise bir DB sırasına karşılık geliyor mu?
Chris Noe

14
Hi & lo değerleri tipik olarak tek bir tamsayı değerinde mi yoksa iki kısımlı bir işletme anahtarı mıdır?
Chris Noe

51
IP adresi gibi - ICANN size yüksek bir 'ağ' numarası verirse, verdiğiniz CIDR aralığı sınırında istediğiniz kadar düşük 'ana bilgisayar' numarasına sahip olursunuz.
gbjbaanb

6
@Adam: Temel olarak, hiçbir şey - bir değeri ("yüksek" kısım) arttırmak potansiyel olarak bir grup anahtar oluşturmaktan daha ucuzdur. ( Veri aktarımı açısından potansiyel olarak çok daha ucuzdur - minimum sayıda bant genişliğine sahip çok sayıda anahtarı "ayırabilirsiniz".)
Jon Skeet

4
@Adam: Anahtarlar sadece rakamsa bu doğrudur. GUID'ler için çok fazla değil :) Ama evet, basit sayılar söz konusu olduğunda, herhangi bir atomik "sabit bir miktarda artış" yapacaktır. Eğer bir sayıyı iki bölüme ayırırsanız, hi-lo'nun yaptığı şey budur.
Jon Skeet

157

Jon'un cevabına ek olarak:

Bağlantısız çalışabilmek için kullanılır. Bir istemci daha sonra sunucudan bir hi numarası isteyebilir ve lo sayısının kendisini artıran nesneler oluşturabilir. Lo aralığı bitinceye kadar sunucuyla iletişim kurması gerekmez.


1
Bunu kısalık için tercih ederim.
Geliştirici Marius Žilėnas

34

Bu çok yaygın bir soru olduğundan, bu cevabın dayandığı bu makaleyi yazdım .

Hi / lo algoritmaları sekans alanını “hi” gruplarına böler. Eşzamanlı olarak bir “hi” değeri atanır. Her "hi" grubuna, eşzamanlı yinelenen girişler hakkında endişelenmeden çevrimdışı olarak atanabilen maksimum sayıda "lo" girişi verilir.

  1. “Hi” belirteci veritabanı tarafından atanır ve iki ardışık çağrının benzersiz ardışık değerleri görmesi garanti edilir
  2. Bir “hi” jetonu alındıktan sonra yalnızca “incrementSize” e (“lo” giriş sayısı) ihtiyacımız var
  3. Tanımlayıcı aralığı aşağıdaki formülle verilmiştir:

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

    ve "lo" değeri şu aralıkta olacaktır:

    [0, incrementSize)

    başlangıç ​​değerinden uygulanıyorsa:

    [(hi -1) * incrementSize) + 1)
  4. Tüm "lo" değerleri kullanıldığında, yeni bir "hi" değeri getirilir ve döngü devam eder

Bu makalede daha ayrıntılı bir açıklama bulabilirsiniz :

Ve bu görsel sunumu takip etmek de kolay:

resim açıklamasını buraya girin

Hi / lo optimizer tanımlayıcı üretimini optimize etmek için iyi olsa da, tanımlama stratejimiz hakkında hiçbir şey bilmeden veritabanımıza satır ekleyen diğer sistemlerle iyi oynamaz.

Hibernate , hi / lo jeneratör stratejisinin avantajlarını sunan ve aynı zamanda bu dizi ayırma stratejisinin farkında olmayan diğer 3. taraf istemcilerle birlikte çalışabilirlik sağlayan birleştirilmiş optimizasyon aracı sunar.

Hem verimli hem de diğer sistemlerle birlikte çalışabilir olan pooled-lo optimizer, eski hi / lo tanımlayıcı stratejisinden çok daha iyi bir adaydır.


Seni bazen anlamıyorum hahaha yani: hi / lo optimizer tanımlayıcı üretimi optimize etmek için iyi olsa da (Tamam iyi), diğer sistemlerle iyi oynamıyor (diğer sistemlerle ne demek istiyorsun? olanlar?) tanımlayıcı stratejimiz hakkında hiçbir şey bilmeden veritabanımıza satır ekleme (Tanımlayıcı oluşturma, satır eklemek için de kullanılmıyor mu?).
Adelin

INSERT deyimi çalıştırmaya çalışan bir DBA gibi diğer sistemler. Geçerli sıra verilerini okursa, bu belirli DB tablosunda hilo kullandığımızı bilerek bir sonraki tanımlayıcı değerini bulmanın kolay olduğunu düşünüyor musunuz?
Vlad Mihalcea

Yorumunuz yanıtınız için uygun değilse özür dilerim, ancak varsayılan olarak hangi optimize edicinin kullanıldığını merak ediyordum? Yoksa DB (PostgreSQL kullanıyorum) bağlıdır? Çünkü geçerli dizi değeri ve oluşturulan kimlikler arasındaki ilişkiyi anlayamıyorum. @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "name") @SequenceGenerator(name="name", sequenceName = "name_seq", allocationSize=100)Kimliklerim için kullanıyorum .
Stefan Golubović

1
Hazırda Bekletme 5'den beri, Toplanan Hi / lo değil, yeni Optimize Edici'dir. Havuzlanmış Optimize Edici hakkında daha fazla bilgi için bu makaleye göz atın .
Vlad Mihalcea

@VladMihalcea, sanırım üçüncü madde işaretinde bir yazım hatası var, ilk kod parçacığı , (hi * incrementSize) + 1)... öyle olmalı , hi * incrementSize), değil mi?
Huiagan

23

Lo, anahtar boşluğunu, bir insanın mantıklı bir şekilde seçebileceği anlamlı boyut aralıklarından (örneğin, bir seferde 200 anahtar elde etmek) ziyade, tipik olarak bazı makine kelime boyutuna bağlı olarak büyük parçalara ayıran önbelleğe alınmış bir ayırıcıdır.

Hi-Lo kullanımı, sunucu yeniden başlatıldığında çok sayıda anahtarı boşa harcama ve büyük insan dostu olmayan anahtar değerler oluşturma eğilimindedir.

Hi-Lo ayırıcıdan daha iyi olan "Lineer Chunk" ayırıcıdır. Bu tablo benzeri bir ilkeyi kullanır, ancak küçük, uygun büyüklükte parçalar ayırır ve hoş insan dostu değerler üretir.

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

Bir sonraki, örneğin 200 anahtarı ayırmak için (bunlar sunucuda bir aralık olarak tutulur ve gerektiği gibi kullanılır):

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

Bu işlemi gerçekleştirebilmeniz (çekişmeyi işlemek için yeniden deneme yöntemlerini kullan) şartıyla, 200 anahtar ayırdınız ve gerektiğinde dağıtabilirsiniz.

Yığın boyutu sadece 20 olan bu şema, bir Oracle dizisinden ayırmaktan 10 kat daha hızlıdır ve tüm veritabanları arasında% 100 taşınabilir. Tahsis performansı hi-lo'ya eşdeğerdir.

Ambler'in fikrinden farklı olarak, anahtar boşluğuna bitişik doğrusal bir sayı satırı gibi davranır.

Bu, kompozit anahtarların (gerçekten iyi bir fikir olmadı) hızını önler ve sunucu yeniden başlatıldığında tüm sözcüklerin israfını önler. "Dost", insan ölçeğinde anahtar değerler üretir.

Bay Ambler'in fikri, karşılaştırma olarak, yüksek 16 veya 32 biti ayırır ve yüksek kelimelerin artması olarak büyük insan dostu olmayan anahtar değerler üretir.

Tahsis edilen anahtarların karşılaştırılması:

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

Tasarım açısından çözümü, karşılaştırma çizgisi elde edilmeden sayı çizgisinde (bileşik anahtarlar, büyük hi_word ürünleri) Linear_Chunk'tan daha karmaşıktır.

Hi-Lo tasarımı OO haritalamasında ve kalıcılığında erken ortaya çıktı. Bugünlerde Hazırda Bekleme gibi kalıcılık çerçeveleri varsayılan olarak daha basit ve daha iyi ayırıcılar sunar.


4
Güzel gönderi, ama soruyu cevaplamıyorsun.
14'te orbfish

1
İlginç bir cevap için +1. Başvuruların büyük çoğunluğunun Hi-Lo'dan daha basit bir yaklaşım karşısında hiçbir avantaj sağlamadığını kabul ediyorum; ancak, Hi-Lo'nun çok eşzamanlı uygulamalarda çoklu ayırıcıların özel durumuna daha uygun olduğunu düşünüyorum.
richj

1
Teşekkürler @richj! Demek istediğim , "lineer blok tahsisi" ile birden fazla ayırıcı veya büyük blok boyutları kullanabilmenizdir, ancak Hi / Lo'dan farklı olarak, NEXT_VAL ayırıcısının tablodaki tuşlara doğrusal bir şekilde uymasını sağlar ve ayarlanabilir. HiLo'nun aksine, çarpmaya gerek yoktur - sadece gerekli değildir! NEXT_HI çarpanı ve depolaması HiLo'yu daha karmaşık hale getirir ve ayarlanabilirliği bozar, çünkü blok boyutunu değiştirmek verilecek bir sonraki anahtarı keyfi olarak değiştirir. Bakınız: literatejava.com/hibernate/…
Thomas W

2
Birden fazla bağımsız ayırıcıyla ilgileniyorum. Hi-Lo ile yüksek değerin bölücü kimliği / blok kimliği olarak bölümlendirilebileceği açıktır. Aynı yaklaşımın Lineer Chunk'a uygulanabileceği hemen belli değildi (fakat bana göre), toplam aralığın ayırıcılar arasındaki bölünmesi ile aynı problem. Şimdi anladım. Teşekkürler.
richj

1
Oh, bunu düşündükten sonra, SEQ sütununun bir tablo adıyla eşleştiğini düşünüyorum. Örneğin, Müşteriler tablosunda, biri Siparişler tablosunda, vb. İçin bir ayırıcı vardır. Affet beni, bazen yavaşım.
Rock Anthony Johnson

1

Hi / Lo algoritmasının tecrübelerime dayanarak çoğaltma senaryolarına sahip birden çok veritabanı için mükemmel olduğunu gördüm. Bunu hayal edin. New York'ta (takma ad 01) bir sunucunuz ve Los Angeles'ta (takma ad 02) başka bir sunucunuz var, o zaman bir PERSON tablonuz var ... yani bir kişi oluştururken New York'ta ... HI değeri olarak her zaman 01 kullanıyorsunuz ve LO değeri bir sonraki güvenlik açığıdır. örnek.

  • 010000010 Jason
  • 010000011 David
  • 010000012 Theo

Los Angeles'ta her zaman HI 02 kullanıyorsunuz. örneğin:

  • 020000045 Rupert
  • 020000046 Oswald
  • 020000047 Mario

Bu nedenle, veritabanı çoğaltmasını (hangi marka olursa olsun) kullandığınızda, tüm birincil anahtarlar ve veriler, yinelenen birincil anahtarlar, koleksiyonlar vb.

Bu senaryoya girmenin en iyi yolu budur.


Hazırda Bekletme modunda çalışmaz. HiLo algrotirm her işlemde yeni bir dizi değeri alır, bu nedenle HI sayacı akordinal olarak artar. Ancak örneğinizde, HI sayacı bir DB için her zaman sabittir.
Dmitry1405
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.