العروض والفهارس

العروض والفهارس

تخيل أنك تقترض الكتب من المكتبة بشكل متكرر. هناك طريقتان للعثور على كتاب: الأولى هي البحث عبر كل رف في كل مرة (مسح الجدول بالكامل)؛ والثانية هي التحقق من فهرس بطاقات الكتالوج أولاً والذهاب مباشرة إلى الرف الصحيح (استعلام الفهرس). "قائمة القراءة الموصى بها" في المكتبة تشبه العرض — ليست رفًا حقيقيًا، بل قائمة منتقاة من كتب من أرفف مختلفة، مما يسهل العثور على ما تريد. تعمل العروض والفهارس في SQL بنفس الطريقة.


1. المفاهيم الأساسية

العرض — المفهوم

العرض هو جدول افتراضي لا يخزن البيانات بل يحفظ عبارة استعلام SELECT. في كل مرة تقوم بالوصول إلى العرض، ينفذ قاعدة البيانات استعلام تعريف العرض ويعيد النتائج.

SQL
-- إنشاء عرض: عرض معلومات الموظفين
CREATE VIEW v_employee_info AS
SELECT 
    e.employee_id,
    CONCAT(e.first_name, e.last_name) AS name,
    e.salary,
    d.department_name AS department,
    d.city
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

استخدام العرض تمامًا مثل استخدام جدول عادي:

SQL
-- الاستعلام عن العرض
SELECT * FROM v_employee_info WHERE salary > 10000;

إنشاء العروض

SQL
CREATE VIEW view_name AS
SELECT statement;
SQL
-- إنشاء عرض إحصائيات الأقسام
CREATE VIEW v_department_stats AS
SELECT 
    d.department_id,
    d.department_name AS department,
    COUNT(e.employee_id) AS employee_count,
    AVG(e.salary) AS avg_salary,
    SUM(e.salary) AS total_salary
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;

تعديل العروض

SQL
-- الطريقة 1: CREATE OR REPLACE (مُوصى بها)
CREATE OR REPLACE VIEW v_employee_info AS
SELECT 
    e.employee_id,
    CONCAT(e.first_name, e.last_name) AS name,
    e.salary,
    e.hire_date,
    d.department_name AS department
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

-- الطريقة 2: ALTER VIEW
ALTER VIEW v_employee_info AS
SELECT employee_id, first_name, last_name, salary FROM employees;

حذف العروض

SQL
DROP VIEW IF EXISTS v_employee_info;
💡 نصيحة: حذف العرض لا يؤثر على بيانات الجدول الأساسي — العرض مجرد "اختصار" لاستعلام.

مزايا العروض

الميزة الوصف
تبسيط الاستعلامات المعقدة تغليف JOINs المعقدة كعروض؛ استخدامها ببساطة عبر SELECT * FROM view_name
أمان البيانات عرض أعمدة أو صفوف محددة للمستخدمين، وإخفاء البيانات الحساسة
الاستقلال المنطقي تعديل تعريفات العروض لا يؤثر على التطبيقات التي تستخدم العرض
منطق متسق ضمان استخدام جميع المستخدمين نفس منطق الاستعلام، وتجنب التكرار

عيوب العروض

العيب الوصف
أداء إضافي كل وصول يتطلب تنفيذ الاستعلام الأساسي؛ قد تكون العروض المعقدة بطيئة
قيود التحديث العروض التي تحتوي على JOINs أو دوال تجميعية أو DISTINCT عادةً غير قابلة للتحديث
صعوبة التصحيح العروض المتداخلة متعددة الطبقات تزيد من صعوبة استكشاف الأخطاء
💡 نصيحة: لا تخزن العروض البيانات بنفسها — هي "أسماء مستعارة للاستعلام." عندما تتغير بيانات الجدول الأساسي، تتغير نتائج العرض accordingly.


الفهرس — المفهوم

الفهرس هو هيكل بيانات، مشابه لجدول محتويات الكتاب، يساعد قاعدة البيانات على تحديد موقع البيانات بسرعة وتجنب مسح الجدول بالكامل.

SQL
-- بدون فهرس: مسح الجدول بالكامل (بحث صف بصف)
SELECT * FROM employees WHERE last_name = 'Zhang';

