9 دقيقة قرائية

اهلا! 👋🏻 استكمالا لسلسلة زبدة قواعد البيانات، اليوم حنتكلم عن كيف محركات قواعد البياينات تحفظ المعلومات في الذاكرة، وهل هذا المستوى من التفصيل والتعمق مهم فعلا لك كشحص تقني او لا.

حاكون ممتن لو ساعدتني على نشر العمل هذا عن طريق ارسال المدونة لاحد ممكن يستفيد منها، فالاخير الهدف هو نشر محتوى عربي تقني بجودة عالية مجانا؛ مساعدتك لي في هذا الهدف يعني لي الكثير. 🐳🍉

- غوني

اليوم باغطي بعض من اهم االمفاهيم اللي تعتبر أساسية في عالم قواعد البيانات، وهي:

مقدمة 🙇‍♂️

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

غير عن ذلك، معرفتك لهذه المبادئ، بالعمق الكافي، يجعلك واثق في بحثك لحل اي مشاكل قد تواجهك، وفهمك لوجهة نظر محرك قاعدة البيانات عن العالم. هذا غير سهولة التواصل بينك وبين فريقك لشرح المشكلة، سببها، وخطة حلها.

والآن، وبعد الاجابة عن السؤال الأول، خلينا نتكلم عن المبدأ خلف اي محرك قواعد بيانات ونبني من هناك.

العصور الأولى: خلينا نسوي قاعدة بيانات 🦍

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

البداية: جائزة ابسط (و أغبى) قاعدة بيانات فالعالم 🥇

خلينا نشوف قاعدة بيانات بـPython نسميها قاعدة بيانات GhawanniBase:

import json
import os

# Define the file where data will be stored
DATA_FILE = 'GhawanniBase.json'

def store(key, data):
    entry = {'key': key, 'data': data}
    
    # Append the entry to the file
    with open(DATA_FILE, 'a') as file:
        file.write(json.dumps(entry) + '\n')

def query(key):
    latest_data = None
    
    # Check if the file exists
    if os.path.exists(DATA_FILE):
        with open(DATA_FILE, 'r') as file:
            for line in file:
                entry = json.loads(line)
                if entry['key'] == key:
                    latest_data = entry['data']
    
    return latest_data

الفكرة سهلة، كل اللي صار هنا 👆 انه فيه عندنا خاصيتين، حفظ بيانات واسترجاع بيانات. نوع فاعدة البيانات هذه، مثل ما قلنا في اول منشور في السلسة، من نوع Key-Value Pairs، و مثل ما تلاحط، قاعدين تحفظ اي مدخل كسطر جديد في ملف، حتى لو كان المفتاح متكرر اكثر من مره، ولهذا السبب، في خاصية الاسترجاع query نرجع آخر مدخل لقاعدة البيانات فقط.

هذه خاصية (ليست عيب 😎) ممتازة جدا لو كان فيه كتابة بشكل كبير في قاعدة البيانات حقتنا، لانه ماصار فيه الخطوات التالية عند اضافة object جديد:

  1. بحث عن المفتاح في قاعدة البيانات
    1. تحديث الـobject في حال وجوده من قبل
    2. اضافة جديد في حال عدم وجوده فصرنا نتخطى هذه الخطوات ونضيف على طول، وخلينا التأكد من ان استرجاع آخر ملف وقت القراءة.

صراحة سوينا شيء رهيب نظرا ان نظامنا اقل من 25 سطر سهلة الفهم. ولكن طبعا، مافيها اي من المقومات اللازمة حتى تكون قاعدة بيانات حقيقية، ومن هذه المقومات:

  • البحث بكفاءة عالية بدلالة مفتاح متفق عليه من قبل
  • البحث عن طريق نمط معين في البيانات او بأي مفتاح من مفاتيح الـobject (حتى لو بكفاءة اقل)
  • دعم عدة عمليات كتابة من مستخدمين مختلفين بالتوازي
  • تقسيم قاعدة البيانات الى عدة اجهزة في حال كبرت (partitioning / sharding)
  • عمل عدة نسخ من قاعدة البيانات وتزامنها مع بعضها للحماية من تعطل الخدمة او خسارة البيانات (replication)
  • القائمة تطووول.. 📜

