مميزات تصميم نموذج بيانات لـ NoSQL

مقدمة

مميزات تصميم نموذج بيانات لـ NoSQL "عليك أن تجري بأسرع ما يمكن فقط لتبقى في مكانك،
وللوصول إلى مكان ما، عليك أن تجري بسرعة مضاعفة على الأقل!
(ج) أليس في بلاد العجائب

منذ فترة طُلب مني إلقاء محاضرة المحللين شركتنا في موضوع تصميم نماذج البيانات، لأن الجلوس في المشاريع لفترة طويلة (أحيانًا لعدة سنوات) يغيب عن بالنا ما يحدث حولنا في عالم تقنيات تكنولوجيا المعلومات. في شركتنا (يحدث ذلك فقط) لا تستخدم العديد من المشاريع قواعد بيانات NoSQL (على الأقل في الوقت الحالي)، لذلك في محاضرتي، أوليت بعض الاهتمام لها بشكل منفصل باستخدام مثال HBase وحاولت توجيه عرض المواد إلى هؤلاء الذين لم يستخدموها قط عملوا. وعلى وجه الخصوص، قمت بتوضيح بعض ميزات تصميم نموذج البيانات باستخدام مثال قرأته منذ عدة سنوات في مقال "مقدمة لتصميم مخطط HB ase" بقلم أمانديب كورانا. عند تحليل الأمثلة، قارنت عدة خيارات لحل نفس المشكلة من أجل نقل الأفكار الرئيسية بشكل أفضل إلى الجمهور.

في الآونة الأخيرة، "من لا شيء أفعله"، سألت نفسي هذا السؤال (عطلة نهاية الأسبوع الطويلة في شهر مايو في الحجر الصحي تساعد بشكل خاص على ذلك)، إلى أي مدى ستتوافق الحسابات النظرية مع الممارسة؟ في الواقع، هكذا ولدت فكرة هذا المقال. قد لا يتعلم المطور الذي يعمل مع NoSQL لعدة أيام أي شيء جديد منه (وبالتالي قد يتخطى نصف المقالة على الفور). ولكن ل محللينبالنسبة لأولئك الذين لم يعملوا بشكل وثيق مع NoSQL بعد، أعتقد أنه سيكون مفيدًا لاكتساب فهم أساسي لميزات تصميم نماذج البيانات لـ HBase.

تحليل المثال

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

لنفكر في المشكلة "الاصطناعية" التالية، والتي سنواصل العمل معها:

من الضروري تصميم بنية تخزين لقائمة أصدقاء مستخدمي بعض الشبكات الاجتماعية المجردة. للتبسيط، سنفترض أن جميع اتصالاتنا موجهة (كما هو الحال في Instagram، وليس Linkedin). يجب أن يسمح لك الهيكل بما يلي بشكل فعال:

  • أجب عن سؤال ما إذا كان المستخدم "أ" يقرأ المستخدم "ب" (نمط القراءة)
  • السماح بإضافة/إزالة الاتصالات في حالة اشتراك/إلغاء اشتراك المستخدم أ من المستخدم ب (قالب تغيير البيانات)

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

USER_ID
friends_id

فازيا
بيتيا

فازيا
Оля

فيما يلي، من أجل الوضوح والفهم الأفضل، سأشير إلى الأسماء بدلاً من الهويات

في حالة HBase، نحن نعلم أن:

  • من الممكن البحث الفعال الذي لا يؤدي إلى مسح كامل للجدول حصرا عن طريق المفتاح
    • في الواقع، هذا هو السبب في أن كتابة استعلامات SQL المألوفة للكثيرين في قواعد البيانات هذه فكرة سيئة؛ من الناحية الفنية، بالطبع، يمكنك إرسال استعلام SQL مع عمليات الانضمام والمنطق الآخر إلى HBase من نفس Impala، ولكن ما مدى فعاليته...

لذلك، نحن مضطرون لاستخدام معرف المستخدم كمفتاح. وأول ما فكرت به في موضوع "أين وكيف يتم تخزين معرفات الأصدقاء؟" ربما فكرة لتخزينها في الأعمدة. سيبدو هذا الخيار الأكثر وضوحًا و"سذاجة" على هذا النحو (دعنا نسميه الخيار 1 (الافتراضي)لمزيد من المرجع):