-- مع فهرس: بحث مباشر (عبر الفهرس)
CREATE INDEX idx_last_name ON employees(last_name);
SELECT * FROM employees WHERE last_name = 'Zhang';

إنشاء الفهارس

SQL
-- فهرس عادي (يسمح بقيم مكررة)
CREATE INDEX idx_column ON table_name(column_name);

-- فهرس فريد (لا يسمح بقيم مكررة)
CREATE UNIQUE INDEX idx_column ON table_name(column_name);

-- فهرس نصي كامل (للبحث النصي الكامل)
CREATE FULLTEXT INDEX idx_column ON table_name(column_name);

-- فهرس مركب (تركيبة أعمدة متعددة)
CREATE INDEX idx_columns ON table_name(column1, column2);

حذف الفهارس

SQL
-- صيغة MySQL
DROP INDEX idx_column ON table_name;

-- الصيغة المعيارية
ALTER TABLE table_name DROP INDEX idx_column;

أنواع الفهارس

النوع الكلمة المفتاحية الوصف حالة الاستخدام
فهرس عادي INDEX فهرس أساسي، يسمح بقيم مكررة أعمدة الاستعلام المتكرر
فهرس فريد UNIQUE INDEX يجب أن تكون قيم العمود فريدة البريد الإلكتروني، أرقام الهوية، إلخ
فهرس نصي كامل FULLTEXT INDEX يدعم البحث النصي الكامل محتوى المقالات، أوصاف المنتجات
فهرس مركب INDEX(col1, col2) فهرس تركيبة أعمدة متعددة استعلامات الشروط المتعددة

الفهرس المركب وقاعدة أقصى يسار

تتبع الفهارس المركبة قاعدة أقصى يسار: يجب أن تتطابق شروط الاستعلام من العمود الأيسر للفهرس لاستخدامه.

SQL
-- إنشاء فهرس مركب
CREATE INDEX idx_name_age ON employees(last_name, first_name, salary);

-- ✅ يمكن استخدام الفهرس (يطابق العمود الأيسر)
SELECT * FROM employees WHERE last_name = 'Zhang';
SELECT * FROM employees WHERE last_name = 'Zhang' AND first_name = 'Wei';

-- ❌ لا يمكن استخدام الفهرس (يتخطى العمود الأيسر)
SELECT * FROM employees WHERE first_name = 'Wei';
SELECT * FROM employees WHERE salary > 10000;
💡 نصيحة: عند تصميم الفهارس المركبة، ضع الأعمدة الأكثر استخدامًا في الاستعلامات على اليسار.

تكلفة الفهارس

التكلفة الوصف
مساحة التخزين تتطلب الفهارس مساحة قرص إضافية
أداء الكتابة INSERT/UPDATE/DELETE تحتاج إلى تحديث الفهارس đồng bộ
تكلفة الصيانة الكثير من الفهارس تقلل سرعة الكتابة
💡 نصيحة: المزيد ليس أفضل! أنشئ فهارس فقط للأعمدة التي يتم استعلامها بشكل متكرر ولها حجم بيانات كبير. الجداول الصغيرة (بضع مئات من الصفوف) عادةً لا تحتاج إلى فهارس.


2. الصيغة الأساسية

صيغة العروض

SQL
-- إنشاء عرض
CREATE [OR REPLACE] VIEW view_name AS SELECT statement;

-- الاستعلام عن العرض (مثل الجدول العادي)
SELECT * FROM view_name WHERE condition;

-- حذف عرض
DROP VIEW [IF EXISTS] view_name;
💡 نصيحة: يُوصى بتسمية العروض ببادئة v_ أو view_ لتمييزها بسهولة عن الجداول الحقيقية.

صيغة الفهارس

SQL
-- إنشاء فهرس
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(column1, column2, ...);

-- حذف فهرس
DROP INDEX index_name ON table_name;

-- عرض فهارس جدول
SHOW INDEX FROM table_name;
💡 نصيحة: المفاتيح الأساسية (PRIMARY KEY) وقيود التفرد (UNIQUE) تنشئ فهارس تلقائيًا — لا حاجة للإنشاء اليدوي.

