في الجزء الثاني من مقال Database Design ، بعد ما اتكلمنا عن التصميم على مستوى ال data entities نفسها و كيف كل عقلية تصميم (ACID vs BASE) بتفرق بطريقة تعاملنا مع ال data entities العندنا … اليوم رح نتطرق لموضوعنا الثاني Normalization rules vs Data Modeling Patterns ، و اللي هو طريقة تصميم ال data entities نفسها من منظور ال Relational Databases و ال Non-relational Databases … و قراءة مفيدة للجميع ✨
أولا ، Normalization Rules:-
هي القوانين اللي من خلالها بنقدر نوصل لشكل tables نهائي قابل لانو بتنفذ عليه عمليات JOIN ناجحة أثناء عمل نظامنا. و طبعا بما انو قلنا tables ف هاد معناه أنو هاي القوانين بتتطبق في ال Relational Databases. طيب ، ايش هي هاي القوانين و شلون بنستخدما:
القانون الأول (NF1) ، ال Atomicity: و هو القانون اللي بينص على أنو غير مسموح لأي خانة في أي عمود من أعمدة ال table عندي أنو بحتوي على أكثر من قيمة وحدة. مثال على هاد الشي فلنفرض أنو عندنا عمود أسمو colors بحدد لون ال entity اللي عندي ، و بناءا على قانونا ، غير مسموح انو يكون عندي أكتر من لون واحد لكل خانة بالعمود ، يعني ما بقدر احدد Blue, Green, Red سوا لنفس ال entity ، لازم يكون لون واحد بس. طيب اذا كان في عندي entity فعلا محتاجة لاكثر من لون؟ بنلجأ لحل اسمو ال Junction Tables و اللي هي يتكون واصل بين table منفصلة للالوان و ال table الخاصة بال entity اللي شغالين عليها ، بحيث بنربط كل لون عندي مباشرة بال entity من غير ما نكرر اللون بنفس العمود.
طيب ما هي الفايدة من كللللل هاللفة و الدورة ؟ باختصار لما اكون متاكد انو كل خانة بكل عمود بتحتوي فقط على قيمة وحدة ، هاد الشي بساعد عمليان ال JOIN على انها تفلتر الداتا جوا ال entities بشكل اسرع و ادق ، و بالتالي زيادة مصداقية و كفائة عمليات البحث في ال database اللي عندنا.
القانون الثاني (NF2) ، ال Whole Key: بعد ما اتاكدت انو اي خانة عندي باي عمود رح تحتوي على قيمة واااحدة فقط لا غير ، بنجي للخطوة الثانية و اللي هي نخلي كل الخانات الخاصين بأي entity تتبع Key واحد فقط لا غير بكااامل قيمتو ، بعني؟؟
خلينا نفترض أنو عندنا جدول بيوصف مستخدم خواصه name, age, phone, password ، و ال name عندي مكون من first_name و last_name ، و قررت انو ال name هو رح يكون المفتاح اللي رح يمثل عندي كل مستخدم ، و عن طريقو ببحث عن المستخدمين المسجلين عندي … حلو
هاد رح يعني انو كل البيانات الخاصة باي مستخدم رح تكون تابعة لخاصية ال name فقط لا غير ك key ، و انو ال name كامل هو المدخل الوحيد و الاكثر كفاءة للوصول لاي بيانات فرعية خاصة باي مستخدم. بعني لو حبيت اوصل لارقام تلفون مستخدم اسمو "علي حسان" ، ف اسم "علي حسان" هو اسرع key ممكن يوصلني لرقم النلفون ، و انو لو حاولت ابحث عن طريق "علي" او "حسان" لوحدهم ف ما رح تجيني نفس كفائة و سرعة النتائج.
بعرف يمكن الشرح يبان بديهي بس على أرض الواقع في تطبيقا أعقد من مثالنا بتشمل شي اسمو Composite keys هي الهدف الرئيسي من القانون الثاني ، واللي مبدأ عملها بشكل كبير بيشبه مثال ال name المكون من first_name و last_name.
القانون الثالث (NF3) , ال Transitiveness: يمكن هاد اهم قانون عندي ، و اللي بينص على أنو اي مجموعة داتا بتعتمد بتمثيلا على key معين (مثال المستخدم name, age, phone, password) لازم تكون table مستقلة لوحدها.
اذا اتوسعنا من مثال المستخدم نفسو ، فالنفرض انو المستخدم عندو بيانات اضافية بتوصف موقعو ، و بتحتوي على بيانات اضافية مثل location, city, country ، و كانت هالبيانات بتعتمد دايما على ال locatoin بتحديد باقي البيانات اللي هي ال city و country ، ف من الافضل أنو تكون في عندي table منفصلة خاصة بهالبيانات ، و بتم تمثيل البيانات عند المستخدم بشي اسمو Foreign key فقط لا غير.
بشكل كبير جدا هاد القانون الاساسي اللي بيحم عندي كيفية توزيع البيانات على tables مختلفة و ربط البيانات مع بعضا البعض.
ثانيا ، Data Modeling Patterns:-
بما انو هالطريقة مستخدمة بال Non-relational Databases ، ف كل القوانين الذكرناها فوق بتم تجاهلا ، و بنبدا عملية optimization منفصلة بطرق بتناسب عمل ال Non-relational Databases.
و تركيزنا هون رح يكون بشكل كبير على انشاء عدد ال documents الكافي كحد ادنى ، لتخزين اكبر كمية بيانات بنحتاجا ، لتوفير اسرع عمليات بحث أو queries للداتابيز اللي عندنا. بعبارة أخرى ، اكبر كمية داتا بحتاجا بأقل عدد queries.
و طبعا في ال Non-relational Databases ما بكون عندي tables بحدد عن طريقا شكل الداتا اللي رح اخزنو ، و انما ركون عندي documents بخزن فيها الداتا اللي بحتاجا في ال query الوحدة بغض النظر عن كون كل ال documents بتحتوي على نفس الخواص او لا ، او كان فيها تكرار للبيانات او لا.
طريقة التفكير اللي بتقترحا ال Data Modeling Patterns بتخلينا نطلع من اي اطار محدد لتصميم الداتابيز الخاصة فينا ، و بتخلي هدفنا الرئيسي أنو نشكل الداتا بالشكل اللي بدنا ياه ، طالما بيضمنلنا السرعة و الكفاءة بشكل الداتا اللي رح نستخدمو. و بحكم انو التطبيقات العملية و الحلول دايما بتكون متشابهة و بتحل مشاكل الها نفس الطبيعة ، فانتشرت Patterns للتصميم بتساعد على الوصول لهدفنا (أسرع queries بتحتوي على افضل شكل بيانات بنحتاجو) مثل:
ال Bucket Pattern: باختصار بتقترح هالطريقة انو لو عندي فترة معينة متوقع فيها قراءات متكررة بشكل دوري ، فبدل ما اخزن كل قراءة في document منفصل متل ما هو متوقع ، لا ممكن اخزن قراءات كل فترة معينة بنفس ال document لتقليل عدد ال documents و الحصول على قراءات اكبر بنفس عملية ال Read من الداتابيز … منطقي. و مثال على استحدام مماثل ، اذا كان عندي نظام تتبع ترتيب العدائين اللي حيعبرو خط نهاية في سباق مكون من اكثر من لفة ، فبدل ما اخزن كل مرة احد المتسابقين بيعبر خط النهاية في document منفصل ، ممكن اخزن بيانات كل لفة كاملة لكل العدائين بنفس ال document.
ال Attribute Pattern: بتقترح هالطريقة انو في حال عندي Collection (مجموعة documents) بتوصف data entities فيها احتمالية اختلاف في الخصائص ، مثل وحدات البضاعة في بقالة مثلا ، ف ممكن بدل ما اعمل Collection لكل نوع من انواع البضاعة لوحدو ، اعمل Collection وحدة فيها الداتا الاساسية المشتركة بين كل الوحدات (كمية ، سعر ، تكلفة ، تاريخ … ) ، و اعمل key/value pairs خاصة بكل نوع فرعي من البضاعة العندي بنفس ال document بحيث انو كل وحدة من الوحدات اللي عندي بتملا ال pairs الخاصة فيها فقط لا غير.
ال Computed Pattern: طبعا مختلف أنواع ال Databases بوفرولنا Functions بتسهل علينا اجراء عمليات بسيطة على الداتا قبل قراءتها من الداتابيز بغرض توفير زيادة العملية على عمل النظام و ما الى هنالك. و اللي بيحكم قرار انو نستخدم ال Functions المتوفرة مقابل انو نصممها بنفسنا في الكود الخاص فينا بيرجع لنقطة وحدة: كم مرة رح نستدعي ال Function ، و بما انو استدعائها ممكن يكون في عملية Read أو Write ، ف العملية ما مهمة و انما المهم فقط هو عدد المرات اللي بنستدعي فيها الفنكشن. فاذا وجدنا انو عندي عمليات Read/Write كثيرة بتستدعي Function معينة بصورة ممكن تأثر على اداء ال Database ، ف من الافضل انو نكتب ال Function بنفسنا في الكود الخاص فينا ، و نقوم فقط بتخزين النتيجة النهائية في الداتابيز.
هاي كانت مقارنة بسيطة بين كيفية تصميم ال Data Entities من منظور ال Relational و ال Non-relational ، و اللي في بنختم الجزء الثاني من مقال ال Database Design ، و ان شاء الله الجزء القادم رح يكون الاخير بعنوان How to Choose Between SQL and Non-SQL Databases
و ان شاء الله تكون في فايدة للجميع ✨