ไทย

เครื่องมือสำหรับนักพัฒนา · ตัวสร้าง UUID

สุ่ม UUID คีย์หลักและการกระจายตัวของ B-Tree: เกิดอะไรขึ้นจริงๆ

· เหตุใดจึงสำคัญ

uuid การเข้ารหัส เบราว์เซอร์-apis

แผนภาพ B-tree แสดงส่วนแทรกตามลำดับที่เติมหน้าเดียว เทียบกับส่วนแทรกแบบสุ่มที่กระจัดกระจายอยู่ในหลายหน้า
ภาพประกอบเวกเตอร์ต้นฉบับ ToolAcre

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

ส่วนแทรกช้าลงเมื่อตารางใหญ่ขึ้น — อาการที่ส่งผลให้ DBA พิจารณาตัวเลือกหลักของพวกเขา

การแทรกแถวที่มีการสุ่ม UUID เป็นคีย์หลักในฐานข้อมูลที่มีดัชนีคลัสเตอร์จะทำให้ฐานข้อมูลแทรกแถวใหม่ในตำแหน่งสุ่มภายในโครงสร้าง B-tree คีย์ลำดับต่อท้ายหน้าใบไม้ขวาสุด ทำให้ส่วนแทรกทั้งหมดอยู่ภายในพื้นที่ขนาดเล็กที่อาศัยแคช คีย์สุ่มจะกระจายส่วนแทรกทั่วทั้งดัชนี บังคับให้ฐานข้อมูลสำรวจและแก้ไขเพจให้ห่างกันมากในที่จัดเก็บข้อมูลทางกายภาพ เมื่อตารางขยายใหญ่ขึ้นและโครงสร้างต้นไม้ลึกขึ้น ทุกส่วนแทรกจะสัมผัสกับหน้ามากขึ้น และทำให้การดำเนินการ I/O มากขึ้น การดำเนินการที่ดูเหมือนถูกเมื่อพันแถว จะกลายเป็นราคาแพงเป็นล้าน นี่ไม่ใช่ปัญหาทางทฤษฎี มันแสดงให้เห็นว่าเป็นการย่อยสลายที่วัดได้ในปริมาณการแทรก

วิธีเติม B-tree แบบคลัสเตอร์ - คีย์ตามลำดับต่อท้ายหน้าสุดท้าย ปุ่มสุ่มสัมผัสหน้าทั่วทั้งดัชนี

กลไกนี้เป็นพื้นฐานในการทำงานของ B-tree เนื่องจากพวกมันรักษาลำดับคีย์ที่เรียงลำดับไว้ภายในหน้าใบไม้ เมื่อคุณแทรกแถวที่มีคีย์ 10,001 ลงในตารางที่ได้จัดเก็บคีย์ 1 ถึง 10,000 ไว้แล้ว ฐานข้อมูลจะรู้ว่าแถวนั้นอยู่ที่ใด: ในตอนท้าย ในเพจขวาสุดที่มีอยู่หากมีช่องว่าง หรือในเพจใหม่ที่ต่อท้ายทางด้านขวา เมื่อคุณแทรกแถวที่มีการสุ่ม UUID เช่น 7524fae2-7dec-11d0-a765-00a0c91e6bf6 ลงในตารางเดียวกัน ฐานข้อมูลจะต้องนำทางแผนผังเพื่อค้นหาเพจย่อยที่มีคีย์ในช่วง UUID นั้น ค้นหาตำแหน่งที่แน่นอนภายในเพจนั้น และแทรกแถว หากหน้านั้นเต็ม หน้าจะแยก ย้ายเนื้อหาครึ่งหนึ่งไปยังหน้าใหม่ และอัปเดตโหนดหลัก

การแยกหน้าและความกดดันของแคช — เหตุใดการแทรกแบบสุ่มจึงมีค่าใช้จ่ายมากกว่า I/O และเหตุใดเอฟเฟกต์จึงขยายตามขนาดตาราง