💡 نصيحة: استخدم EXPLAIN للتحقق مما إذا كان الاستعلام يستخدم فهرسًا: EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';


مثال: إنشاء واستخدام العروض (الصعوبة ⭐)

SQL
-- إنشاء عرض تفاصيل الطلبات
CREATE OR REPLACE VIEW v_order_detail AS
SELECT 
    o.order_id,
    CONCAT(e.first_name, e.last_name) AS owner,
    d.department_name AS department,
    o.order_date,
    o.total_amount AS amount,
    o.status
FROM orders o
LEFT JOIN employees e ON o.employee_id = e.employee_id
LEFT JOIN departments d ON e.department_id = d.department_id;

-- الاستعلام باستخدام العرض
SELECT * FROM v_order_detail WHERE status = 'completed';
▶ جرّب الكود

الناتج:

TEXT
order_id | owner      | department | order_date | amount   | status
---------+------------+------------+------------+----------+-----------
    1001 | WangQiang  | Sales      | 2026-05-10 | 2500.00  | completed
    1002 | WangQiang  | Sales      | 2026-05-15 | 1800.00  | completed
    1005 | ZhaoMin    | Sales      | 2026-06-10 | 4100.00  | completed
SQL
-- استخدام العرض لتجميع مبالغ الطلبات حسب القسم
SELECT department, COUNT(*) AS order_count, SUM(amount) AS total_amount
FROM v_order_detail
GROUP BY department;

نهج الاستعلام:

  1. يغلف العرض منطق JOIN الثلاثي الجداول المعقد
  2. لا حاجة سوى لاستعلامات بسيطة — لا حاجة لإعادة كتابة JOIN
  3. تتحدث نتائج العرض تلقائيًا مع تغير البيانات الأساسية

مثال: إنشاء فهارس لتحسين أداء الاستعلام (الصعوبة ⭐⭐)

SQL
-- عرض خطة تنفيذ الاستعلام الحالي
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';
▶ جرّب الكود

الناتج (بدون فهرس):

TEXT
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+

يشير type = ALL إلى مسح الجدول بالكامل، و rows = 6 يشير إلى مسح جميع الصفوف.

SQL
-- إنشاء فهرس
CREATE INDEX idx_last_name ON employees(last_name);

-- عرض خطة التنفيذ مرة أخرى
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';

الناتج (مع فهرس):

TEXT
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+
| id | select_type | table     | type | possible_keys | key           | key_len | ref   | rows | Extra |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+
|  1 | SIMPLE      | employees | ref  | idx_last_name | idx_last_name | 152     | const |    1 |       |
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+

يشير type = ref إلى استخدام الفهرس، و rows = 1 يشير إلى مسح صف واحد فقط.

SQL
-- إنشاء فهرس مركب
CREATE INDEX idx_status_date ON orders(status, order_date);

-- استعلام يمكنه استخدام الفهرس
EXPLAIN SELECT * FROM orders WHERE status = 'completed' AND order_date > '2026-06-01';

-- عرض جميع الفهارس على جدول
SHOW INDEX FROM employees;

نهج الاستعلام:

  1. عمود type في EXPLAIN: ALL (مسح الجدول بالكامل) → ref (مرجع الفهرس) يشير إلى تحسن الأداء
  2. عمود rows: كلما قل عدد الصفوف الممسوحة كان أفضل
  3. يجب استخدام الفهارس المركبة وفقًا لقاعدة أقصى يسار

3. سيناريوهات التطبيق الشائعة

السيناريو 1: تبسيط إدارة الأذونات باستخدام العروض

SQL
-- إنشاء عرض يحتوي فقط على معلومات غير حساسة
CREATE OR REPLACE VIEW v_employee_public AS
SELECT 
    employee_id,
    CONCAT(first_name, last_name) AS name,
    d.department_name AS department
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;

-- المستخدمون العاديون يمكنهم الوصول إلى هذا العرض فقط، وليس الراتب أو معلومات حساسة أخرى
SELECT * FROM v_employee_public;
💡 النهج: استبعد الأعمدة الحساسة (مثل الراتب، البريد الإلكتروني) من العرض وسيطر على الوصول إلى البيانات من خلال العرض.

السيناريو 2: تنفيذ تقارير البيانات باستخدام العروض

