Kodokon kodokon.com

نمذجة البيانات: التطبيع وإلغاء التطبيع

هيكِل مخطّطاتك من الصيغة العادية الأولى 1NF إلى الثالثة 3NF لإزالة الشذوذات، واعرف متى تُلغي التطبيع عن وعي كامل.

10 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

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

SQL
CREATE TABLE bad_orders (
  id INTEGER PRIMARY KEY,
  customer_name TEXT,
  customer_email TEXT,
  product_names TEXT,
  total REAL
);

INSERT INTO bad_orders
  (customer_name, customer_email,
   product_names, total)
VALUES
  ('Alice', 'alice@mail.com',
   'keyboard,mouse', 74.0),
  ('Alice', 'alice@mail.co',
   'monitor', 199.0);
قائمة في عمود واحد، وبريد إلكتروني مكرّر بخطأ مطبعي: كل شيء موجود هنا.

الصيغ العادية الثلاث الأولى، عمليًا. 1NF: قيم ذرّية - ينتهكها product_names = 'keyboard,mouse'، ما يجعل أي WHERE أو JOIN على المنتجات غير عملي. 2NF (مفتاح مركّب): يعتمد كل عمود على المفتاح بأكمله - إن تخزين سعر منتج من الكتالوج في سطر طلب مُعرَّف بـ (الطلب، المنتج) ينتهكها، لأن السعر يعتمد على المنتج وحده. 3NF: لا يعتمد أي عمود غير مفتاحي على عمود آخر غير مفتاحي - ينتهكها customer_email الذي يعتمد على customer_name؛ ومن هنا يأتي التكرار alice@mail.co. وإليك المخطّط المُصحَّح.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT NOT NULL UNIQUE
);

CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  price REAL NOT NULL
);

CREATE TABLE purchases (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL
    REFERENCES customers(id)
);

CREATE TABLE purchase_items (
  purchase_id INTEGER NOT NULL
    REFERENCES purchases(id),
  product_id INTEGER NOT NULL
    REFERENCES products(id),
  quantity INTEGER NOT NULL,
  PRIMARY KEY (purchase_id, product_id)
);
كل معطى يعيش في مكان واحد؛ والمفاتيح الخارجية تربط كل شيء معًا.
SQL
PRAGMA foreign_keys = ON;

INSERT INTO customers (name, email)
VALUES ('Alice', 'alice@mail.com');

INSERT INTO products (name, price)
VALUES ('keyboard', 49.0), ('mouse', 25.0);

INSERT INTO purchases (customer_id) VALUES (1);

INSERT INTO purchase_items
  (purchase_id, product_id, quantity)
VALUES (1, 1, 1), (1, 2, 1);

SELECT c.name, p.name AS product,
       i.quantity, p.price
FROM purchase_items AS i
JOIN purchases AS pu ON pu.id = i.purchase_id
JOIN customers AS c ON c.id = pu.customer_id
JOIN products AS p ON p.id = i.product_id;
يُعاد بناء التفصيل الكامل عبر عمليات الربط.

إذن، متى ينبغي أن تُلغي التطبيع؟ عندما تصبح عمليات القراءة عنق الزجاجة المقيس: عمليات ربط بين خمسة جداول على شاشة حسّاسة، أو تجميع يُعاد حسابه في كل عرض. الأنماط النزيهة: عمود تخزين مؤقت (purchases.total مُجمَّد وقت الطلب - وهو أمر مشروع: فالسعر المدفوع معطى تاريخي يختلف عن سعر الكتالوج)، أو عدّاد يحافظ عليه مُطلِق (trigger)، أو جدول تقارير يُعاد بناؤه دفعةً واحدة. الثمن الواجب دفعه: يمكن لكل نسخة أن تنحرف، وأصبح كودك، لا المحرّك، هو الذي يضمن الاتساق.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. عمود product_names الذي يحمل 'keyboard,mouse' ينتهك أي صيغة عادية؟
    • 1NF
    • 2NF
    • 3NF
  2. أي عَرَض يدل على انتهاك 3NF؟
    • مفتاح أساسي مكوّن من عمودين
    • عمود غير مفتاحي يعتمد على عمود آخر غير مفتاحي
    • جدول بلا فهرس ثانوي
  3. متى يكون إلغاء التطبيع مبرَّرًا؟
    • منذ مرحلة التصميم، لتوفير عمليات الربط المستقبلية
    • بعد القياس، على القراءات الحسّاسة، مع قبول خطر عدم الاتساق
    • أبدًا: يجب أن يبقى المخطّط في 3NF مهما كان