مفتاح الصف
مكبرات الصوت

فازيا
1: بيتيا
2: عليا
3: داشا

بيتيا
1: ماشا
2: فاسيا

هنا، كل سطر يتوافق مع مستخدم شبكة واحد. تحتوي الأعمدة على أسماء: 1، 2، ... - حسب عدد الأصدقاء، ويتم تخزين معرفات الأصدقاء في الأعمدة. من المهم ملاحظة أن كل صف سيحتوي على عدد مختلف من الأعمدة. في المثال الموجود في الشكل أعلاه، يحتوي صف واحد على ثلاثة أعمدة (1 و2 و3)، والثاني يحتوي على عمودين فقط (1 و2) - هنا استخدمنا بأنفسنا خاصيتين HBase لا تمتلكهما قواعد البيانات العلائقية:

  • القدرة على تغيير تكوين الأعمدة ديناميكيًا (إضافة صديق -> إضافة عمود، إزالة صديق -> حذف عمود)
  • قد تحتوي الصفوف المختلفة على تركيبات أعمدة مختلفة

دعونا نتحقق من هيكلنا للتأكد من امتثاله لمتطلبات المهمة:

  • قراءة البيانات: لكي نفهم ما إذا كانت Vasya مشتركة في Olya، سنحتاج إلى الطرح الخط بأكمله بواسطة المفتاح RowKey = "Vasya" وقم بفرز قيم الأعمدة حتى "نلتقي" بأوليا فيها. أو قم بالتكرار من خلال قيم جميع الأعمدة، "لا تفي" عليا وإرجاع الإجابة خطأ؛
  • تحرير البيانات: إضافة صديق: لمهمة مماثلة نحتاج أيضًا إلى الطرح الخط بأكمله باستخدام المفتاح RowKey = "Vasya" لحساب العدد الإجمالي لأصدقائه. نحتاج إلى هذا العدد الإجمالي للأصدقاء لتحديد رقم العمود الذي نحتاج إلى كتابة معرف الصديق الجديد فيه.
  • تغيير البيانات: حذف صديق:
    • بحاجة إلى طرح الخط بأكمله بواسطة المفتاح RowKey = "Vasya" وقم بالفرز عبر الأعمدة للعثور على العمود الذي تم تسجيل الصديق الذي سيتم حذفه فيه؛
    • بعد ذلك، بعد حذف صديق، نحتاج إلى "تحويل" جميع البيانات إلى عمود واحد حتى لا نحصل على "فجوات" في ترقيمها.

دعونا الآن نقيم مدى إنتاجية هذه الخوارزميات، والتي سنحتاج إلى تنفيذها على جانب "التطبيق المشروط"، باستخدام يا رمزية. دعنا نشير إلى حجم شبكتنا الاجتماعية الافتراضية بالرمز n. إذن الحد الأقصى لعدد الأصدقاء الذي يمكن أن يمتلكه مستخدم واحد هو (n-1). يمكننا أيضًا إهمال هذا (-1) لأغراضنا، لأنه في إطار استخدام رموز O، فهو غير مهم.

  • قراءة البيانات: من الضروري طرح السطر بأكمله والتكرار عبر جميع أعمدته في الحد. وهذا يعني أن التقدير الأعلى للتكاليف سيكون تقريبًا O(n)
  • تحرير البيانات: إضافة صديق: لتحديد عدد الأصدقاء، تحتاج إلى التكرار عبر جميع أعمدة الصف، ثم إدراج عمود جديد => O(n)
  • تغيير البيانات: حذف صديق:
    • يشبه الإضافة - تحتاج إلى الاطلاع على جميع الأعمدة في الحد => O(n)
    • بعد إزالة الأعمدة، نحتاج إلى "نقلها". إذا قمت بتنفيذ هذا "المباشر"، فستحتاج في الحد الأقصى إلى ما يصل إلى (n-1) من العمليات. ولكن هنا، وفي الجزء العملي، سنستخدم نهجًا مختلفًا، والذي سينفذ "التحول الزائف" لعدد محدد من العمليات - أي أنه سيتم إنفاق وقت ثابت عليها، بغض النظر عن n. يمكن إهمال هذا الوقت الثابت (O(2) على وجه الدقة) مقارنةً بـ O(n). الطريقة موضحة في الشكل أدناه: نقوم ببساطة بنسخ البيانات من العمود "الأخير" إلى العمود الذي نريد حذف البيانات منه، ثم نحذف العمود الأخير:
      مميزات تصميم نموذج بيانات لـ NoSQL

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