خلينا نبدأ نشوف كيف مطورين قواعد البيانات طوروا الخواص المذكورة اعلاه؛ ونبدأ بأهم خاصية في أي قاعدة بيانات: لو بحثت، ابغا النتيجة الصحيحة و بسرعة، والحل كان الفهارس او Indexes

الفهارس (Indexes) تنقذ اليوم 🗃️

خلينا نفترض التالي، عندنا معلومة فريدة (unique) في كل مدخل في قاعدة البيانات، ولنفترض انه نبغا دائما نسترجع البيانات بدلالة هذه العلومة. اذا، نحتاج طريقة نرتب المعلومات في قاعدة البيانات بحيث نقدر نبحث بكفاءة عالية.

المشكلة هذه مو جديدة، المكتبات من اكثر من 200 سنة تستخدم نظام The Dewey Decimal لترقيم الكتب ووضعها في مكانها المناسب في المكتبة، وفي اي مكتبة فالعالم الترتيب حيكون نفسه.

اذا، نحتاج خوارزمية نقدر ندخل فيها اي مفتاح فريق من اختيارنا ويكون الترتيب موجود، فنقدر عند احتياج المعلومة نستردها بكل سرعة وبدخول عشوائي او قريب من عشوائي (random access).

اول طريقة لفهرسة البيانات ممكن تجي في البال هي استخدام جدول مجزأ او hash table كهيكل بيانات يدعم المواصفات اللي فوق.

ميزة الـhash tables انها دائما تكون خيار فعال لرفع الكفاءة بشكل ممتاز، فتعقيدها في اسوأ الاحوال يكون Big O(n) بسبب التصادمات او الـcollisions، وفي متوسط (average) الاحوال Big O(1) (وصول مباشر).

لشرح اوفى واوضح للـhash tables (انصح بالمشاهدة، لانها هيكل بيانات رهيب)، هذا فيديو يشرح بشكل لطيف:

لقينا حل جيد للفهرسة، ولكن، فيه معوقات تجعلنا نفكر في حلول اخرى، مثل:

  • ما نقدر نبحث في نطاق (مثلا: كل المنتجات اللي سعرها بين ١٠٠ و ٥٠٠ ريال)
  • لازم كل الـhash table تدخل في الذاكرة العشوائية (RAM) عشان نعرف في نبحث في الذاكرة (Disk)

طبعا، هذا لا يعني انها سيئة ابدا، خصوصا للاستخدامات اللي تتطلب حفظ البيانات بشكل مؤقت (من غير كبر البيانات بشكل هائل). فمثلا، Redis و Memcached كلها تستخدم Hash tables للفهرسة البيانات اللي تحفظ فيها.

والآن، لازم نشوف طريقة ثانية نكون الفهرس، من خلالها تناسب الاستخدامات الاخرى، فيا مرحبا ألف بالاشجار.

ازرع شجرة، اجني ثمرة 🌲

عشان نتخطى التحديات اللي موجودة فوق، تم استخدام اكثر من data structure للبيانات، كل واحد منها ممتاز لاستخدامات مختلفة، اهمها الـB-Trees و الـLSM Trees، خلينا نستكشف كل واحدة.

B-Trees 🌴

لو كنت خريج Computer Science او Software Engineering فالغالب درست هذا الـdata strcuture المشهور. B-Trees اختصار لـBalanced Trees، الفكرة الاساسية تبني على الـbinary trees الشي الاساسي فيها انها توازن نفسها بنفسها (self-balancing)، بحيث ان كل الـleafs تكون على نفس المستوى وكل مدخل جديد على الشجرة يكون من الجذر (root).

