ฐานข้อมูล Messenger (ตอนที่ 2): การแบ่งพาร์ติชัน "เพื่อหากำไร"

เราประสบความสำเร็จในการออกแบบโครงสร้างของฐานข้อมูล PostgreSQL สำหรับจัดเก็บจดหมายโต้ตอบ หนึ่งปีผ่านไป ผู้ใช้กำลังกรอกข้อมูลอยู่ และตอนนี้ก็มี บันทึกนับล้านและ... มีบางอย่างเริ่มช้าลง

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

นี่คือที่มาของการช่วยเหลือ การแบ่งส่วน.

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

เราจะพิจารณาไม่ใช่สคริปต์เฉพาะสำหรับการใช้การแบ่งพาร์ติชัน "ในฮาร์ดแวร์" แต่เป็นแนวทางของตัวเอง - อะไรและอย่างไรควร "ตัดเป็นชิ้น ๆ" และความปรารถนาดังกล่าวนำไปสู่อะไร

แนวคิด

มากำหนดเป้าหมายของเราอีกครั้ง: เราต้องการให้แน่ใจว่าวันนี้ พรุ่งนี้ และในหนึ่งปี ปริมาณข้อมูลที่ PostgreSQL อ่านระหว่างการดำเนินการอ่าน/เขียนจะยังคงเท่าเดิมโดยประมาณ

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

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

จากข้อจำกัดเหล่านี้ เห็นได้ชัดว่าโซลูชันข้อความที่ดีที่สุดคือ ส่วน "รายวัน" - ท้ายที่สุดแล้วผู้ใช้ของเรามักจะอ่านสิ่งที่มาหาเขา "วันนี้" หรือ "เมื่อวาน"

ถ้าเราเขียนและอ่านเพียงส่วนเดียวในระหว่างวัน สิ่งนี้ก็จะทำให้เราเช่นกัน การใช้หน่วยความจำและดิสก์มีประสิทธิภาพมากขึ้น - เนื่องจากดัชนีส่วนทั้งหมดพอดีกับ RAM ได้อย่างง่ายดาย ตรงกันข้ามกับดัชนี "ใหญ่และอ้วน" ทั่วทั้งโต๊ะ

เป็นขั้นเป็นตอน

โดยทั่วไปแล้ว ทุกอย่างที่กล่าวมาข้างต้นดูเหมือนเป็นผลกำไรอย่างต่อเนื่อง และสามารถทำได้ แต่สำหรับสิ่งนี้ เราจะต้องพยายามอย่างหนัก - เพราะว่า การตัดสินใจแบ่งเอนทิตีหนึ่งทำให้จำเป็นต้อง "เห็น" สิ่งที่เกี่ยวข้อง.

ข้อความ คุณสมบัติ และการคาดการณ์

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

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

ฐานข้อมูล Messenger (ตอนที่ 2): การแบ่งพาร์ติชัน "เพื่อหากำไร"

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

หัวข้อ

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

ฐานข้อมูล Messenger (ตอนที่ 2): การแบ่งพาร์ติชัน "เพื่อหากำไร"

เพิ่มคีย์การแบ่งพาร์ติชัน (วันที่ของหัวข้อ) ให้กับตารางทั้งหมด: หัวข้อ, ผู้เข้าร่วม

แต่ตอนนี้เรามีปัญหาสองประการพร้อมกัน:

  • ฉันควรค้นหาข้อความในหัวข้อใด
  • ฉันควรค้นหาหัวข้อจากข้อความในส่วนใด

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

  • เราจะเพิ่มในข้อความ ช่องวันที่ของหัวข้อ
  • มาเพิ่มในหัวข้อกัน ตั้งวันที่ข้อความ จดหมายโต้ตอบนี้ (อาจเป็นตารางแยกหรืออาร์เรย์วันที่)

ฐานข้อมูล Messenger (ตอนที่ 2): การแบ่งพาร์ติชัน "เพื่อหากำไร"

เนื่องจากจะมีการแก้ไขรายการวันที่ของข้อความเล็กน้อยสำหรับการติดต่อแต่ละครั้ง (ท้ายที่สุดแล้วข้อความเกือบทั้งหมดจะตกใน 1-2 วันติดกัน) ฉันจะเน้นที่ตัวเลือกนี้

โดยรวมแล้ว โครงสร้างของฐานข้อมูลของเราอยู่ในรูปแบบต่อไปนี้ โดยคำนึงถึงการแบ่งพาร์ติชัน:

ตาราง: RU หากคุณเกลียดอักษรซีริลลิกในชื่อตาราง/ฟิลด์ จะเป็นการดีกว่าที่จะไม่ดู

-- секции по дате сообщения
CREATE TABLE "Сообщение_YYYYMMDD"(
  "Сообщение"
    uuid
      PRIMARY KEY
, "Тема"
    uuid
, "ДатаТемы"
    date
, "Автор"
    uuid
, "ДатаВремя" -- используем как дату
    timestamp
, "Текст"
    text
);

CREATE TABLE "Адресат_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Сообщение"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Сообщение", "Персона")
);

CREATE TABLE "Файл_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Файл"
    uuid
      PRIMARY KEY
, "Сообщение"
    uuid
, "BLOB"
    uuid
, "Имя"
    text
);

CREATE TABLE "РеестрСообщений_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Владелец"
    uuid
, "ТипРеестра"
    smallint
, "ДатаВремя"
    timestamp
, "Сообщение"
    uuid
, PRIMARY KEY("Владелец", "ТипРеестра", "Сообщение")
);
CREATE INDEX ON "РеестрСообщений_YYYYMMDD"("Владелец", "ТипРеестра", "ДатаВремя" DESC);

-- секции по дате темы
CREATE TABLE "Тема_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Документ"
    uuid
, "Название"
    text
);

CREATE TABLE "УчастникТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Тема", "Персона")
);

CREATE TABLE "ДатыСообщенийТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Дата"
    date
);

ประหยัดเงินไปได้สวยเลย

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

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

ที่มา: will.com

เพิ่มความคิดเห็น