مفتاح الصف
مكبرات الصوت

فازيا
1: بيتيا
2: عليا
3: داشا
العد: 3

بيتيا
1: ماشا
2: فاسيا

العد: 2

مقارنة بالخيار الأول:

  • قراءة البيانات: للحصول على إجابة على السؤال "هل يقرأ فاسيا أوليا؟" لم يتغير شيء => O(n)
  • تحرير البيانات: إضافة صديق: لقد قمنا بتبسيط عملية إدراج صديق جديد، لأننا الآن لا نحتاج إلى قراءة السطر بأكمله والتكرار على أعمدته، ولكن يمكننا فقط الحصول على قيمة عمود "العدد"، وما إلى ذلك. حدد على الفور رقم العمود لإدراج صديق جديد. وهذا يؤدي إلى تقليل التعقيد الحسابي إلى O(1)
  • تغيير البيانات: حذف صديق: عند حذف صديق، يمكننا أيضًا استخدام هذا العمود لتقليل عدد عمليات الإدخال/الإخراج عند "تحريك" البيانات خلية واحدة إلى اليسار. لكن الحاجة إلى التكرار عبر الأعمدة للعثور على العمود الذي يجب حذفه لا تزال قائمة، لذلك => ​​O(n)
  • من ناحية أخرى، الآن عند تحديث البيانات نحتاج إلى تحديث عمود “العدد” في كل مرة، ولكن هذا يستغرق وقتا ثابتا، وهو ما يمكن إهماله في إطار رموز O

بشكل عام، يبدو الخيار الثاني أكثر مثالية، لكنه أشبه بـ "التطور بدلاً من الثورة". سنحتاج إلى القيام "بثورة". الخيار 3 (عمود).
دعونا نقلب كل شيء "رأسًا على عقب": سنعينه معرف مستخدم اسم العمود! ما سيتم كتابته في العمود نفسه لم يعد مهمًا بالنسبة لنا، فليكن الرقم 1 (بشكل عام، يمكن تخزين الأشياء المفيدة هناك، على سبيل المثال، مجموعة "العائلة/الأصدقاء/إلخ"). قد يفاجئ هذا النهج "الشخص العادي" غير المستعد الذي ليس لديه خبرة سابقة في العمل مع قواعد بيانات NoSQL، ولكن هذا النهج بالتحديد هو الذي يسمح لك باستخدام إمكانات HBase في هذه المهمة بشكل أكثر فعالية:

مفتاح الصف
مكبرات الصوت

فازيا
بيتيا: 1
عليا: 1
داشا: 1

بيتيا
ماشا: 1
فاسيا: 1

هنا نحصل على العديد من المزايا في وقت واحد. لفهمها، دعونا نحلل البنية الجديدة ونقدر التعقيد الحسابي:

  • قراءة البيانات: للإجابة على سؤال ما إذا كان Vasya مشتركًا في Olya، يكفي قراءة عمود واحد "Olya": إذا كان موجودًا، فالإجابة صحيحة، وإذا لم يكن كذلك - False => O(1)
  • تحرير البيانات: إضافة صديق: إضافة صديق: فقط قم بإضافة عمود جديد "معرف الصديق" => O(1)
  • تغيير البيانات: حذف صديق: فقط قم بإزالة عمود معرف الصديق => O(1)

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

قد تشعر بالحيرة وتذهب أبعد قليلاً في طريق تحسين الأداء وتقليل عمليات الإدخال / الإخراج عند الوصول إلى قاعدة البيانات. ماذا لو قمنا بتخزين معلومات العلاقة الكاملة مباشرةً في مفتاح الصف نفسه؟ أي جعل المفتاح المركب مثل userID.friendID؟ في هذه الحالة، ليس علينا حتى قراءة أعمدة السطر على الإطلاق (الخيار 4 (الصف)):

