การออกแบบฐานข้อมูลสำหรับการจัดการ 1 พันล้านแถวและการนับ


10

เราได้รับข้อมูล GPS แบบเรียลไทม์ในอัตราประมาณ 5,000 ราคา นาที (จากเซิร์ฟเวอร์ TCP 4 แห่ง) แต่ละเซิร์ฟเวอร์ใช้การเชื่อมต่อเดียวเพื่อแทรกข้อมูลและบัฟเฟอร์ข้อมูลระหว่างแทรก ทุกๆ 15 นาทีหรือมากกว่านั้นบริการจะดึงข้อมูลนี้และประมวลผลไปยังการเดินทาง เมื่อสร้างการเดินทางแล้วข้อมูล GPS ที่แท้จริงมักไม่สำคัญนักหากผู้ใช้ต้องการเห็นเส้นทางบนแผนที่

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

ฉันหวังว่าจะได้รับความคิดเห็นเกี่ยวกับการออกแบบในปัจจุบันและความคิดบางอย่างที่เราต้องปรับปรุงประสิทธิภาพและคำตอบสำหรับคำถามของเรา - และเคล็ดลับอื่น ๆ ที่ผู้คนอาจมี!

การออกแบบในปัจจุบัน

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

ออกแบบโต๊ะ

  • รหัส (PK, ตัวระบุที่ไม่ซ้ำ)
  • DeviceId (FK, int)
  • PersonId (FK, int)
  • รหัสยานพาหนะ (FK, int)
  • TokenId (FK, int)
  • UtcTime (PK, datetime2 (3))
  • ละติจูด (ลอย)
  • ลองจิจูด (float)
  • ความเร็ว (พิมพ์เล็ก)
  • หัวเรื่อง (smallint)
  • ดาวเทียม (Tinyint)
  • IOData (varbinary (100))
  • IgnitionState (Tinyint)
  • UserInput (Tinyint)
  • CreateTimeUtc (datetime2 (3))

ดัชนี

  • DeviceId_CreateTimeUtc_Desc
  • DeviceId_UtcTime_Desc (ทำคลัสเตอร์)
  • PersonId_UtcTime_Desc
  • TokenId_UtcTime_Desc
  • VehicleId_UtcTime_Desc

ทุกสัปดาห์ปัจจุบันใช้เวลาประมาณ 10 GB รวมถึงดัชนีและปัจจุบันมีข้อมูลประมาณ 300 GB ในฐานข้อมูลหลัก

ตารางข้อมูลในฐานข้อมูลหลักมีกลุ่มไฟล์ของตนเองที่มี 1 ไฟล์ แต่อยู่ในดิสก์เดียวกันกับตารางอื่นทั้งหมดในฐานข้อมูลหลัก ฐานข้อมูลรองอยู่บนดิสก์อื่น แต่อยู่ในเครื่องเดียวกัน

ฉันคิดว่าเรากำลังใช้งานการสร้างดัชนีใหม่ทุกสัปดาห์เมื่อมีการใช้พาร์ติชันตารางใหม่ (สัปดาห์) ไม่มีการหดตัว

เครื่องนี้เป็น HP 8 คอร์ที่มีหน่วยความจำ 12 GB และดิสก์ที่เก็บฐานข้อมูลหลักกำลังเรียกใช้ RAID 10

ไอเดีย

  • จำกัด จำนวนข้อมูลที่เก็บไว้ในฐานข้อมูลหลักเช่นสูงสุด 1 เดือน อย่างน้อยที่สุดมันจะทำให้ฐานข้อมูลสามารถจัดการได้มากขึ้นสำหรับการสำรอง / กู้คืน แต่เราคาดหวังว่าจะเห็นการปรับปรุงประสิทธิภาพด้วยการทำเช่นนี้?
  • สร้าง 2 ไฟล์ในกลุ่มไฟล์สำหรับข้อมูลปัจจุบันและแจกจ่ายไปยังฟิสิคัลพาร์ติชันที่ต่างกัน 2 ตัว
  • สร้างฐานข้อมูล master-slave ที่เก็บข้อมูลปัจจุบันดังนั้นการแทรกและอ่านจะดำเนินการกับฐานข้อมูลที่แตกต่างกัน
  • วางไฟล์สำหรับข้อมูลปัจจุบันบนดิสก์ SSD (การทำมิรเรอร์จะทำให้ประสิทธิภาพของดิสก์ SSD แตกต่างกันหรือไม่)

โปรดแจ้งให้เราทราบหากต้องการข้อมูลเพิ่มเติม มีหลายปัจจัยที่มีอิทธิพลต่อการทำงานอย่างน่ากลัวและอาจมีหลายวิธีในการปรับแต่ง


ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
พอลไวท์ 9

คำตอบ:


8

5,000 เม็ดต่อนาทีมีประมาณ 83 เม็ดต่อวินาที ด้วย 5 ดัชนีที่แทรก 400 ฟิสิคัลแถวต่อวินาที หากปริมาณงานอยู่ในหน่วยความจำจะไม่เกิดปัญหาแม้แต่กับเซิร์ฟเวอร์ที่มีขนาดเล็กที่สุด แม้ว่านี่จะเป็นการแทรกแบบทีละแถวโดยใช้วิธีที่ไม่มีประสิทธิภาพที่สุดที่ฉันคิดได้ การค้นหา 83 คำต่อวินาทีนั้นไม่น่าสนใจจากมุมมองของ CPU

อาจเป็นเพราะคุณผูกกับดิสก์ STATISTICS IOคุณสามารถตรวจสอบได้โดยดูที่สถิติการรอคอยหรือ

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