ميزات الـB-Trees ✅

  • نقدر بكل سهولة نقوم بـquereis على range او نطاق بحكم ان الـB-Trees دائما متوازنة (balanced)
  • كفاءة عالية في القراءة من البيانات المحفوظة برضه بحكم انها balanced

عيوب الـB-Trees ❌

  • الكتابة بطيئة، خصوصا لو لازم نوازن الشجرة بعد الكتابة

استخدامات الـB-Trees 💭

تستخدم الـB-Trees في كثير من قواعد البيانات المشهورة، منها:

  • PostgreSQL
  • MySQL (InnoDB)

وفالغالب ممتازة تستخدم احد هذه التقنيات لما يكون عندك احتياج كبير للقراءة بسرعة وماعندك كتابة بشكل كبير ومتكرر و سريع على قاعدة البيانات.

مصدر لتعلم الـB-Trees 🧠

تقدر تلاقي شرح رهيب على Geeks for Geeks هنا

LSM Trees 🌳

هذا نوع data structure يركز اكثر على الكتابة على حساب كفاءة القراءة. الـLSM Trees اختصار لـLog-Structured Merge Trees، الفكرة ان اي كتابة جديدة تكون على الذاكرة العشوائية (RAM) وبعدين لما تكبر البيانات في الـRAM، الخوارزمية تسوي flush الى المستوى الأقل في الذاكرة الدائمة وتضغط البيانات (compression) عشان تحافظ على المساحة. البيانات اللي تنضغط في الذاكرة تحفظ على نوع آخر من الـdata structures اسمه SSTables (Sorted String Tables) (تقدر تقرأ عنه هنا)، وعشان تكون العملية آمنة، اي كتابة تحفظ في Write-Ahead Log (WAL) (اقرأ هنا).

ميزات LSM Trees ✅

  • بحكم ان كل الكتابات تكون في الذاكرة العشوائية وبدون ترتيب، يمكن بهولة كبيرة الكتابة بشكل سريع جدا
  • لو كنت تحتاج تقرأ بيانات مكتوبة للتو (قبل الـflush)، يمكن استردادها بكفاءة عالية جدا
  • كفاءة عالية في الحفظ في الذاكرة الدائمة (disk) بسبب المستويات الكثيرة للضغط على الـSSTables

عيوب LSM Trees ❌

  • استرداد البيانات القديمة بطيء مقارنة بالـdata strcutures الاخرى
  • بسبب عمليات الضغط المتكررة، تحتاج موارد تشغيلية اعلى من الـdata strcutures الاخرى

استخدمات LSM Trees 💭

تستخدم الـLSM Trees في الكثير من التقنيات اللي توعد بكفاءة كتابة عالية، مثل:

  • Cassandra
  • LevelDB

لو كنت تعرف انك تحتاج كفاءة كتابة عالية و ان اغلب عمليات القراءة للبيانات المكتوبة من فترة بسيطة، احد هذه التقنيات قد يكون الانسب لك.

مصدر لتعلم LSM Trees 🧠

هذا مقال رهيب يغظي هذا الـdata structure بشكل ممتاز

طيب خلينا نقلب الصفوف عواميد 🤸🏻‍♂️

فيه نوعين مشهورة من اسخدامات قواعد اليانات:

  • خدمة المستخدمين، ويكون التركيز على صف (row) واحد وغالبا الشغل عليه
  • التحليل والتفصيل في البيانات، غالبا يكون على عامود (column) او اكثر من دون النظر الى كل صف على حدى

هذه النوعين مختلفة جدا في طبيعتها وتتطلب تغييرات في كيف نكتب، نحفظ، ونسترد البيانات في الـdatabase اللي نستخدمها. خلينا نستكشف اول شيء كيف البيانات تحفظ في الـdisk وكيف يؤثر هذا القرار على استخدمنا للبيانات.

التأثير على طريقة الحفظ وقرب البيانات من بعضها 🫂