مفتاح الصف
مكبرات الصوت

فاسيا بيتيا
بيتيا: 1

فاسيا.عليا
عليا: 1

فاسيا داشا
داشا: 1

بيتيا.ماشا
ماشا: 1

بيتيا.فاسيا
فاسيا: 1

من الواضح أن تقييم جميع سيناريوهات معالجة البيانات في مثل هذا الهيكل، كما في الإصدار السابق، سيكون O(1). سيكون الاختلاف مع الخيار 3 فقط في كفاءة عمليات الإدخال/الإخراج في قاعدة البيانات.

حسنًا ، "القوس" الأخير. من السهل أن نرى أنه في الخيار 4، سيكون لمفتاح الصف طول متغير، مما قد يؤثر على الأداء (هنا نتذكر أن HBase يخزن البيانات كمجموعة من البايتات ويتم فرز الصفوف في الجداول حسب المفتاح). بالإضافة إلى أن لدينا فاصلًا قد يلزم التعامل معه في بعض السيناريوهات. للتخلص من هذا التأثير، يمكنك استخدام التجزئات من معرف المستخدم ومعرف الصديق، وبما أن كلا التجزئتين سيكون لهما طول ثابت، يمكنك ببساطة تسلسلهما، بدون فاصل. ثم ستبدو البيانات في الجدول بهذا الشكل (الخيار 5 (التجزئة)):

مفتاح الصف
مكبرات الصوت

dc084ef00e94aef49be885f9b01f51c01918fa783851db0dc1f72f83d33a5994
بيتيا: 1

dc084ef00e94aef49be885f9b01f51c0f06b7714b5ba522c3cf51328b66fe28a
عليا: 1

dc084ef00e94aef49be885f9b01f51c00d2c2e5d69df6b238754f650d56c896a
داشا: 1

1918fa783851db0dc1f72f83d33a59949ee3309645bd2c0775899fca14f311e1
ماشا: 1

1918fa783851db0dc1f72f83d33a5994dc084ef00e94aef49be885f9b01f51c0
فاسيا: 1

من الواضح أن التعقيد الخوارزمي للعمل مع مثل هذا الهيكل في السيناريوهات التي ندرسها سيكون هو نفس تعقيد الخيار 4 - أي O(1).
في المجمل، دعونا نلخص جميع تقديراتنا للتعقيد الحسابي في جدول واحد:

إضافة صديق
التحقق من صديق
إزالة صديق

الخيار 1 (الافتراضي)
O (ن)
O (ن)
O (ن)

الخيار 2 (العدد)
يا (1)
O (ن)
O (ن)

الخيار 3 (العمود)
يا (1)
يا (1)
يا (1)

الخيار 4 (الصف)
يا (1)
يا (1)
يا (1)

الخيار 5 (التجزئة)
يا (1)
يا (1)
يا (1)

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

التحضير للتجربة

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

  • إضافة صديق جديد
  • التحقق مما إذا كان المستخدم "أ" صديقًا للمستخدم "ب".
  • إزالة صديق واحد

وبالتالي، ومع الأخذ في الاعتبار المتطلبات المبينة في البيان الأولي، يظهر سيناريو التحقق على النحو التالي:

  • تسجيل البيانات. قم بإنشاء شبكة أولية بحجم n بشكل عشوائي. وللتقرب من "العالم الحقيقي"، فإن عدد الأصدقاء لكل مستخدم هو أيضًا متغير عشوائي. قم بقياس الوقت الذي يكتب خلاله "التطبيق المشروط" جميع البيانات التي تم إنشاؤها إلى HBase. ثم قم بتقسيم الوقت الناتج على إجمالي عدد الأصدقاء المضافين - وبهذه الطريقة نحصل على متوسط ​​الوقت "لعملية تجارية" واحدة
  • قراءة البيانات. لكل مستخدم، قم بإنشاء قائمة "الشخصيات" التي تحتاج إلى الحصول على إجابة لها سواء كان المستخدم مشتركًا بها أم لا. طول القائمة = عدد أصدقاء المستخدم تقريبًا، وبالنسبة لنصف الأصدقاء المحددين يجب أن تكون الإجابة "نعم"، وبالنسبة للنصف الآخر - "لا". يتم إجراء التحقق بالترتيب الذي تتناوب فيه الإجابات "نعم" و "لا" (أي أنه في كل حالة ثانية سيتعين علينا مراجعة جميع أعمدة السطر للخيارين 1 و 2). يتم بعد ذلك تقسيم إجمالي وقت الفحص على عدد الأصدقاء الذين تم اختبارهم للحصول على متوسط ​​وقت الفحص لكل موضوع.
  • حذف البيانات. إزالة كافة الأصدقاء من المستخدم. علاوة على ذلك، فإن ترتيب الحذف عشوائي (أي أننا نقوم "بخلط" القائمة الأصلية المستخدمة لتسجيل البيانات). يتم بعد ذلك تقسيم إجمالي وقت الفحص على عدد الأصدقاء الذين تمت إزالتهم للحصول على متوسط ​​الوقت لكل شيك.

