رقم الحلقة (18)
حسناً... هذا يكفي، أظن أن التجربة قد فشلت فشلاً ذريعاً؛ ليس هناك تفاعل على الإطلاق، باستثناء تساؤل الأخ robotic، هذا يلقنني درساً جديداً: لا تسأل! فقط قل ما لديك وانصرف، لا تحاول لعب دور الأستاذ، لأن أحداً لا يحب التمارين... الأخ محمد ندا: أنا سعيد بوجودك ثانيةً، تواضعك يخجلني، لكنني لا أحسب أنني قد أضيف شيئاً إلى من كان بمستواك... ربما من باب التذاكر بالعلم ليس إلا... الأخ robotic: سنرى بإذن الله معاً كيف أن التصميم النموذجي لفواتير الأصناف يحوي عدداً من الجداول أكثر من اثنين بأي حال... الأخ أبا رحمة: وإياكم جزى الله خيراً، تشرفت بوجودك...
رقم الفاتورة تاريخ الفاتورة اسم العميل هاتف العميل رقم الصنف اسم الصنف الكمية السعر الإجمالي
دعونا الآن نعود إلى تصميمنا السابق الذي أعدته في الأعلى من أجل سهولة الرجوع إليه. أشرت إلى أن من مشاكل هذا التصميم عدم القدرة أحياناً على حفظ بعض المعلومات في قاعدة البيانات. مثال على ذلك أنك يجب أن تنتظر حتى يشتري منك عميل شيئاً ما ويحصل على فاتورة لكي تستطيع تسجيل اسمه ورقم هاتفه، بغير ذلك تظل عاجزاً عن حفظ بيانات العميل لأنك لا يمكن أن تحفظ صفاً في هذا الجدول بغير رقم فاتورة ورقم صنف (تذكر أن هذين هما معاً المفتاح الأساسي للجدول، ولا يمكن تركهما خاليين). نفس الكلام ينطبق أيضاً على بيانات الأصناف. هذه مشكلة تتعلق بإضافة البيانات، دعنا نفحص مشاكل التعديل والحذف.
من الواضح طبعاً أننا نعاني هنا من التكرار حتى النخاع. الاسم الكامل للعميل ورقم هاتفه سيتكرران (تكراراً زائداً بدون فائدة إضافية) مع كل فاتورة جديدة، بل ومع كل صنف في الفاتورة. مرة أخرى، ليست المشكلة الكبرى هنا في مقدار مساحة الخزن المهدرة، وإنما في المشاكل التي قد تواجهها عند القيام ببعض العمليات على الجدول. مثلاً، لنفترض أن هاتف عميل قد تغير يوماً ما (احتمال وارد جداً)، يجب عليك الآن تغيير رقم الهاتف في عدد كبير من الصفوف وليس في صف واحد فقط، لأن رقم الهاتف يتكرر مع كل صنف في كل فاتورة. إن هذا يعني أكثر من مجرد القيام بعدد أكبر من عمليات التعديل، إنه يعني احتمال الوقوع في وضع inconsistency الذي تكلمنا عنه من قبل عند الحديث عن مشاكل نظام الملفات لو تذكر، وهو أن تجد رقم هاتف نفس العميل بقيمتين مختلفتين في مكانين مختلفين كنتيجة لتعديل بعض أماكن وجوده وعدم تعديل البعض الآخر. هذا قد يحدث لسبب أو لآخر، لكن النتيجة هي عدم الوثوق في مصداقية النظام في أحسن الأحوال. أما في الأسوأ، فهو عدم اكتشاف هذا الاختلاف أصلاً إلا متأخراً جداً. هذا النوع من الأخطاء يسمى أخطاء (أو شذوذ anomaly) التعديل.
كيف يمكن أن نواجه مشاكل عند حذف البيانات من مثل هذا التصميم؟ كما توقعت أنت وكنت على وشك أن تقول، ليست المشكلة الوحيدة هي في الانتباه لحذف عدد من الصفوف عند إرادة حذف فاتورة مثلاً، لكن هناك احتمالية فقد بيانات عميل عند حذف آخر فاتورة له، أو فقد بيانات صنف عند حذف آخر فاتورة ظهر فيها هذا الصنف. يسمى هذا النوع من الأخطاء بشذوذ الحذف delete anomaly. في قاعدة بيانات تحترم نفسها، لا ينبغي أن نجد مثل هذه الإشكاليات. ومن أجل التخلص منها، تم تأسيس قواعد التسوية، عبر تحديد عدد من الأشكال (السوية) التي ينبغي أن تكون الجداول فيها. يتم الوصول بالجداول إلى هذه الأشكال عبر تحقيق شروط معينة، كل شرط منها يوصلك إلى شكل سوي. وينبغي أن تمر على الشكل السوي الأول حتى تصل إلى الثاني، وهكذا.
هل تقول إنني قد نسيت شيئاً؟ أنت تقصد أنك تتوقع أن أعطيك التصميم الصحيح لمثالنا الذي أشبعته ركلاً ولكماً، أقصد نقداً وتخطيئاً... أنا لم أنس ذلك في الواقع، ولا أحاول تناسيه أيضاً، لا تنظر إلي هكذا، وإنما هذا هو موضوع التسوية أساساً، أن تسوي التصميم ليحقق الأشكال السوية التي أسرد منها هنا الأشكال الثلاثة الكافية عملياً، ثم نمر بإذن الله عليها بشيء من التفصيل.
افتراض أولي: البيانات في قاعدة البيانات مقسمة إلى جداول كل منها له مفتاح أساسي.
1. يكون الجدول في الشكل السوي الأول First Normal Form (1NF) إذا كانت قيم كل أعمدته ذرية atomic، ولم تكن هناك مجموعات مكررة من الأعمدة.
2. يكون الجدول في الشكل السوي الثاني Second Normal Form(2NF)إذا كان في الشكل السوي الأول، وكل الأعمدة غير المفتاحية معتمدة تماماً على كامل المفتاح الأساسي.
3. يكون الجدول في الشكل السوي الثالث Third Normal Form (3NF) إذا كان في الشكل السوي الثاني، وكل الأعمدة غير المفتاحية مستقلة بعضها عن بعض.
هناك من يقول الآن: كل هذه بديهيات! لكن مع ذلك، اسمحوا لي أن أثرثر قليلاً حول هذه البديهيات لأن هذا هو موضوع السلسلة على كل حال، ولا يمكن أن أكمل الحلقة في تقشير البطاطا مثلاً... من أجل ذلك سأتعرض بإذن الله للعديد من الأمثلة، فمن كان يجد ذلك مملاً، بإمكانه تجاوز الأمثلة اللاحقة لأنها مجرد تكرار لترسيخ المفهوم.
دعنا نعود إلى موضوع الفواتير مع الأصناف، ولنفترض أن طالباً مبتدئاً جداً (ربما في سنته الأولى) فكر ثم قدّر ثم جاء بالتصميم التالي لجدول الفواتير:
رقم الفاتورة تاريخ الفاتورة الصنف السعر الكمية الصنف السعر الكمية الصنف السعر الكمية
لأنه لاحظ أن هناك عدة أصناف في الفاتورة الواحدة، لكل منها سعر وكمية (تم اختصار بقية البيانات من أجل تبسيط النقاش ولكي يكفي عرض الصفحة). ينص شرط الشكل السوي الأول على أن مجموعات الأعمدة المكررة ممنوعة. المجموعة (الصنف، السعر، الكمية) هي مجموعة مكررة من الأعمدة، وعلى هذا فهي تكسر قاعدة الشكل السوي الأول. ما الخطأ في مثل هذا التصميم؟ لاحظ من فضلك أنك في هذا التصميم بين الإفراط والتفريط؛ أعني أنك تضع حداً اصطناعياً لعدد الأصناف في الفاتورة الواحدة، وما يدريك حتى لو حجزت مكاناً لعشرين صنفاً ألا يأتي من يشتري واحداً وعشرين صنفاً في فاتورة واحدة يوماً ما؟ ثم إن غالبية الفواتير لا تزيد عدد أصنافها عن بضع أصناف، مما يجعل كل هذا العدد المحجوز بلا معنى للغالبية العظمى من الفواتير. أمر آخر: القصد من تصميم قواعد البيانات في المقام الأول هو الوصول الفعال للمعلومة، وهذا أبعد ما يكون في تصميم كهذا. تخيل استعلاماً بسيطاً عن الكميات المباعة من صنف محدد. يجب عليك أن تكرر البحث عن الصنف ليس في كل الصفوف فحسب، بل وفي أكثر من حقل، لأن ذلك الصنف قد يظهر في أي حقل من الحقول الثلاثة. قاعدة الشكل السوي الأول تقضي على مثل هذه المشاكل.
ربما أنك تفكر الآن بأنه من المستبعد أن يأتي أحدهم ويضع مثل هذا التصميم، لكنني أحب أن أؤكد لك أنهم لم يأتوا بهذه القاعدة من الفراغ، وأنك ستجد دائماً من يصنع أشياء غريبة، ربما كان مبتدئاً وربما لم يكن مبتدئاً جداً. سأضرب لك الآن مثالاً آخر من المحتمل أنك رأيته في مكان ما. كتصميم لقاعدة بيانات طلاب تم اقتراح الجدول التالي (كالعادة، أكتفي بالحقول المعبرة لغرض المساحة):
رقم الطالب اسم الطالب مادة1 مادة2 مادة3 مادة4 مادة5 مادة6 مادة7
على اعتبار أن لكل فصل دراسي جدول كهذا بسرد مواد ذلك الفصل. هذا التصميم لا يأخذ بعين الاعتبار إمكانية تغيير المنهج وزيادة أو نقصان عدد المواد في وقت ما، وهو احتمال أكبر من الصفر بكل تأكيد، دع عنك أن هذا يتطلب عدة جداول لنفس البيانات أصلاً، لأن لكل فصل مواد مختلفة. لاحظ أن الأعمدة هنا هي أسماء المواد، فإذا حاولت إضافة بعض المرونة بتسجيل اسم كل مادة (أو رمزها) مع علامة الطالب كالتالي:
رقم الطالب اسم الطالب مادة علامة مادة علامة مادة علامة مادة علامة مادة علامة مادة علامة
فإن هذا يشبه بالضبط مثال أصناف الفواتير الأول، ويحمل نفس مشكلة الحدود الصناعية، ويكسر إلى أجزاء صغيرة قاعدة التسوية الأولى: لا مجموعات مكررة من الحقول.
مثال آخر لن يضر أحداً... بيانات كتاب في قاعدة بيانات مكتبة تشمل إلى جانب رقم وعنوان وعدد صفحات الكتاب وخلافه، ربما حقلاً لموضوع الكتاب أو تصنيفه (مثلاً برمجة، تصميم، إنترنت، قواعد بيانات...). المشكلة أن كتاباً واحداً ربما يتم تصنيفه تحت أكثر من موضوع. كتاب عن الأكسس مثلاً قد يصنف تحت قواعد البيانات وتحت البرمجة على سبيل المثال. ربما قدّر المصمم أن أي كتاب لا يمكن أن يصنف تحت أكثر من ثلاثة تصنيفات مختلفة ولذلك وضع التصميم التالي لجدول الكتب:
رقم الكتاب العنوان الطبعة سنة الطبعة عدد الصفحات عدد النسخ تصنيف1 تصنيف2 تصنيف3
أغلب الكتب لها تصنيف واحد فقط مما يعني فراغ مهدر، ومن الممكن أن أصنف كتاباً عن برمجة PHP مع MySQL على سبيل المثال تحت موضوع برمجة وقواعد بيانات وإنترنت ومصادر مفتوحة ولغات سكربت.
أمر آخر يعالجه الشكل السوي الأول، وإن كان احتمال مصادفته أقل. تنص قاعدة الشكل السوي الأول على أن كل حقل يجب أن تكون قيمته ذرية (ترجمة atomic، يجب أن تقبل ذلك). الفرض هنا أن الذرة غير قابلة للتقسيم، والمقصود أن في كل حقل (عمود) قيمة واحدة مفردة، لا مجموعة أو قائمة من القيم بأي شكل كان. مثلاً، في مثال جدول الكتب، قد يختار المصمم التصميم التالي:
رقم الكتاب العنوان الطبعة سنة الطبعة عدد الصفحات عدد النسخ التصنيفات
ثم يكتب في حقل التصنيفات شيئاً مثل: (برمجة، قواعد بيانات، إنترنت). تخيل أن المطلوب منك هو استعلام يجمع الكتب على حسب تصنيفاتها. سيكون هذا تمريناً ثقيلاً، لكنني لن أطلب ذلك، لا تقلق. مثال آخر لمثل هذا التصميم تخصيص حقل واحد للعنوان الذي يشمل المدينة والبلد على سبيل المثال.
الآن، وبعد أن عقدنا الأمور بما فيه الكفاية، كيف من الممكن تصحيح أمثال هذه الجداول لتحقق الشكل السوي الأول (لاحظ: لا أقول ليصبح تصميمها سليماً تماماً). نحن نسير في خطوات، ودائماً يتضمن الحل تقسيم الجدول إلى جداول أصغر من أجل التخلص من الإشكاليات. يسمى هذا التقسيم decomposition. في حالة متطلب (الذرية)، يمكن فصل القيم المتزاحمة في حقل واحد في حقول منفصلة، لكنك ستقع هنا في فخ مجموعات الأعمدة المتكررة. في هذه الحالة من الممكن تلافي هذا الخطأ بتحويل المجموعات المكررة أفقياً إلى مجموعات مكررة رأسياً. هذا يعني أن تحول المجموعات المكررة من أعمدة إلى صفوف. على سبيل المثال، في حالة الفواتير والأصناف، التصميم التالي يتخلص من مشكلة مجموعات الأعمدة المكررة:
رقم الفاتورة تاريخ الفاتورة الصنف الكمية السعر 000001 01/05/2009 صنف1 5 85 000001 01/05/2009 صنف2 1 300 000001 01/05/2009 صنف3 3 100
لاحظت التكرار؟ بالطبع، نحن لم نتخلص من كل المشاكل بعد، ما زلنا في الشكل السوي الأول. المهم أيضاً أن تلاحظ أن المفتاح الأساسي في هذا التصميم لا يمكن أن يكون رقم الفاتورة، لأسباب واضحة طبعاً، لذا من الممكن جعله مزيجاً من رقم الفاتورة والصنف. نفس الحل ينسحب على مثال المواد والكتب. يتم تعديل المفتاح الأساسي والتخلص من التكرار أفقياً إلى التكرار رأسياً.
أعلم أنني قد أثقلت عليك اليوم، لكن دعني أختم بمثال صديقنا العزيز محمد ندا. لقد وضع قبل شهر تقريباً ملفاً يحوي متطلبات بنك المتقدمين. كجزء من جدول المتقدمين نجد الحقول التالية كتصميم أولي (لاحظ أن المسرود في الملف هو المتطلبات وليس التصميم):
الاسم تاريخ الميلاد محل الميلاد العنوان التليفونات 1، 2، جوال المؤهل خبرة1 خبرة2 خبرة3 اللغات
إلى غيرها من الحقول التي تجدها في الملف (تعقيب ثانٍ على الحلقة رقم (11) في الصفحة الثالثة). أعلم أنك لم تكمل كلامك بعد من أن التمارين غير مستحبة على الإطلاق، لكن يبدو أنني من النوع الذي لا يتعلم بسرعة، وإني لأزعم أن لديك الآن ما يكفي من المعرفة (أو أنني أظن ذلك؟) لتكتشف كلا النوعين من أنواع الخروقات للشكل السوي الأول. سأبدأ بإذن الله الحلقة القادمة بالتعليق على هذا الأمر قبل الانتقال إلى الشكل السوي الثاني من أشكال التسوية. لا، لم أنس السؤال بالطبع، ترى: هل أنت...........؟
(يتبع إن شاء الله)...
تم تعديل هذه المشاركة بواسطة أحمد مبارك الحيقي في 1 يونيو 2009 في 00:32