ปุ่มสุ่มจะสร้างรูปแบบการแทรกกรณีที่แย่ที่สุด เนื่องจากทุกส่วนแทรกจะลงที่ตำแหน่งสุ่มในแผนผังแทนที่จะต่อท้ายหน้าขวาสุด ฐานข้อมูลจะต้องค้นหาเพจที่ถูกต้อง ซึ่งโดยปกติแล้วจะมีค่าใช้จ่ายในการอ่านหลายเพจ—หนึ่งเพจต่อระดับของแผนผัง จากนั้นจะต้องแก้ไขหน้านั้น ซึ่งอาจทำให้เกิดการแบ่งแยกที่แพร่กระจายขึ้นไปบนแผนผัง มีการแก้ไขเพจมากขึ้น มีการเขียนเพิ่มขึ้น และพูลบัฟเฟอร์หน่วยความจำจะเต็มไปด้วยเพจจากภูมิภาคต่างๆ ของแผนผัง แทนที่จะมุ่งเน้นไปที่จุดแทรกที่ใช้งานอยู่ แคชพลาดเพิ่มขึ้น และ I/O กลายเป็นคอขวด โดยมีอัตราการแทรกเพิ่มขึ้นเมื่อตารางขยายไปสู่ระดับที่ใหญ่ขึ้น

ข้อความหรือไบนารี — สตริงอักขระ 36 เทียบกับคอลัมน์ uuid ดั้งเดิมหรือไบนารี (16) 16 ไบต์ และผลกระทบต่อขนาดดัชนี

ต้นทุนไม่เท่ากันในกลไกฐานข้อมูล เนื่องจากระบบที่ต่างกันปรับการจัดการเพจให้เหมาะสมแตกต่างกัน ฐานข้อมูลที่มีการบีบอัดข้อมูลเชิงรุก ขนาดเพจเล็ก หรือการดำเนินการในหน่วยความจำอาจแสดงความแตกต่างด้านประสิทธิภาพเล็กน้อยระหว่างคีย์ตามลำดับและคีย์สุ่ม ฐานข้อมูลที่มีเพจขนาดใหญ่ ดิสก์เชิงกล หรือมีหน่วยความจำจำกัดจะเสื่อมลงอย่างมาก ปัญหาเป็นสิ่งที่สังเกตและวัดได้: วัดอัตราการแทรกที่ 1,000 แถว 100,000 แถว และ 1,000,000 แถว หากอัตราต่อวินาทีลดลงอย่างรวดเร็วในระดับที่ใหญ่ขึ้น คุณกำลังประสบปัญหาการแทรกแบบสุ่มกับฮาร์ดแวร์และการกำหนดค่าฐานข้อมูลเฉพาะของคุณ

ทางเลือกที่เรียงลำดับเวลา - UUIDv7 และ ULID รักษาเอกลักษณ์ในขณะที่แทรกที่ส่วนท้ายของดัชนีอย่างไร

UUID เป็นสตริงใช้อักขระ 36 ในรูปแบบข้อความหรือ 16 bytes เป็นประเภทไบนารี UUID ขึ้นอยู่กับรูปแบบพื้นที่เก็บข้อมูลที่เลือก สตริงอักขระ 36 ในคอลัมน์ UTF-8 หรือ ASCII คือ 36 bytes เมื่อเปรียบเทียบกับ 8 bytes สำหรับจำนวนเต็ม 64 บิต ดัชนีในคอลัมน์ string-UUID มีขนาดใหญ่กว่าดัชนีในคอลัมน์จำนวนเต็มถึงสามเท่า โดยถือว่าไม่มีการใช้เทคนิคการบีบอัด ดัชนีที่ใหญ่ขึ้นหมายถึงมีหน้าดัชนีน้อยลงที่พอดีกับพูลบัฟเฟอร์ ซึ่งหมายถึงการเข้าใช้แคชน้อยลงเมื่อสำรวจแผนผัง ดัชนีขนาดเล็กที่เหมาะกับ RAM ทำงานได้ดีกว่าดัชนีขนาดใหญ่ที่ต้องอ่านจากดิสก์ในทุกแบบสอบถาม โดยไม่คำนึงถึงลำดับการแทรกหรือรูปแบบปริมาณงาน

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