SQL
-- إنشاء عرض تقرير المبيعات الشهري
CREATE OR REPLACE VIEW v_monthly_sales AS
SELECT 
    DATE_FORMAT(order_date, '%Y-%m') AS month,
    COUNT(*) AS order_count,
    SUM(total_amount) AS total_sales,
    AVG(total_amount) AS avg_order_amount,
    COUNT(DISTINCT customer_id) AS customer_count
FROM orders
WHERE status != 'cancelled'
GROUP BY DATE_FORMAT(order_date, '%Y-%m');

-- الاستعلام عن التقرير
SELECT * FROM v_monthly_sales ORDER BY month;

الناتج:

TEXT
month   | order_count | total_sales | avg_order_amount | customer_count
--------+-------------+-------------+------------------+---------------
2026-05 |           2 |     4300.00 |          2150.00 |              2
2026-06 |           3 |     8250.00 |          2750.00 |              3

❓ أسئلة شائعة

س: ما الفرق بين العرض والجدول المؤقت? ج: لا تخزن العروض البيانات — كل استعلام ينفذ SQL الأساسي، لذا تكون النتائج دائمًا محدثة؛ الجداول المؤقتة تخزن لقطات البيانات، مما يوفر استعلامات أسرع ولكن بيانات قد تكون قديمة. العروض مناسبة لقوالب الاستعلام طويلة الأجل، بينما الجداول المؤقتة مناسبة لخطوات الحساب الوسيطة.

س: هل يمكن للعروض تعديل البيانات? ج: يعتمد على تعريف العرض. العروض التي تحتوي على JOINs أو دوال تجميعية أو DISTINCT أو استعلامات فرعية عادةً غير قابلة للتحديث (SELECT فقط). العروض البسيطة ذات الجدول الواحد (بدون تجميع) يمكن تحديثها باستخدام UPDATE. عمليًا، تُستخدم العروض بشكل أساسي للاستعلام — لا يُوصى بتعديل البيانات من خلال العروض.

س: هل المزيد من الفهارس دائمًا أفضل? ج: لا. تستهلك الفهارس مساحة التخزين وتقلل أداء INSERT/UPDATE/DELETE. أنشئ فهارس فقط للأعمدة التي يتم استعلامها بشكل متكرر ولها تعددية عالية (قيم متميزة كثيرة). الجداول الصغيرة عادةً لا تحتاج إلى فهارس.

س: كيف أعرف ما إذا كان الاستعلام يستخدم فهرسًا? ج: استخدم أمر EXPLAIN لعرض خطة التنفيذ. ركز على عمود type: ALL (مسح الجدول بالكامل، الأبطأ) → indexrangerefeq_refconst (الأسرع). إذا كان type هو ALL والجدول يحتوي على كمية كبيرة من البيانات، فقد يكون هناك حاجة إلى فهرس.


📖 ملخص


📝 تمارين

التمرين 1 (⭐): أنشئ عرض v_high_salary يعرض معلومات الموظف (الاسم، الراتب، اسم القسم) للموظفين الذين رواتبهم أعلى من 10000، ثم استخدم العرض للاستعلام عن الموظفين ذوي الرواتب المرتفعة في قسم "التكنولوجيا".

التمرين 2 (⭐⭐): أنشئ عرض v_department_report يحتوي على اسم القسم، وعدد الموظفين، ومتوسط الراتب، وأعلى راتب، وأقل راتب. ثم استخدم العرض لإيجاد القسم الذي لديه أعلى متوسط راتب.

التمرين 3 (⭐⭐): أنشئ فهرسًا على عمود customer_id في جدول orders، واستخدم EXPLAIN لمقارنة أداء الاستعلام قبل وبعد إنشاء الفهرس. ثم أنشئ فهرسًا مركبًا على orders(status, order_date) واختبر أي الاستعلامات يمكنها استخدامه.


الدرس التالي

👉 18-practice-aggregate - تطبيق: تحليل البيانات: طبّق الدوال التجميعية، واستعلامات التجميع، والتعبيرات الشرطية، والدوال المتقدمة معًا لتحسين مهارات تحليل البيانات من خلال سيناريوهات عملية!

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%