อัลกอริทึม Hi / Lo คืออะไร?


464

อัลกอริทึม Hi / Lo คืออะไร?

ฉันพบสิ่งนี้ในเอกสารของNHibernate (เป็นวิธีหนึ่งในการสร้างคีย์ที่ไม่ซ้ำกันในส่วน 5.1.4.2) แต่ฉันไม่พบคำอธิบายที่ดีเกี่ยวกับวิธีการทำงาน

ฉันรู้ว่า Nhibernate จัดการกับมันและฉันไม่จำเป็นต้องรู้ว่าข้างใน แต่ฉันแค่อยากรู้

คำตอบ:


540

แนวคิดพื้นฐานคือคุณมีตัวเลขสองตัวเพื่อสร้างคีย์หลัก - หมายเลข "สูง" และหมายเลข "ต่ำ" โดยทั่วไปแล้วลูกค้าสามารถเพิ่มลำดับ "สูง" โดยรู้ว่าสามารถสร้างคีย์ได้อย่างปลอดภัยจากช่วงทั้งหมดของค่า "สูง" ก่อนหน้านี้ด้วยความหลากหลายของค่า "ต่ำ"

ตัวอย่างเช่นสมมติว่าคุณมีลำดับ "สูง" ที่มีค่าปัจจุบันเท่ากับ 35 และหมายเลข "ต่ำ" อยู่ในช่วง 0-1023 จากนั้นลูกค้าสามารถเพิ่มลำดับเป็น 36 (เพื่อให้ลูกค้ารายอื่นสามารถสร้างคีย์ได้ในขณะที่ใช้งาน 35) และรู้ว่าคีย์ 35/0, 35/1, 35/2, 35/3 ... 35/1023 คือ ที่มีอยู่ทั้งหมด

มันมีประโยชน์มาก (โดยเฉพาะกับ ORMs) เพื่อให้สามารถตั้งค่าคีย์หลักในฝั่งไคลเอ็นต์แทนการแทรกค่าโดยไม่มีคีย์หลักแล้วดึงกลับไปยังไคลเอนต์ นอกเหนือจากสิ่งอื่นก็หมายความว่าคุณสามารถทำให้ผู้ปกครอง / ความสัมพันธ์กับเด็กและมีกุญแจทั้งหมดในสถานที่ก่อนที่คุณทำใด ๆแทรกซึ่งจะทำให้พวกเขา batching ง่าย


14
คุณกำลังบอกว่า "ช่วงต่ำ" มีการประสานงานภายในไคลเอนต์ในขณะที่ "ลำดับสูง" สอดคล้องกับลำดับ DB หรือไม่?
Chris Noe

14
โดยทั่วไปแล้วค่า hi & lo จะประกอบด้วยค่าจำนวนเต็มเดียวหรือเป็นคีย์ธุรกิจสองส่วนหรือไม่
395 Chris Noe

51
เช่นเดียวกับที่อยู่ IP - ICANN ให้หมายเลข 'เครือข่าย' ที่สูงคุณจึงมีหมายเลข 'โฮสต์' ต่ำที่สุดเท่าที่คุณต้องการภายในขอบเขต CIDR ที่คุณได้รับ
gbjbaanb

6
@ อดัม: พื้นฐานไม่มีอะไร - มันอาจจะถูกกว่าที่จะเพิ่มค่าหนึ่ง (ส่วน "สูง") กว่าที่จะสร้างพวงกุญแจ (มันอาจมากราคาถูกกว่าในแง่ของการถ่ายโอนข้อมูล - คุณสามารถ "สำรอง" จำนวนมากของกุญแจที่มีแบนด์วิดธ์น้อยที่สุด.)
จอนสกีต

4
@ อดัม: มันเป็นความจริงหากปุ่มเป็นเพียงตัวเลข ไม่มากสำหรับ GUIDs :) แต่ใช่ในกรณีของตัวเลขง่าย ๆ อะตอมใด ๆ "การเพิ่มขึ้นตามจำนวนคงที่" จะทำอย่างไร นั่นเป็นสิ่งที่ Hi-Lo กำลังทำอยู่อย่างมีประสิทธิภาพถ้าคุณคิดว่ามันเป็นตัวเลขหนึ่งตัวแบ่งออกเป็นสองส่วน
Jon Skeet

157

นอกจากคำตอบของจอน:

