MySQL وتصميم قواعد البيانات

أفضل ممارسات تصميم قواعد البيانات

13 دقيقة الدرس 6 من 40

أفضل ممارسات تصميم قواعد البيانات

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

اصطلاحات التسمية

التسمية المتسقة تجعل قاعدة بياناتك موثقة ذاتياً وأسهل للصيانة:

أسماء الجداول: ✓ استخدم أحرف صغيرة مع شرطات سفلية (snake_case) ✓ أسماء جمع: users، orders، products ✓ وصفية وموجزة: order_items، وليس oi ✓ تجنب البادئات مثل tbl_ أمثلة: ✓ users ✓ order_items ✓ product_categories ❌ tblUser، Orders_Table، OI أسماء الأعمدة: ✓ استخدم أحرف صغيرة مع شرطات سفلية (snake_case) ✓ أسماء وصفية: first_name، وليس fname ✓ أعمدة منطقية: is_active، has_discount ✓ أعمدة التاريخ: created_at، updated_at، published_at أمثلة: ✓ first_name ✓ email_address ✓ is_published ✓ created_at ❌ fName، emailAddr، active، createDate المفتاح الأساسي: ✓ ببساطة "id" لمعظم الجداول ✓ INT UNSIGNED AUTO_INCREMENT ✓ بديل: table_name_id (مثل user_id) المفتاح الخارجي: ✓ استخدم اسم الجدول المشار إليه + _id ✓ user_id، product_id، category_id ✓ مؤشر علاقة واضح
الاتساق هو المفتاح: اختر اصطلاحاً واحداً (snake_case موصى به) والتزم به في جميع أنحاء قاعدة البيانات.

أنماط تصميم الجداول

أنماط شائعة تحل تحديات التصميم المتكررة:

1. نمط الطوابع الزمنية أضف created_at و updated_at لكل جدول CREATE TABLE posts ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200), content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); 2. نمط الحذف الناعم استخدم deleted_at بدلاً من حذف السجلات فيزيائياً CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255), deleted_at TIMESTAMP NULL -- NULL يعني غير محذوف ); -- الاستعلام عن السجلات النشطة فقط SELECT * FROM users WHERE deleted_at IS NULL; -- حذف ناعم لمستخدم UPDATE users SET deleted_at = NOW() WHERE id = 1; 3. نمط الحالة/الوضع استخدم ENUM للحالات المحددة جيداً CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending' ); 4. نمط جداول البحث للفئات المتغيرة بشكل متكرر CREATE TABLE order_statuses ( id INT PRIMARY KEY, name VARCHAR(50), description TEXT ); CREATE TABLE orders ( id INT PRIMARY KEY, status_id INT, FOREIGN KEY (status_id) REFERENCES order_statuses(id) );

الحذف الناعم مقابل الحذف الصعب

الحذف الصعب (دائم): DELETE FROM users WHERE id = 1; الإيجابيات: ✓ بسيط ومباشر ✓ يقلل حجم قاعدة البيانات ✓ إزالة بيانات حقيقية السلبيات: ❌ البيانات مفقودة بشكل دائم ❌ لا يمكن التراجع عن الأخطاء ❌ يكسر سلامة الإحالة ❌ يفقد البيانات التاريخية الحذف الناعم (وضع علامة كمحذوف): UPDATE users SET deleted_at = NOW() WHERE id = 1; الإيجابيات: ✓ قابل للاسترداد (التراجع عن الحذف) ✓ يحافظ على سلامة الإحالة ✓ يحفظ البيانات التاريخية ✓ مسار تدقيق متاح السلبيات: ❌ حجم قاعدة بيانات متزايد ❌ يجب تصفية السجلات المحذوفة في الاستعلامات ❌ يضيف تعقيداً متى تستخدم كلاً منهما: - الحذف الصعب: البيانات القابلة للتخلص حقاً (السجلات، البيانات المؤقتة) - الحذف الناعم: بيانات الأعمال المهمة (المستخدمون، الطلبات، المنتجات)
أفضل ممارسة: استخدم الحذف الناعم للمحتوى الذي ينشئه المستخدم وسجلات الأعمال الحرجة. استخدم الحذف الصعب لسجلات النظام والبيانات المؤقتة.

أنماط Created_at و Updated_at

التنفيذ القياسي: CREATE TABLE articles ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200), content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); الفوائد: ✓ تتبع تلقائي لوقت إنشاء السجل ✓ تتبع تلقائي لآخر وقت تعديل ✓ لا حاجة لمنطق التطبيق ✓ مفيد للفرز والتصفية والتدقيق أمثلة الاستعلام: -- المقالات التي تم إنشاؤها مؤخراً SELECT * FROM articles WHERE created_at > DATE_SUB(NOW(), INTERVAL 7 DAY) ORDER BY created_at DESC; -- المقالات المحدثة مؤخراً SELECT * FROM articles ORDER BY updated_at DESC LIMIT 10; -- المقالات التي لم يتم تحديثها أبداً SELECT * FROM articles WHERE created_at = updated_at;

