ما بعد الجدول: نماذج البيانات البديلة
درس 5 من 6
5ما بعد الجدول: نماذج البيانات البديلة
أربع عائلات غير علائقية، ونفس البيانات مرسومة في كل واحدة. وفي النهاية قياس حقيقي: نفس السؤال على نفس الـ٣٠٠ ألف علاقة، ١٩٫٣٧ مللي ثانية مقابل ٠٫٠١.
ماذا تشاهد في الرسم: نفس بيانات المكتبة في أربعة أشكال: مفتاح وقيمة، ووثيقة، وأعمدة، ورسم بياني، ولكل شكل سؤال يجيده.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
الجدول ليس الطريقة الوحيدة لحفظ المعلومات. أحيانًا تحفظها كملفات كاملة (مستندات)، أو كدفتر عناوين سريع (مفتاح وقيمة)، أو كخريطة أصدقاء (رسم بياني)، أو كدفتر قياسات مرتّب بالوقت. كل شكل يجعل نوعًا من الأسئلة سريعًا جدًا ونوعًا آخر بطيئًا.
أربع عائلات غير علائقية: المستندات document مثل MongoDB، والمفتاح والقيمة key-value مثل Redis، والرسم البياني graph مثل Neo4j، والسلاسل الزمنية time-series. الاختيار يتبع نمط الوصول: قراءة كيان كامل، أو بحث بمفتاح، أو تتبّع علاقات بعمق، أو تجميع حسب الزمن.
المتطلبات قبل البداية
الجزء الثالث
تعرف كيف يصير مخطّط الأصناف جداولًا: صنف ← جدول، وتعدّدية ← مفتاح أجنبي.
فكرة الضمّ (JOIN)
أن قراءة صفّ من جدولين تحتاج مطابقة. هذا كل ما تحتاجه لفهم بقية الجزء.
صدق في السؤال
هذا الجزء لا يسأل «أي قاعدة بيانات أفضل؟» بل «أي شكل يناسب سؤالي؟». السؤال الأول لا جواب له.
المفاهيم الأساسية
النموذج العلائقي يطبّع البيانات فلا تتكرّر، ثم يجمعها عند القراءة بالضمّ. هذا ممتاز حين تكون الأسئلة متنوّعة، ومكلف حين يكون السؤال واحدًا ويتكرّر ملايين المرات. البديل ليس «أحدث» بل مخصّص لسؤال بعينه.
جدول تجزئة ضخم: مفتاح واحد ← قيمة لا يفهمها المخزن. أسرع ما يمكن للسؤال «أعطني هذا المفتاح»، وعاجز تمامًا عن «أعطني كل من مدينته الرياض». مجاله: الجلسات، التخزين المؤقّت، العدّادات، مفاتيح الميزات.
كل سجلّ شجرة JSON مستقلّة، والمخزن يفهم داخلها فيستطيع البحث فيه. مجاله: السجلّ الذي تقرأه كاملًا دائمًا، صفحة المنتج، ملف العضو، سلّة الشراء. وثمنه التكرار: البيانات المكرّرة في ألف وثيقة تتقادم.
صفوف عريضة متفرّقة، والقراءة بالعمود لا بالصفّ. مجاله: السلاسل الزمنية والقياسات، ملايين الصفوف وعمودان مطلوبان. ليس «جدولًا أسرع» بل اتجاه قراءة مختلف.
العلاقة سجلّ من الدرجة الأولى: لها نوع وبيانات. مجاله السؤال الذي موضوعه العلاقة: أصدقاء الأصدقاء، أقصر طريق، كشف حلقات الاحتيال. وهذا ما سنقيسه بعد قليل.
النموذج يتبع السؤال، لا العكس. ومن يختار المخزن قبل أن يكتب أسئلته العشرة الأكثر تكرارًا يختار بالعنوان لا بالدليل.
كيف يعمل؟
شكل 1، شجرة اختيار تبدأ من السؤال لا من اسم المنتج، ولاحظ أن الورقة الأخيرة هي العلائقي
نفس البيانات في أربعة أشكال
مفتاح-قيمة: المخزن لا يفهم القيمة، فلا يستطيع السؤال عن داخلها.
# key-value: one key, one opaque blob. The store knows nothing about the inside.
session:9f3a1c -> {"user": 42, "expires": 1772000000, "cart": [7, 19]}
rate:42:minute -> 17
feature:dark -> "on"
GET session:9f3a1c # the only question it answers well
SET rate:42:minute 18وثائقي: نفس العضو، لكن استعاراته داخله، فصفحته قراءة واحدة.
// document: a tree per record. Queryable inside, and self-contained.
{
"_id": 42,
"name": "Muath",
"city": "Riyadh",
"loans": [
{ "barcode": "D-01", "title": "Dune", "due": "2026-03-15" },
{ "barcode": "E-07", "title": "Emma", "due": "2026-03-20" }
]
}
db.members.find({ "loans.due": { $lt: "2026-03-18" } }) // asks inside the treeعائلة أعمدة: صفّ قد يحمل ٣٦٥ عمودًا، ونقرأ منها عمودين.
# column family: rows are wide and sparse; you read the columns you need. # row key | columns (each row may have entirely different ones) member:42 | name=Muath city=Riyadh joined=2024-02-01 reading:42:2026 | 01-05=Dune 01-09=Emma 02-14=Solaris ... (365 possible) SELECT 01-05, 01-09 FROM reading WHERE key = 'reading:42:2026'; # two columns read off disk - not the whole row
رسم بياني: لاحظ أن الاستعارة صارت نوع علاقة له تاريخ، وهذا هو صنف الارتباط من الجزء الثالث، مرسومًا كما هو.
# graph: the relationship is a first-class record with its own type and data.
(Muath)-[:BORROWED {on: "2026-03-01"}]->(Copy D-01)-[:COPY_OF]->(Dune)
(Muath)-[:FOLLOWS]->(Sara)-[:FOLLOWS]->(Amal)
MATCH (m:Member {id: 42})-[:FOLLOWS*2]->(x) RETURN DISTINCT x
# "*2" = two hops. The same question is a self-join in SQL.| النموذج | يجيب ببراعة عن | يعجز عن | ثمنه |
|---|---|---|---|
| مفتاح-قيمة | «أعطني هذا المفتاح» | أي سؤال عن المحتوى | لا علاقات ولا بحث |
| وثائقي | «أعطني هذا السجلّ كاملًا» | الضمّ بين وثائق | تكرار يتقادم |
| عائلة أعمدة | «هذان العمودان من مليون صفّ» | الأسئلة المتنوّعة | تصميم المفتاح يقيّدك |
| رسم بياني | «ما بعد علاقتين أو ثلاث؟» | التجميعات الضخمة | العمق ينفجر |
| علائقي | أسئلة لم تتوقّعها | القراءات الهائلة لسؤال واحد | الضمّ له تكلفة |
التمرين: قياس حقيقي على ٣٠٠ ألف علاقة
الكلام عن «الرسم البياني أسرع للعلاقات» يُقال كثيرًا ويُقاس قليلًا. فقِسناه. بنينا شبكة متابعة: ٢٠٠٠٠ مستخدم، كل واحد يتابع ١٥ غيره، فصار المجموع ٢٩٩٩٨٩ علاقة، وسألنا السؤال نفسه ثلاث مرات:
# the experiment: 20,000 users, each following 15 others
edges = [(a, b), ...] # 299,989 pairs
def fof_table_scan(user): # a table with no index
first = {b for a, b in edges if a == user}
return {b for a, b in edges if a in first} - first - {user}
index = defaultdict(set) # the same data, keyed by follower
for a, b in edges:
index[a].add(b)
def fof_indexed(user): # a table with an index
out = set()
for f in index[user]:
out |= index[f]
return out - index[user] - {user}
def reach(user, depth): # the graph shape, asked recursively
seen, frontier = {user}, {user}
for _ in range(depth):
nxt = set()
for u in frontier:
nxt |= index[u] - seen
seen |= nxt
frontier = nxt
return frontier$ python3 models.py users: 20000 follow edges: 299989 table, full scan per hop 19.37 ms -> 225 results table, indexed on the follower column 0.01 ms -> 225 results graph traversal, 2 hops 0.01 ms -> 225 results same answer from all three: True depth 1 -> 15 users reached (0.00 ms) depth 2 -> 225 users reached (0.03 ms) depth 3 -> 3065 users reached (1.02 ms) depth 4 -> 14971 users reached (10.57 ms)
same answer from all three: True يثبت ذلك. المقارنة عادلة.شكل 2، انفجار العمق: ثلاث خطوات تصل ١٥٪ من الشبكة، وأربع تصل ٧٥٪
اعتقاد شائع × الحقيقة
| الاعتقاد | الحقيقة |
|---|---|
| «NoSQL يعني بلا مخطّط.» | يعني أن المخطّط في كودك لا في المخزن. والمخطّط الضمني أخطر من الصريح لأن لا أحد يفحصه. |
| «قاعدة الرسوم أسرع للعلاقات.» | قسناه: الفهرس على الجدول أعطى نفس الزمن (٠٫٠١ مللي ثانية). المكسب من شكل الوصول. |
| «الوثائقي يلغي الحاجة للتطبيع.» | ينقل تكلفتها من القراءة إلى التحديث. ما كان ضمًّا واحدًا يصير ألف تحديث. |
| «عائلة الأعمدة جدول أسرع.» | اتجاه القراءة مختلف: بالعمود لا بالصفّ. وهي أسوأ من الجدول للأسئلة المتنوّعة. |
| «مفتاح-قيمة بدائي.» | هو الأسرع لسؤاله، والجلسات والعدّادات لا تحتاج أكثر. البدائي هو استخدامه لسؤال آخر. |
| «نختار المخزن ثم نكتب الأسئلة.» | هذا هو الخطأ الأم. اكتب أسئلتك العشرة الأكثر تكرارًا أولًا، ثم اختر الشكل الذي يخدمها. |
جرّب بنفسك
استعلام «أصدقاء الأصدقاء» عندك يأخذ ١٩ مللي ثانية على جدول. ما أول ما تجرّبه؟
لأن هذا بالضبط ما قسناه: الفهرس أعطى ٠٫٠١ مللي ثانية، نفس زمن تخطّي الرسم البياني. الفهرس سطر واحد، والهجرة مشروع. والتخزين المؤقّت يخفي المشكلة ويضيف تقادمًا، وتقليل المستخدمين ليس حلًّا هندسيًّا.
استعلام تخطّي بلا حدّ للعمق على شبكتنا. ماذا يحصل في الإنتاج؟
قياسنا: ١٥ ← ٢٢٥ ← ٣٠٦٥ ← ١٤٩٧١ من ٢٠٠٠٠. النمو أُسّي لا خطّي، ولهذا يبدو الاستعلام سليمًا على بيانات التطوير الصغيرة ويسقط على بيانات حقيقية.
بطاقات مراجعة سريعة
تحقّق من فهمك
1. بجملة واحدة: لماذا أعطى الفهرس والرسم البياني نفس الزمن؟
لأنهما نفس البنية: جدول تجزئة من مستخدم إلى مجموعة من يتابعهم. ومخزن الرسوم يبني هذه البنية لك ويعطيك لغة استعلام لها، لكنه لا يملك سرًّا رياضيًّا أسرع.
2. اشرح بالتفصيل من أين جاءت الـ١٩٫٣٧ مللي ثانية.
دالة المسح تمرّ على قائمة الـ٢٩٩٩٨٩ علاقة مرتين: مرة لتجمع من يتابعهم المستخدم، ومرة لتجمع من يتابعهم أولئك. فهي نحو ٦٠٠ ألف مقارنة في بايثون، وهذا هو الرقم. والفهرس يحوّل السؤال من «امسح كل العلاقات» إلى «١٥ قراءة بمفتاح»، فصار العمل متناسبًا مع حجم الجواب لا مع حجم البيانات، وهذا هو الفرق كله، وهو نفس الفرق بين ضمّ بمسح كامل وضمّ بفهرس في أي قاعدة علائقية.
3. (اكتشف الخطأ) فريق نقل بيانات الجلسات من مخزن مفتاح-قيمة إلى قاعدة علائقية «للتوحيد». ما الخطأ؟
استبدلوا الشكل الأمثل لسؤالهم بشكل عام. الجلسة سؤال واحد بمفتاح معروف، ولا تحتاج ضمًّا ولا معاملات ولا استعلامات غير متوقّعة، لكنها تحتاج كتابة في كل طلب وانتهاء صلاحية تلقائيًّا، وكلاهما أرخص بكثير في مخزن مفتاح-قيمة. «التوحيد» هدف إداري حقيقي، لكن ثمنه هنا حمل على أثقل قاعدة في النظام لأجل بيانات مؤقّتة لا تستحقّ المتانة.
4. عندك سؤال واحد يمثّل ٩٥٪ من القراءات وعشرة أسئلة متنوّعة تمثّل ٥٪. كيف تختار؟
لا تختار نموذجًا واحدًا. اجعل العلائقي هو مصدر الحقيقة لأنه يخدم الأسئلة المتنوّعة والتي لم تتوقّعها، وأضف للسؤال الغالب شكلًا مخصّصًا: فهرسًا أولًا، فإن لم يكفِ فعرضًا مادّيًّا أو مخزن مفتاح-قيمة أمامه. والقاعدة: نموذج واحد مصدرٌ للحقيقة، والبقية مشتقّة منه ويمكن إعادة بناؤها. من يجعل الشكل المخصّص مصدرًا للحقيقة يفقد القدرة على الإجابة عن سؤال جديد.
5. (قرار) مديرك قرأ أن شركة كبيرة انتقلت إلى مخزن رسوم، ويريد نفس الشيء. ما ردّك؟
أسأل عن الدليل لا عن المرجع: ما الاستعلام البطيء، وكم زمنه الآن، وما هدفنا، وهل عليه فهرس؟ ثم أعرض ما قسناه في هذا الجزء: نفس السؤال على ٣٠٠ ألف علاقة انخفض من ١٩٫٣٧ إلى ٠٫٠١ مللي ثانية بإضافة فهرس، وهو نفس زمن تخطّي الرسم البياني. فإن بقي بطيئًا بعد الفهرس، وكانت أسئلتنا الأساسية عن مسارات عميقة متغيّرة العمق، فالهجرة لها وجه. وما نجح عند شركة بحجم مختلف وأسئلة مختلفة ليس دليلًا على مشكلتنا، والقياس على بياناتنا يكلّف ساعة، والهجرة تكلّف ربع سنة.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي3
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.