يجب تشغيل السيناريوهات لكل خيار من خيارات نماذج البيانات الخمسة ولأحجام مختلفة من الشبكة الاجتماعية لمعرفة كيف يتغير الوقت مع نموه. في غضون n واحد، يجب بالطبع أن تكون الاتصالات في الشبكة وقائمة المستخدمين المراد التحقق منها هي نفسها بالنسبة لجميع الخيارات الخمسة.
للحصول على فهم أفضل، فيما يلي مثال للبيانات التي تم إنشاؤها لـ n= 5. ينتج "المولد" المكتوب ثلاثة قواميس معرف كمخرجات:

  • الأول مخصص للإدراج
  • والثاني هو للتحقق
  • ثالثا – للحذف

{0: [1], 1: [4, 5, 3, 2, 1], 2: [1, 2], 3: [2, 4, 1, 5, 3], 4: [2, 1]} # всего 15 друзей

{0: [1, 10800], 1: [5, 10800, 2, 10801, 4, 10802], 2: [1, 10800], 3: [3, 10800, 1, 10801, 5, 10802], 4: [2, 10800]} # всего 18 проверяемых субъектов

{0: [1], 1: [1, 3, 2, 5, 4], 2: [1, 2], 3: [4, 1, 2, 3, 5], 4: [1, 2]} # всего 15 друзей

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

تم إجراء التجربة على جهاز كمبيوتر محمول يعمل بنظام التشغيل Windows 10، حيث كان HBase يعمل في إحدى حاويات Docker، وكان Python مع Jupyter Notebook يعمل في الحاوية الأخرى. تم تخصيص نواة وحدة المعالجة المركزية لـ Docker و2 جيجابايت من ذاكرة الوصول العشوائي. كل المنطق، مثل محاكاة "التطبيق الشرطي" و"الأنابيب" لتوليد بيانات الاختبار وقياس الوقت، تمت كتابته بلغة بايثون. تم استخدام المكتبة للعمل مع HBase com.happybaseلحساب التجزئة (MD5) للخيار 5 - hashlib

مع الأخذ في الاعتبار قوة الحوسبة لجهاز كمبيوتر محمول معين، تم اختيار الإطلاق لـ n = 10، 30، ... بشكل تجريبي. 170 - عندما كان إجمالي وقت التشغيل لدورة الاختبار الكاملة (جميع السيناريوهات لجميع الخيارات لجميع n) معقولًا إلى حد ما ومناسبًا خلال حفل شاي واحد (في المتوسط ​​15 دقيقة).

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

نتيجة التجربة