حفظ البيانات له طريقتين:

  1. بالصف - Row-Oriented ↔️: والمعنى ان الصح الواحد والبيانات اللي تخصه تحفظ جنب بعض على الذاكرة، يتم تحميلها ينفس الطريقة على الذاكرة العشوائية بحكم انه يتم التعامل مع كل صف على حدى
  2. بالعامود - Columnar ↕️: وهنا، يقوم نظام قاعدة البيانات بحفظ البيانات بحيث ان بيانات العامود الواحد تكون متقاربة في الذاكرة، على تحسب ان اغلبية عمليات التحميل من الـdisk الى الـRAM تكون تهتم بجميع او اغلبية المعلومات في العامود الواحد، وليس كل صف على حدى.

هذا اكبر فرق في كيف يتم حفظ البيانات وكيف هذا القرار يؤثر على استرجاع البيانات:

  • لو عمليات القراءة والكتابة تكون على الصف الواحد: الخيار الاسلم هو قاعدة بيانات Row-Oriented
  • لو عمليات القراءة تحليلية وتعمل على جميع بيانات العامود (بغض النظر عن الصف): الخيار الافضل هو حفظ بيانات العامود الواحد بشكل متقارب في قاعدة بيانات Columnar

اختار: نحلل بيانات (OLAP)؟ ولا نخدم مستخدم (OLTP)؟ 🔎

العمليات هذه لها اسم من الجيد ان كل تقني يعرفه، وهو OLAP (اخصار لـOn Line Analytical Process)، وهي اللي تتعامل مع العواميد بشكل كلي ولا تهتم لكل عامود. انواع قواعد البيانات هذه تكون فالغالب لها خواص وميزات مختلفة عن قواعد البيانات الاخرى (بنتكلم عنا بعد شويه).

فمثلا، من اهم ميزات هذا النوع من قواعد البيانات هو انها تستخدم ذاكرة اقل (الـcompression فعال اكثر لان بيانات العامود من نفس النوع)، القدرة على عمل عمليات رياضية بكفاءة عالية على كم كبير من البيانات، وايضا سرعة في العمل على البيانات بالتوازي.

ولكن هذا يكون على حساب سرعة الكتابة واسترجاع البيانات اللي يكون “لها دخل ببعض” كمثلا معلومات منتج واحد (لان اسعار كل المنتجات محفوظة جنب بعض، وبعيدة عن اساميها).

اما بالنسبة للنوع الآخر، وهو قواعد البيانات من النوع الاول، وفي الغالب هو اللي يجي عالبال لما نتكلم على الـdatabases، يكون مركز على حفظ معلومات الصف الواحد جنب بعض بحكم انها على سبيل المثال معلومات مستخدم واحد ونحتاج دائما نحملها ونسترجعها مع بعضها البعض.

تقنيات تطبق الحفظ العامودي (Columnar Databases) 🗃️

بحكم طريقة استخدامها، فالغالب هذا النوع من قواعد البيانات يكون لمشاريع الـdata warehouses ولا يستخدمها التطبيق بشكل مباشر، الا في حالة ان يكون احد خواص التطبيق تحليل بيانات كبيرة للمستخدم.

من اهم امثلة هذه التقنية Amazon Redshift, Google BigQuery, و Cassandra

الملخص 🧈

شفنا اليوم مع بعض كيف تأثير الفهرسة على قاعدة البيانات، وايش الطرق المختلفة اللي ممكن نكوّن فيها الفهرس او الـindex حقنا.

استكشفنا برضه انواع مختلفة من حفظ البيانات في الذاكرة وايش الفرق بين الـrow-oriented databases والـcolumnar databases وايش الاستخدامات الصحيحة لكل واحدة، الخيار الاسلم تختار التقنية الصحيحة حتى تمكنك وتساعدك بالطريقة الصحيحة وتستفيد من خدمات قاعدة البيانات هذه في المستقبل برضه.


جوك فيديوهات؟ 📼

هذا فيديو بيفابت اللي اتكلمنا فيه انا وعبدالرحمن الرحمة عن الـSQL Databases وتطرقنا فالكلام الى طريقة حفظ البيانات:

اترك تعليق