มันถูกใช้เพื่อให้สามารถเชื่อมต่อการทำงาน จากนั้นลูกค้าสามารถขอหมายเลขเซิร์ฟเวอร์และสร้างวัตถุที่เพิ่มจำนวนตัวเองได้ ไม่จำเป็นต้องติดต่อกับเซิร์ฟเวอร์จนกว่าจะใช้ช่วงที่มีค่าหมด


1
ฉันชอบสิ่งนี้เพื่อความกระชับ
พัฒนา Marius Žilėnas

34

เนื่องจากนี่เป็นคำถามที่พบบ่อยมากฉันจึงเขียนบทความนี้ขึ้นมาซึ่งคำตอบนี้ขึ้นอยู่กับ

อัลกอริทึม hi / lo แยกโดเมนลำดับออกเป็นกลุ่ม "hi" ค่า“ hi” ถูกกำหนดให้พร้อมกัน กลุ่ม "hi" ทุกกลุ่มจะได้รับรายการ "lo" สูงสุดจำนวนสูงสุดซึ่งสามารถกำหนดโดยออฟไลน์โดยไม่ต้องกังวลเกี่ยวกับรายการที่ซ้ำกันที่เกิดขึ้นพร้อมกัน

  1. โทเค็น“ hi” ถูกกำหนดโดยฐานข้อมูลและรับประกันการโทรพร้อมกันสองครั้งเพื่อดูค่าที่ไม่ซ้ำกัน
  2. เมื่อเรียกโทเค็น“ สวัสดี” เราจะต้องใช้“ incrementSize” เท่านั้น (จำนวนรายการ“ lo”)
  3. ช่วงตัวระบุได้รับจากสูตรต่อไปนี้:

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

    และค่า "lo" จะอยู่ในช่วง:

    [0, incrementSize)

    ถูกนำไปใช้จากค่าเริ่มต้นของ:

    [(hi -1) * incrementSize) + 1)
  4. เมื่อใช้ค่า "lo" ทั้งหมดจะมีการเรียกค่า "hi" ใหม่และวัฏจักรจะดำเนินต่อไป

คุณสามารถหาคำอธิบายโดยละเอียดเพิ่มเติมได้ในบทความนี้ :

และการนำเสนอด้วยภาพนี้ง่ายต่อการติดตามเช่นกัน:

ป้อนคำอธิบายรูปภาพที่นี่

ในขณะที่เครื่องมือเพิ่มประสิทธิภาพ hi / lo นั้นใช้งานได้ดีสำหรับการปรับการสร้างตัวระบุ แต่มันก็เล่นได้ไม่ดีนักกับระบบอื่น ๆ ที่แทรกแถวเข้าไปในฐานข้อมูลของเรา

Hibernate เสนอเครื่องมือเพิ่มประสิทธิภาพpooled-loซึ่งนำเสนอข้อดีของกลยุทธ์ตัวสร้าง hi / lo ขณะเดียวกันก็ให้การทำงานร่วมกันกับลูกค้าบุคคลที่สามอื่น ๆ ที่ไม่ทราบถึงกลยุทธ์การจัดสรรลำดับนี้

เนื่องจากทั้งประสิทธิภาพและทำงานร่วมกันกับระบบอื่น ๆ เครื่องมือเพิ่มประสิทธิภาพ pooled-lo เป็นตัวเลือกที่ดีกว่ากลยุทธ์ตัวระบุ hi / lo แบบดั้งเดิม


ฉันไม่เข้าใจคุณจริงๆบางครั้งฮ่าฮ่าฮ่าดังนั้น: ในขณะที่เครื่องมือเพิ่มประสิทธิภาพ hi / lo นั้นดีสำหรับการปรับการสร้างตัวระบุ (ดีพอ) มันไม่เล่นได้ดีกับระบบอื่น ๆ (คุณหมายถึงอะไรโดยระบบอื่น ๆ ? อัน?) การแทรกแถวลงในฐานข้อมูลของเรา (ไม่สร้างตัวระบุที่ใช้ในการแทรกแถวด้วย?) โดยไม่ทราบอะไรเกี่ยวกับกลยุทธ์ตัวระบุของเรา
Adelin

ระบบอื่น ๆ เช่น DBA พยายามเรียกใช้คำสั่ง INSERT หากเธออ่านข้อมูลลำดับปัจจุบันคุณคิดว่าเป็นเรื่องง่ายหรือไม่ที่จะหาค่าตัวระบุถัดไปที่รู้ว่าเราใช้ hilo ในตารางฐานข้อมูลนี้หรือไม่
Vlad Mihalcea