ลองนึกภาพตารางที่คุณใส่ตอนท้ายเท่านั้นเพราะกุญแจที่เพิ่มขึ้นเรื่อย ๆ ชุดการทำงานจะเป็นหนึ่งหน้า: หน้าสุดท้าย สิ่งนี้จะสร้าง IO ตามลำดับเช่นกันเมื่อผู้เขียนขี้เกียจหรือกระบวนการตรวจสอบเขียน "end" ของตารางลงในดิสก์

ลองนึกภาพตารางที่มีส่วนแทรกแบบสุ่ม (ตัวอย่างคลาสสิก: คีย์ guid) ที่นี่ทุกหน้าเป็นชุดการทำงานเนื่องจากหน้าแบบสุ่มจะถูกสัมผัสสำหรับการแทรกแต่ละครั้ง IOs เป็นแบบสุ่ม นี่เป็นกรณีที่เลวร้ายที่สุดเมื่อมันมาถึงชุดทำงาน

คุณอยู่ตรงกลาง (SomeValue, SequentialDateTime)ดัชนีของคุณเป็นของโครงสร้าง องค์ประกอบแรกสุ่มบางส่วนเรียงตามลำดับที่ได้รับจากที่สอง ฉันเดาว่ามีค่าที่เป็นไปได้ค่อนข้างน้อยสำหรับ " SomeValue" เพื่อให้คุณมีจุดแทรกที่วางแบบสุ่มจำนวนมากในดัชนีของคุณ

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

หากคุณสามารถลดขนาดของ "พาร์ติชัน" รายสัปดาห์หรือเพิ่มหน่วยความจำเซิร์ฟเวอร์โดยบิตคุณอาจจะปรับ

ฉันคาดหวังว่าส่วนแทรกของต้นสัปดาห์จะเร็วขึ้นในตอนท้าย คุณสามารถทดสอบทฤษฎีนี้บนเซิร์ฟเวอร์ dev โดยใช้การวัดประสิทธิภาพด้วยขนาดข้อมูลที่แน่นอนและค่อยๆลดหน่วยความจำเซิร์ฟเวอร์จนกว่าคุณจะเห็นถังประสิทธิภาพ

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

ในฐานะที่เป็นวิธีแก้ปัญหาอย่างรวดเร็วฉันจะเพิ่มเลเยอร์บัฟเฟอร์ระหว่างไคลเอนต์และตารางหลัก อาจสะสม 15 นาทีของการเขียนลงในตารางการแสดงละครและล้างมันเป็นระยะ สิ่งนี้จะช่วยลดภาระการโหลดและใช้แผนการที่มีประสิทธิภาพมากกว่าในการเขียนลงในตารางขนาดใหญ่


1
@usr ขอบคุณสำหรับคำตอบที่ครอบคลุมและอธิบายได้ดีมาก! เราได้พูดคุยเกี่ยวกับการเพิ่มหน่วยความจำเซิร์ฟเวอร์จริงโดยไม่ทราบว่าจะมีผลกระทบมากน้อยเพียงใด แต่ตอนนี้เรามีเหตุผลที่น่าสนใจอย่างยิ่งที่จะทำเช่นนั้น :) คุณพูดถูกว่า "SomeValue" สุ่มจุดแทรกบางส่วน ประมาณ 10,000 รหัสอุปกรณ์ ข้อเสนอแนะของคุณคือตารางที่ไม่มีดัชนีหรือไม่และจากนั้นงานที่จะแทรกลงในตารางหลักทุก ๆ X นาที?
sondergard

@usr Reg. ข้อเสนอแนะของคุณสำหรับการแปลงดัชนีคลัสเตอร์เป็นลำดับเราสามารถเพิ่ม auto-inc คอลัมน์เอกลักษณ์ (จำนวนเต็ม) และเปลี่ยนดัชนีคลัสเตอร์เป็นคอลัมน์นี้เพื่อจุดประสงค์เดียวในการรักษาลำดับ มันจะไม่ซ้ำกันในตาราง แต่ตราบใดที่คีย์หลักคือเราควรจะดี
sondergard

1
หากตารางการแสดงละครมีขนาดเล็กและแบบสอบถามของคุณสามารถอยู่กับมันได้คุณไม่จำเป็นต้องจัดทำดัชนีเลย แต่คุณทำได้; กลยุทธ์หนึ่งคือการสร้าง CI ในคอลัมน์ข้อมูลประจำตัว (ดังที่คุณพูด) สิ่งนี้สามารถทำงานได้อย่างน่าอัศจรรย์ถ้า CI มีขนาดใหญ่และดัชนีอื่น ๆ มีขนาดเล็ก เนื่องจาก CI กำลังเขียนอยู่ในขณะนี้เรียงลำดับพวกเขามีส่วนร่วมน้อยกว่าปัญหาของคุณ กลยุทธ์นี้ประสบความสำเร็จมากที่สุดหากมีความแตกต่างของขนาดที่มีความหมาย; ความคิดอื่นจะมีหนึ่งตารางต่อวัน อาจรวมเป็นรายเดือน
usr

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

2
อย่างไรก็ตามสำหรับทุกคนที่ประสบปัญหาเดียวกันอย่างจริงจังหากคุณมีจำนวนมากของการเขียนและมีเพียงไม่กี่คนที่อ่านคุณต้องการผนวกท้ายและการทำดัชนีล่าช้า ในทางตรงกันข้ามถ้าคุณต้องการอ่านอย่างรวดเร็วและไม่สนใจว่าจะใช้เวลานานแค่ไหนในการแทรกคุณต้องมีดัชนีคลัสเตอร์
tiktak
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.