ความแตกต่างในการจัดเก็บข้อมูลมีความสำคัญอย่างมากสำหรับทั้งดัชนีหลักและดัชนีรอง เนื่องจากทุกดัชนีรองที่มีคีย์หลักจะต้องจัดเก็บค่า 36 อักขระ UUID หรือ 16 ไบต์ไบนารี UUID แบบเต็ม ซึ่งทำให้ดัชนีรองมีขนาดใหญ่กว่าดัชนีอย่างมากโดยใช้คีย์จำนวนเต็มสำหรับการค้นหาคีย์หลัก ชุดผลลัพธ์การจำลองแบบ การสำรองข้อมูล และแบบสอบถามทั้งหมดจะเติบโตตามสัดส่วนด้วยขนาดดัชนีที่ใหญ่ขึ้น ตัวสร้าง ToolAcre UUID สร้างค่าที่เข้ากันได้กับไบนารี จัดเก็บเป็นประเภท binary(16) หรือ GUID ขึ้นอยู่กับฐานข้อมูลช่วยประหยัดพื้นที่เมื่อเปรียบเทียบกับ varchar(36) และปรับปรุงประสิทธิภาพแคชทั่วทั้งกระดาน การเพิ่มประสิทธิภาพพื้นที่จัดเก็บข้อมูลนี้เป็นสิ่งสำคัญสำหรับระบบขนาดใหญ่

สิ่งนี้ไม่ครอบคลุมถึง — ตารางและฐานข้อมูลที่มีการจัดระเบียบฮีปโดยที่คีย์หลักไม่ได้ถูกคลัสเตอร์ โดยที่เอฟเฟกต์จะมีน้อยกว่า

การเพิ่มประสิทธิภาพทั่วไปคือการจัดเก็บ UUID เป็นไบนารีภายในและแสดงเป็นสตริงเมื่อจำเป็นสำหรับ API หรืออินเทอร์เฟซผู้ใช้เท่านั้น การดำเนินการดัชนีและการรวมทำงานในรูปแบบไบนารี่ขนาดกะทัดรัด การตอบสนอง API หรือรหัสแอปพลิเคชันแปลงเป็นตัวแทนสตริง ฐานข้อมูลบางแห่งมีประเภท GUID หรือ UUID ในตัวที่จัดการการแปลงนี้โดยอัตโนมัติ ส่วนอื่นๆ จำเป็นต้องมีการดำเนินการหล่อที่ชัดเจน ความแตกต่างด้านประสิทธิภาพระหว่างคอลัมน์ 36-byte และ 16-byte นั้นเป็นจริง: ตารางที่มีหนึ่งล้านแถวและ 36-ไบต์ เทียบกับ 16-ไบต์ UUID คีย์คอลัมน์จะแตกต่างกัน 20 MB ต่อระดับดัชนี ซึ่งอาจเป็นความแตกต่างระหว่างการปรับดัชนีให้เหมาะสมในแคช L3 และต้องมีการดึงหน่วยความจำ

ประเด็นสำคัญ: รู้จักดัชนีของคุณก่อนที่คุณจะเลือกเวอร์ชัน — ตัวสร้าง ToolAcre จะสร้าง UUID แบบสุ่ม ใช้โพสต์เพื่อตัดสินใจว่าเหมาะกับเครื่องมือจัดเก็บข้อมูลของคุณหรือไม่

ข้อดีข้อเสียระหว่างประสิทธิภาพการแทรก ขนาดดัชนี และคุณลักษณะการสืบค้น จำเป็นต้องมีการตัดสินใจทางสถาปัตยกรรมตามรูปแบบปริมาณงาน สามารถแทรกคีย์สตริงตามลำดับได้อย่างรวดเร็วหากสตริงเพิ่มขึ้น เช่น สตริงที่อิงการประทับเวลา แต่จะใช้พื้นที่เดียวกันกับ UUID แบบสุ่มและข้อมูลชั่วคราวรั่วไหล UUID แบบสุ่มนั้นสะอาดกว่าทางความหมายและไม่มีองค์ประกอบการประทับเวลาที่จะรั่วไหล แต่จะช้ากว่าในการแทรกลงในดัชนีแบบคลัสเตอร์และพื้นที่เก็บข้อมูลโดยรวมมีขนาดใหญ่กว่า ทางเลือกอื่นที่เรียงลำดับเวลา เช่น UUIDv7 ผสมผสานข้อดีต่างๆ เข้าด้วยกันโดยรักษาตำแหน่งการแทรกในขณะเดียวกันก็หลีกเลี่ยงการรั่วไหลของการประทับเวลาในเวอร์ชัน 4 ตัวระบุแบบสุ่ม