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

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



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

هذا هو المكان الذي يأتي التقسيم إلى الإنقاذ.

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

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

مفهوم


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

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

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

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

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

خطوة بخطوة


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

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


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

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


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

المواضيع


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


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

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

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

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

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



نظرًا لأنه سيكون هناك القليل من التعديلات على قائمة تواريخ الرسائل لكل مراسلات فردية (بعد كل ذلك ، تقريبًا كل الرسائل تقع في غضون 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 ); 


حفظ فلسا واحدا جميلة


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

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

Source: https://habr.com/ru/post/ar483170/


All Articles