ฉันขอโทษถ้าความคิดเห็นไม่เหมาะกับคำตอบของคุณ แต่ฉันสงสัยว่าจะใช้เครื่องมือเพิ่มประสิทธิภาพแบบใด หรือไม่ก็ขึ้นอยู่กับฐานข้อมูล (ฉันใช้ PostgreSQL)? เพราะฉันไม่สามารถหาความสัมพันธ์ระหว่างค่าลำดับปัจจุบันและรหัสที่สร้างขึ้นได้ ฉันใช้@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "name") @SequenceGenerator(name="name", sequenceName = "name_seq", allocationSize=100)รหัสประจำตัวของฉัน
สเตฟานGolubović

1
ตั้งแต่ Hibernate 5 Pooled เป็นเครื่องมือเพิ่มประสิทธิภาพใหม่ไม่ใช่ Hi / lo ลองอ่านบทความนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับเครื่องมือเพิ่มประสิทธิภาพ Pooled
Vlad Mihalcea

@VladMihalcea ฉันเชื่อว่าคุณมีการพิมพ์ผิดใน bullet สามตัวอย่างแรกที่, (hi * incrementSize) + 1)... มันควรจะ, hi * incrementSize)ใช่มั้ย?
Huiagan

23

Lo คือตัวจัดสรรแคชที่แยก keyspace ออกเป็นชิ้นใหญ่โดยทั่วไปจะขึ้นอยู่กับขนาดของคำศัพท์ของเครื่องแทนที่จะเป็นช่วงขนาดที่มีความหมาย

การใช้ Hi-Lo มีแนวโน้มที่จะทำให้เสียคีย์จำนวนมากในการรีสตาร์ทเซิร์ฟเวอร์และสร้างค่าคีย์ขนาดใหญ่ที่ไม่เป็นมิตรกับมนุษย์

ดีกว่าตัวจัดสรร Hi-Lo คือตัวจัดสรร "Linear Chunk" สิ่งนี้ใช้หลักการที่อิงกับตารางคล้ายกัน แต่จัดสรรชิ้นขนาดเล็กและสะดวกสบายและสร้างคุณค่าที่เป็นมิตรกับมนุษย์

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

หากต้องการจัดสรรถัดไปให้พูด 200 คีย์ (ซึ่งจะถูกเก็บไว้เป็นช่วงในเซิร์ฟเวอร์ & ใช้ตามต้องการ):

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

เพื่อให้คุณสามารถทำธุรกรรมนี้ (ใช้การลองใหม่เพื่อจัดการกับการโต้แย้ง) คุณได้จัดสรร 200 คีย์และสามารถแจกจ่ายได้ตามต้องการ

ด้วยขนาดที่เล็กเพียง 20 โครงร่างนี้เร็วกว่าการจัดสรรจากลำดับ Oracle 10 เท่าและสามารถพกพาได้ 100% ในฐานข้อมูลทั้งหมด ประสิทธิภาพการจัดสรรเทียบเท่ากับ hi-lo

ซึ่งแตกต่างจากความคิดของ Ambler มันถือว่า keyspace เป็นตัวเลขเชิงเส้นที่ต่อเนื่องกัน

สิ่งนี้หลีกเลี่ยงแรงกระตุ้นสำหรับคีย์คอมโพสิต (ซึ่งไม่เคยเป็นความคิดที่ดีจริงๆ) และหลีกเลี่ยงการสูญเสียคำศัพท์ทั้งหมดเมื่อเซิร์ฟเวอร์รีสตาร์ท มันสร้างค่าคีย์มิตร "มิตร" ระดับมนุษย์

ความคิดของนายแอมโบเลอร์โดยการเปรียบเทียบจัดสรร 16-32- บิตสูงและสร้างค่าคีย์ที่ไม่เป็นมิตรกับมนุษย์จำนวนมากเป็นการเพิ่มคำศัพท์

การเปรียบเทียบคีย์ที่จัดสรร:

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

การออกแบบที่ชาญฉลาดโซลูชันของเขามีความซับซ้อนโดยพื้นฐานบนหมายเลขบรรทัด (คีย์ผสมผลิตภัณฑ์ hi_word ขนาดใหญ่) กว่า Linear_Chunk โดยไม่ได้รับผลประโยชน์เชิงเปรียบเทียบ

การออกแบบ Hi-Lo เกิดขึ้นในช่วงต้นของการทำแผนที่ OO และการคงอยู่ เฟรมเวิร์กการคงอยู่ของวันนี้เช่น Hibernate เสนอตัวจัดสรรที่ง่ายกว่าและดีกว่าเป็นค่าเริ่มต้น