الاختبار الأول هو كيف يتغير الوقت الذي يقضيه في ملء قائمة الأصدقاء. والنتيجة في الرسم البياني أدناه.
مميزات تصميم نموذج بيانات لـ NoSQL
تُظهر الخيارات من 3 إلى 5، كما هو متوقع، وقت "معاملة تجارية" ثابت تقريبًا، والذي لا يعتمد على نمو حجم الشبكة وفرق لا يمكن تمييزه في الأداء.
يُظهر الخيار 2 أيضًا أداءً ثابتًا، ولكنه أسوأ قليلاً، تقريبًا مرتين تقريبًا مقارنة بالخيارات 2-3. وهذا لا يسعه إلا أن يفرح، لأنه يرتبط بالنظرية - في هذا الإصدار، يكون عدد عمليات الإدخال / الإخراج من / إلى HBase أكبر مرتين بالضبط. يمكن أن يكون هذا بمثابة دليل غير مباشر على أن منصة الاختبار الخاصة بنا، من حيث المبدأ، توفر دقة جيدة.
كما هو متوقع، تبين أن الخيار 1 هو الأبطأ ويوضح زيادة خطية في الوقت المستغرق في إضافة بعضها البعض إلى حجم الشبكة.
دعونا الآن نلقي نظرة على نتائج الاختبار الثاني.
مميزات تصميم نموذج بيانات لـ NoSQL
تعمل الخيارات 3-5 مرة أخرى كما هو متوقع - وقت ثابت، بغض النظر عن حجم الشبكة. يوضح الخياران 1 و2 زيادة خطية في الوقت مع زيادة حجم الشبكة والأداء المماثل. علاوة على ذلك، فإن الخيار 2 أبطأ قليلاً - على ما يبدو بسبب الحاجة إلى تدقيق ومعالجة عمود "العدد" الإضافي، والذي يصبح أكثر وضوحًا مع نمو n. لكنني سأظل أمتنع عن استخلاص أي استنتاجات، لأن دقة هذه المقارنة منخفضة نسبيا. بالإضافة إلى ذلك، تغيرت هذه النسب (أي الخيارين، 1 أو 2، أسرع) من الجري إلى الجري (مع الحفاظ على طبيعة الاعتماد و"الذهاب برقبة ورقبة").

حسنًا، الرسم البياني الأخير هو نتيجة اختبار الإزالة.

مميزات تصميم نموذج بيانات لـ NoSQL

مرة أخرى، لا توجد مفاجآت هنا. الخيارات 3-5 تؤدي الإزالة في وقت ثابت.
علاوة على ذلك، فمن المثير للاهتمام أن الخيارين 4 و5، على عكس السيناريوهات السابقة، يُظهران أداءً أسوأ قليلاً بشكل ملحوظ من الخيار 3. ومن الواضح أن عملية حذف الصفوف أكثر تكلفة من عملية حذف الأعمدة، وهو أمر منطقي بشكل عام.

الخياران 1 و2، كما هو متوقع، يوضحان زيادة خطية في الوقت. وفي الوقت نفسه، يكون الخيار 2 أبطأ باستمرار من الخيار 1 - بسبب عملية الإدخال/الإخراج الإضافية "لصيانة" عمود العد.

الاستنتاجات العامة للتجربة:

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

خاتمة

لا ينبغي أن تؤخذ التجارب التقريبية التي تم إجراؤها على أنها حقيقة مطلقة. هناك العديد من العوامل التي لم تؤخذ في الاعتبار وشوهت النتائج (تظهر هذه التقلبات بشكل خاص في الرسوم البيانية ذات حجم الشبكة الصغير). على سبيل المثال، سرعة التوفير التي تستخدمها Happybase، وحجم وطريقة تنفيذ المنطق الذي كتبته في بايثون (لا أستطيع أن أدعي أن الكود قد كتب على النحو الأمثل واستخدم بشكل فعال قدرات جميع المكونات)، ربما ميزات التخزين المؤقت لـ HBase، والنشاط في الخلفية لنظام التشغيل Windows 10 على الكمبيوتر المحمول، وما إلى ذلك. بشكل عام، يمكننا أن نفترض أن جميع الحسابات النظرية أثبتت صحتها تجريبيا. حسنًا، أو على الأقل لم يكن من الممكن دحضهم بمثل هذا "الهجوم المباشر".

في الختام، توصيات لكل من بدأ للتو في تصميم نماذج البيانات في HBase: استخلص من الخبرة السابقة في العمل مع قواعد البيانات العلائقية وتذكر "الوصايا":

  • عند التصميم، ننطلق من مهمة وأنماط معالجة البيانات، وليس من نموذج المجال
  • وصول فعال (بدون فحص كامل للجدول) – فقط عن طريق المفتاح
  • عدم التطبيع
  • يمكن أن تحتوي الصفوف المختلفة على أعمدة مختلفة
  • التكوين الديناميكي للمتحدثين

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

إضافة تعليق