قاعدة بيانات Messenger (الجزء 2): تقسيم "من أجل الربح"

لقد نجحنا في تصميم بنية قاعدة بيانات PostgreSQL الخاصة بنا لتخزين المراسلات ، وقد مر عام ، ويعمل المستخدمون بنشاط على ملئه ، والآن ملايين السجلاتو ... بدأ شيء ما في إبطاء كل شيء.

قاعدة بيانات Messenger (الجزء 2): تقسيم "من أجل الربح"
الحقيقة هي أن مع نمو حجم الجدول ، ينمو "عمق" الفهارس أيضًا - وإن كان لوغاريتميا. ولكن بمرور الوقت يجبر الخادم على القيام بنفس مهام القراءة / الكتابة معالجة صفحات البيانات عدة مراتمما كانت عليه في البداية.

هذا هو المكان الذي يتعلق الأمر بالإنقاذ التقسيم.

ألاحظ أن الأمر لا يتعلق بالتجزئة ، أي توزيع البيانات بين قواعد البيانات أو الخوادم المختلفة. لأنه حتى تقسيم البيانات على بعض لن تتخلص من مشكلة فهارس "الانتفاخ" بمرور الوقت. من الواضح أنه إذا كنت تستطيع تشغيل خادم جديد كل يوم ، فلن تكمن مشاكلك بعد الآن في مستوى قاعدة بيانات معينة.

لن نأخذ في الاعتبار نصوصًا محددة لتنفيذ التجزئة "في الأجهزة" ، ولكننا سننظر في النهج نفسه - ماذا وكيف يجب "تقطيعه إلى شرائح" ، وما الذي تؤدي إليه هذه الرغبة.

مفهوم

مرة أخرى ، نحدد هدفنا: نريد التأكد من أن كمية البيانات التي تقرأها PostgreSQL لأي عملية قراءة / كتابة تظل كما هي تقريبًا اليوم وغدًا وبعد عام.

لأي البيانات المتراكمة زمنيا (الرسائل والمستندات والسجلات والمحفوظات ...) الخيار الطبيعي لمفتاح القسم هو تاريخ / وقت الحدث. في حالتنا ، هذا الحدث لحظة إرسال الرسالة.

لاحظ أن المستخدمين دائمًا تقريبًا تعمل فقط مع الأحدث مثل هذه البيانات - يقرؤون أحدث الرسائل ، ويحللون أحدث السجلات ، ... لا ، بالطبع ، يمكنهم التمرير مرة أخرى في الوقت المناسب ، إلا أنهم نادرًا ما يفعلون ذلك.

من هذه القيود ، يصبح من الواضح أن الحل الأمثل للرسائل سيكون أقسام "يومية" - بعد كل شيء ، سيقرأ مستخدمنا دائمًا ما جاء إليه "اليوم" أو "أمس".

إذا كتبنا وقرأنا عمليًا في قسم واحد فقط خلال اليوم ، فهذا يعطينا أيضًا استخدام الذاكرة والقرص بشكل أكثر كفاءة - نظرًا لأن جميع فهارس الأقسام تتلاءم بسهولة مع ذاكرة الوصول العشوائي ، على عكس "الكبيرة والدسمة" الموجودة في جميع أنحاء الجدول.

خطوة بخطوة

بشكل عام ، كل ما سبق يبدو وكأنه ربح واحد كبير. وهو قابل للتحقيق ، لكن من أجل هذا علينا أن نعمل بجد - لأنه قرار تقسيم أحد الكيانات يؤدي إلى الحاجة إلى "رأى" وما يرتبط بها.

الرسالة وخصائصها وتوقعاتها

نظرًا لأننا قررنا قطع الرسائل حسب التواريخ ، فمن المعقول أيضًا تقسيم خصائص الكيانات التي تعتمد عليها (الملفات المرفقة ، قائمة المستلمين) ، و أيضا حسب تاريخ آخر.

نظرًا لأن إحدى مهامنا النموذجية هي مجرد عرض سجلات الرسائل (غير مقروءة ، واردة ، وكلها) ، فمن المنطقي أيضًا "رسمها" في التقسيم حسب تواريخ الرسائل.

قاعدة بيانات Messenger (الجزء 2): تقسيم "من أجل الربح"

نضيف مفتاح القسم (تاريخ الرسالة) إلى جميع الجداول: المستلمون والملف والسجلات. لا يمكنك الإضافة إلى الرسالة نفسها ، ولكن يمكنك استخدام DateTime الموجود.

المواضيع

نظرًا لأن الموضوع واحد لعدة رسائل ، فلن يكون من الممكن "قصه" في نفس النموذج ، فمن الضروري الاعتماد على شيء آخر. مثالي لحالتنا. تاريخ أول رسالة في المراسلات - هذه هي ، في الواقع ، لحظة إنشاء الموضوع.

قاعدة بيانات Messenger (الجزء 2): تقسيم "من أجل الربح"

أضف مفتاح قسم (تاريخ الموضوع) إلى جميع الجداول: موضوع ، عضو.

لكن الآن لدينا مشكلتان في آن واحد:

  • في أي قسم للبحث عن رسائل حول الموضوع؟
  • في أي قسم للبحث عن موضوع الرسالة؟

يمكنك بالطبع الاستمرار في البحث في جميع الأقسام ، لكن الأمر سيكون محزنًا للغاية ، وسوف يلغي كل مكاسبنا. لذلك ، من أجل معرفة المكان الذي يجب البحث فيه بالضبط ، سنقوم بإنشاء روابط / مؤشرات منطقية للأقسام:

  • أضف إلى الرسالة موضوع تاريخ المجال
  • أضف إلى الموضوع تعيين تاريخ الرسالة هذه المراسلات (يمكنك استخدام جدول منفصل ، أو يمكنك استخدام مجموعة من التواريخ)

قاعدة بيانات Messenger (الجزء 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
);

احفظ فلسا واحدا

حسنًا ، ماذا لو استخدمنا التقسيم الكلاسيكي. استنادًا إلى توزيع قيم الحقول (من خلال المشغلات والوراثة أو PARTITION BY) ، ولكن "يدويًا" على مستوى التطبيق ، يمكنك أن ترى أن قيمة مفتاح التقسيم مخزنة بالفعل في اسم الجدول نفسه.

لذلك إذا كنت كذلك قلقون للغاية بشأن كمية البيانات المخزنة، يمكنك بعد ذلك التخلص من هذه الحقول "الإضافية" والعناوين الخاصة بجداول معينة. صحيح ، يجب نقل جميع التحديدات من عدة أقسام في هذه الحالة بالفعل إلى جانب التطبيق.

المصدر: www.habr.com

إضافة تعليق