4
โพสต์ดี แต่คุณไม่ได้ตอบคำถาม
orbfish

1
+1 สำหรับคำตอบที่น่าสนใจ ฉันยอมรับว่าแอพพลิเคชั่นส่วนใหญ่ไม่ได้รับประโยชน์จาก Hi-Lo ในวิธีที่ง่ายกว่า แต่ฉันคิดว่า Hi-Lo นั้นเหมาะสำหรับกรณีพิเศษของตัวจัดสรรหลายตัวในแอปพลิเคชันที่เกิดขึ้นพร้อมกันสูง
richj

1
ขอบคุณ @richj! ประเด็นของฉันคือคุณสามารถใช้ตัวจัดสรรหลายตัวหรือขนาดบล็อกขนาดใหญ่ด้วย "การจัดสรรบล็อกเชิงเส้น" แต่นั่นไม่เหมือน Hi / Lo - มันรักษาความสอดคล้องเชิงเส้นของตัวจัดสรร NEXT_VAL กับคีย์ในตารางและสามารถปรับได้ ซึ่งแตกต่างจาก HiLo ไม่จำเป็นต้องมีการคูณ - มันก็ไม่จำเป็น! ตัวคูณและการจัดเก็บของ NEXT_HI ทำให้ HiLo มีความซับซ้อนมากขึ้น & แบ่งความสามารถในการปรับเนื่องจากการเปลี่ยนขนาดบล็อกจะเป็นการเปลี่ยนคีย์ถัดไปโดยพลการที่จะออก .. ดู: literatejava.com/hibernate/ …
โทมัส W

2
ฉันสนใจผู้จัดสรรอิสระหลายราย ด้วย Hi-Lo เป็นที่ชัดเจนว่าค่าสูงสามารถแบ่งพาร์ติชันเป็น ID จัดสรร / ID บล็อก ไม่ชัดเจนในทันที (สำหรับฉัน) ว่าแนวทางเดียวกันนี้สามารถนำไปใช้กับ Linear Chunk ได้ แต่โดยทั่วไปแล้วปัญหาเดียวกันของการหารช่วงทั้งหมดระหว่างตัวจัดสรร ฉันเข้าใจแล้ว ขอบคุณ
richj

1
โอ้หลังจากคิดเกี่ยวกับมันฉันคิดว่าคอลัมน์ SEQ แมปกับชื่อตาราง ตัวอย่างเช่นมีตัวจัดสรรตารางลูกค้าหนึ่งรายสำหรับตารางคำสั่งซื้อและอื่น ๆ ยกโทษให้ฉันฉันช้าบางครั้ง
Rock Anthony Johnson

1

ฉันพบว่าอัลกอริทึม Hi / Lo นั้นสมบูรณ์แบบสำหรับหลายฐานข้อมูลที่มีสถานการณ์การจำลองแบบตามประสบการณ์ ลองนึกภาพสิ่งนี้ คุณมีเซิร์ฟเวอร์ในนิวยอร์ก (นามแฝง 01) และเซิร์ฟเวอร์อื่นในลอสแองเจลิส (นามแฝง 02) จากนั้นคุณมีตารางส่วนบุคคล ... ดังนั้นในนิวยอร์กเมื่อบุคคลสร้าง ... คุณใช้ 01 เป็นค่า HI เสมอ และค่า LO คือ secuential ถัดไป ตัวอย่าง

  • 010000010 เจสัน
  • 010000011 เดวิด
  • 010000012 ธีโอ

ในลอสแองเจลิสคุณใช้ HI 02 เสมอเช่น:

  • 020000045 รูเพิร์ต
  • 020000046 ออสวอลด์
  • 020000047 มาริโอ

ดังนั้นเมื่อคุณใช้การจำลองแบบฐานข้อมูล (ไม่ว่ายี่ห้อใด) คีย์หลักและข้อมูลทั้งหมดจะรวมกันได้อย่างง่ายดายและเป็นธรรมชาติโดยไม่ต้องกังวลกับคีย์หลักที่ซ้ำกันการคอลและอื่น ๆ

นี่เป็นวิธีที่ดีที่สุดในสถานการณ์นี้


มันไม่ทำงานในไฮเบอร์เนต HiLo algrotirm ได้รับค่าลำดับใหม่ในแต่ละธุรกรรมดังนั้นการเพิ่มขึ้นของตัวนับ HI ตามลำดับ แต่ในตัวอย่างของคุณ HI-counter คงที่เสมอสำหรับหนึ่งฐานข้อมูล
Dmitry1405
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.