UUID مقابل معرفات الزيادة التلقائية

INT الزيادة التلقائية (التقليدي): CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) ); الإيجابيات: ✓ بسيط وفعال ✓ تخزين صغير (4 بايت) ✓ متسلسل وقابل للفرز ✓ أداء فهرس سريع ✓ قابل للقراءة من قبل الإنسان السلبيات: ❌ قابل للتنبؤ (مصدر قلق أمني) ❌ المتسلسل يكشف معلومات الأعمال ❌ صعب في الأنظمة الموزعة ❌ خطر تصادم في عمليات الدمج UUID (معرف فريد عالمياً): CREATE TABLE users ( id CHAR(36) PRIMARY KEY DEFAULT (UUID()), -- MySQL 8.0+ name VARCHAR(100) ); -- مثال UUID: "550e8400-e29b-41d4-a716-446655440000" الإيجابيات: ✓ فريد عالمياً (بدون تصادمات) ✓ غير متسلسل (أكثر أماناً) ✓ رائع للأنظمة الموزعة ✓ يمكن إنشاؤه من جانب العميل ✓ عمليات دمج قاعدة بيانات سهلة السلبيات: ❌ تخزين أكبر (36 بايت كـ CHAR) ❌ فهرسة أبطأ ❌ غير قابل للقراءة من قبل الإنسان ❌ ترتيب عشوائي (يؤثر على تفتت الفهرس) التوصية: - استخدم INT AUTO_INCREMENT لمعظم الحالات - استخدم UUID لـ: أنظمة موزعة، واجهات برمجية عامة، معرفات حساسة للأمان - بديل: BIGINT مع خوارزمية Snowflake ID

العلاقات متعددة الأشكال

عندما يمكن لجدول واحد أن ينتمي إلى جداول أخرى متعددة:

السيناريو: التعليقات يمكن أن تكون على المقالات أو الفيديوهات ❌ حل ضعيف (FKs متعددة قابلة للـ null): CREATE TABLE comments ( id INT PRIMARY KEY, content TEXT, post_id INT NULL, video_id INT NULL ); -- المشكلة: غير واضح أيهما مستخدم، بدون قيد FK ✓ حل أفضل (نمط متعدد الأشكال): CREATE TABLE comments ( id INT PRIMARY KEY, content TEXT, commentable_type VARCHAR(50), -- 'post' أو 'video' commentable_id INT ); -- الاستعلام عن تعليقات لمقال محدد SELECT * FROM comments WHERE commentable_type = 'post' AND commentable_id = 1; ✓ أفضل حل (جداول منفصلة): CREATE TABLE post_comments ( id INT PRIMARY KEY, post_id INT, content TEXT, FOREIGN KEY (post_id) REFERENCES posts(id) ); CREATE TABLE video_comments ( id INT PRIMARY KEY, video_id INT, content TEXT, FOREIGN KEY (video_id) REFERENCES videos(id) ); المقايضات: - متعدد الأشكال: مرن لكن بدون قيود FK - جداول منفصلة: جداول أكثر لكن سلامة مفروضة - اختر بناءً على: تشابه البيانات وأنماط الاستعلام
مهم: العلاقات متعددة الأشكال تضحي بسلامة الإحالة من أجل المرونة. استخدمها فقط عندما تفوق الفائدة المخاطرة.

تصميم مخطط التجارة الإلكترونية الكامل

لنصمم قاعدة بيانات تجارة إلكترونية كاملة وجاهزة للإنتاج:

1. المستخدمون والمصادقة CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, password_hash CHAR(60) NOT NULL, first_name VARCHAR(50), last_name VARCHAR(50), phone VARCHAR(20), is_active BOOLEAN DEFAULT TRUE, email_verified_at TIMESTAMP NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, deleted_at TIMESTAMP NULL, INDEX idx_email (email), INDEX idx_active (is_active, deleted_at) ); 2. العناوين (واحد-إلى-متعدد مع المستخدمين) CREATE TABLE addresses ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL, address_type ENUM('billing', 'shipping', 'both') DEFAULT 'shipping', street_address VARCHAR(255) NOT NULL, city VARCHAR(100) NOT NULL, state VARCHAR(100), postal_code VARCHAR(20), country CHAR(2) DEFAULT 'US', is_default BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX idx_user (user_id) ); 3. فئات المنتجات CREATE TABLE categories ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, parent_id INT UNSIGNED NULL, -- للفئات المتداخلة name VARCHAR(100) NOT NULL, slug VARCHAR(100) UNIQUE NOT NULL, description TEXT, image_url VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, display_order INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (parent_id) REFERENCES categories(id) ON DELETE SET NULL, INDEX idx_parent (parent_id), INDEX idx_slug (slug) ); 4. المنتجات CREATE TABLE products ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, category_id INT UNSIGNED, sku VARCHAR(50) UNIQUE NOT NULL, name VARCHAR(200) NOT NULL, slug VARCHAR(200) UNIQUE NOT NULL, description TEXT, short_description VARCHAR(500), price DECIMAL(10,2) NOT NULL, compare_at_price DECIMAL(10,2), -- السعر الأصلي للخصومات cost DECIMAL(10,2), -- التكلفة للبائع stock_quantity INT UNSIGNED DEFAULT 0, weight_grams INT UNSIGNED, is_active BOOLEAN DEFAULT TRUE, is_featured BOOLEAN DEFAULT FALSE, image_url VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL, INDEX idx_category (category_id), INDEX idx_sku (sku), INDEX idx_slug (slug), INDEX idx_featured (is_featured, is_active) );

ميزات تصميم المخطط الرئيسية

أفضل الممارسات المطبقة: ✓ تسمية متسقة (snake_case) ✓ أنواع بيانات مناسبة (DECIMAL للمال، ENUM للحالة) ✓ طوابع زمنية على كل جدول (created_at، updated_at) ✓ حذف ناعم حيثما كان مناسباً (users) ✓ فهارس على المفاتيح الخارجية والأعمدة المستعلم عنها بشكل متكرر ✓ لقطة سعر المنتج في order_items (دقة تاريخية) ✓ فصل العناوين (عناوين قابلة لإعادة الاستخدام) ✓ قيود فريدة (email، SKU، order_number) ✓ علاقات مفاتيح خارجية صحيحة مع إجراءات ON DELETE ✓ قيم افتراضية للسيناريوهات الشائعة ✓ قيود فحص للتحقق من صحة البيانات (تقييم 1-5) ✓ دعم الفئات المتداخلة (parent_id) ✓ أعلام مميزة/نشطة للتصفية السهلة

تحدي التصميم:

أضف هذه الميزات إلى مخطط التجارة الإلكترونية:

  1. نظام رموز/كوبونات الخصم
  2. ميزة قائمة الرغبات
  3. متغيرات المنتج (الحجم، اللون)

تلميحات الحل:

1. رموز الخصم: CREATE TABLE coupons ( id INT PRIMARY KEY, code VARCHAR(50) UNIQUE, discount_type ENUM('percentage', 'fixed_amount'), discount_value DECIMAL(10,2), min_purchase_amount DECIMAL(10,2), max_uses INT, used_count INT DEFAULT 0, valid_from TIMESTAMP, valid_until TIMESTAMP ); 2. قائمة الرغبات: CREATE TABLE wishlist_items ( id INT PRIMARY KEY, user_id INT, product_id INT, created_at TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (product_id) REFERENCES products(id), UNIQUE (user_id, product_id) ); 3. متغيرات المنتج: CREATE TABLE product_variants ( id INT PRIMARY KEY, product_id INT, sku VARCHAR(50) UNIQUE, option1_name VARCHAR(50), -- مثلاً "الحجم" option1_value VARCHAR(50), -- مثلاً "كبير" option2_name VARCHAR(50), -- مثلاً "اللون" option2_value VARCHAR(50), -- مثلاً "أحمر" price DECIMAL(10,2), stock_quantity INT, FOREIGN KEY (product_id) REFERENCES products(id) );

الملخص

في هذا الدرس، تعلمت:

  • استخدم تسمية snake_case متسقة للجداول والأعمدة
  • أضف طوابع زمنية created_at و updated_at لكل جدول
  • استخدم حذف ناعم لبيانات الأعمال المهمة، حذف صعب للبيانات القابلة للتخلص
  • INT AUTO_INCREMENT للمعرفات في معظم الحالات، UUID للأنظمة الموزعة
  • العلاقات متعددة الأشكال تضحي بسلامة الإحالة من أجل المرونة
  • التقط بيانات مهمة (الأسعار، أسماء المنتجات) في سجلات الطلب
  • استخدم أنواع بيانات مناسبة: DECIMAL للمال، ENUM للحالة
  • أضف فهارس على المفاتيح الخارجية والأعمدة المستعلم عنها بشكل متكرر
الوحدة مكتملة! لقد أكملت الوحدة 1: مبادئ تصميم قواعد البيانات. لديك الآن أساس متين في تصميم قاعدة البيانات، والتطبيع، وأنواع البيانات، وأفضل الممارسات. التالي، سنغوص في الاستعلامات المتقدمة!

ES
Edrees Salih
منذ 13 ساعة

We are still cooking the magic in the way!