العروض والفهارس
العروض والفهارس
تخيل أنك تقترض الكتب من المكتبة بشكل متكرر. هناك طريقتان للعثور على كتاب: الأولى هي البحث عبر كل رف في كل مرة (مسح الجدول بالكامل)؛ والثانية هي التحقق من فهرس بطاقات الكتالوج أولاً والذهاب مباشرة إلى الرف الصحيح (استعلام الفهرس). "قائمة القراءة الموصى بها" في المكتبة تشبه العرض — ليست رفًا حقيقيًا، بل قائمة منتقاة من كتب من أرفف مختلفة، مما يسهل العثور على ما تريد. تعمل العروض والفهارس في SQL بنفس الطريقة.
1. المفاهيم الأساسية
العرض — المفهوم
العرض هو جدول افتراضي لا يخزن البيانات بل يحفظ عبارة استعلام SELECT. في كل مرة تقوم بالوصول إلى العرض، ينفذ قاعدة البيانات استعلام تعريف العرض ويعيد النتائج.
-- إنشاء عرض: عرض معلومات الموظفين
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;
استخدام العرض تمامًا مثل استخدام جدول عادي:
-- الاستعلام عن العرض
SELECT * FROM v_employee_info WHERE salary > 10000;
إنشاء العروض
CREATE VIEW view_name AS
SELECT statement;
-- إنشاء عرض إحصائيات الأقسام
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;
تعديل العروض
-- الطريقة 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;
حذف العروض
DROP VIEW IF EXISTS v_employee_info;
مزايا العروض
| الميزة | الوصف |
|---|---|
| تبسيط الاستعلامات المعقدة | تغليف JOINs المعقدة كعروض؛ استخدامها ببساطة عبر SELECT * FROM view_name |
| أمان البيانات | عرض أعمدة أو صفوف محددة للمستخدمين، وإخفاء البيانات الحساسة |
| الاستقلال المنطقي | تعديل تعريفات العروض لا يؤثر على التطبيقات التي تستخدم العرض |
| منطق متسق | ضمان استخدام جميع المستخدمين نفس منطق الاستعلام، وتجنب التكرار |
عيوب العروض
| العيب | الوصف |
|---|---|
| أداء إضافي | كل وصول يتطلب تنفيذ الاستعلام الأساسي؛ قد تكون العروض المعقدة بطيئة |
| قيود التحديث | العروض التي تحتوي على JOINs أو دوال تجميعية أو DISTINCT عادةً غير قابلة للتحديث |
| صعوبة التصحيح | العروض المتداخلة متعددة الطبقات تزيد من صعوبة استكشاف الأخطاء |
الفهرس — المفهوم
الفهرس هو هيكل بيانات، مشابه لجدول محتويات الكتاب، يساعد قاعدة البيانات على تحديد موقع البيانات بسرعة وتجنب مسح الجدول بالكامل.
-- بدون فهرس: مسح الجدول بالكامل (بحث صف بصف)
SELECT * FROM employees WHERE last_name = 'Zhang';
-- مع فهرس: بحث مباشر (عبر الفهرس)
CREATE INDEX idx_last_name ON employees(last_name);
SELECT * FROM employees WHERE last_name = 'Zhang';
إنشاء الفهارس
-- فهرس عادي (يسمح بقيم مكررة)
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);
حذف الفهارس
-- صيغة MySQL
DROP INDEX idx_column ON table_name;
-- الصيغة المعيارية
ALTER TABLE table_name DROP INDEX idx_column;
أنواع الفهارس
| النوع | الكلمة المفتاحية | الوصف | حالة الاستخدام |
|---|---|---|---|
| فهرس عادي | INDEX |
فهرس أساسي، يسمح بقيم مكررة | أعمدة الاستعلام المتكرر |
| فهرس فريد | UNIQUE INDEX |
يجب أن تكون قيم العمود فريدة | البريد الإلكتروني، أرقام الهوية، إلخ |
| فهرس نصي كامل | FULLTEXT INDEX |
يدعم البحث النصي الكامل | محتوى المقالات، أوصاف المنتجات |
| فهرس مركب | INDEX(col1, col2) |
فهرس تركيبة أعمدة متعددة | استعلامات الشروط المتعددة |
الفهرس المركب وقاعدة أقصى يسار
تتبع الفهارس المركبة قاعدة أقصى يسار: يجب أن تتطابق شروط الاستعلام من العمود الأيسر للفهرس لاستخدامه.
-- إنشاء فهرس مركب
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. الصيغة الأساسية
صيغة العروض
-- إنشاء عرض
CREATE [OR REPLACE] VIEW view_name AS SELECT statement;
-- الاستعلام عن العرض (مثل الجدول العادي)
SELECT * FROM view_name WHERE condition;
-- حذف عرض
DROP VIEW [IF EXISTS] view_name;
v_ أو view_ لتمييزها بسهولة عن الجداول الحقيقية.
صيغة الفهارس
-- إنشاء فهرس
CREATE [UNIQUE|FULLTEXT] INDEX index_name ON table_name(column1, column2, ...);
-- حذف فهرس
DROP INDEX index_name ON table_name;
-- عرض فهارس جدول
SHOW INDEX FROM table_name;
EXPLAIN للتحقق مما إذا كان الاستعلام يستخدم فهرسًا: EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';
مثال: إنشاء واستخدام العروض (الصعوبة ⭐)
-- إنشاء عرض تفاصيل الطلبات
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';
الناتج:
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
-- استخدام العرض لتجميع مبالغ الطلبات حسب القسم
SELECT department, COUNT(*) AS order_count, SUM(amount) AS total_amount
FROM v_order_detail
GROUP BY department;
نهج الاستعلام:
- يغلف العرض منطق JOIN الثلاثي الجداول المعقد
- لا حاجة سوى لاستعلامات بسيطة — لا حاجة لإعادة كتابة JOIN
- تتحدث نتائج العرض تلقائيًا مع تغير البيانات الأساسية
مثال: إنشاء فهارس لتحسين أداء الاستعلام (الصعوبة ⭐⭐)
-- عرض خطة تنفيذ الاستعلام الحالي
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';
الناتج (بدون فهرس):
+----+-------------+-----------+------+---------------+------+---------+------+------+-------+
| 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 يشير إلى مسح جميع الصفوف.
-- إنشاء فهرس
CREATE INDEX idx_last_name ON employees(last_name);
-- عرض خطة التنفيذ مرة أخرى
EXPLAIN SELECT * FROM employees WHERE last_name = 'Zhang';
الناتج (مع فهرس):
+----+-------------+-----------+------+---------------+---------------+---------+-------+------+-------+
| 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 يشير إلى مسح صف واحد فقط.
-- إنشاء فهرس مركب
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;
نهج الاستعلام:
- عمود
typeفي EXPLAIN:ALL(مسح الجدول بالكامل) →ref(مرجع الفهرس) يشير إلى تحسن الأداء - عمود
rows: كلما قل عدد الصفوف الممسوحة كان أفضل - يجب استخدام الفهارس المركبة وفقًا لقاعدة أقصى يسار
3. سيناريوهات التطبيق الشائعة
السيناريو 1: تبسيط إدارة الأذونات باستخدام العروض
-- إنشاء عرض يحتوي فقط على معلومات غير حساسة
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: تنفيذ تقارير البيانات باستخدام العروض
-- إنشاء عرض تقرير المبيعات الشهري
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;
الناتج:
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(مسح الجدول بالكامل، الأبطأ) →index→range→ref→eq_ref→const(الأسرع). إذا كانtypeهوALLوالجدول يحتوي على كمية كبيرة من البيانات، فقد يكون هناك حاجة إلى فهرس.
📖 ملخص
- العروض هي جداول افتراضية تحفظ استعلامات SELECT، لا تخزن البيانات، وتبقى دائمًا متزامنة مع الجداول الأساسية
- يمكن للعروض تبسيط الاستعلام المعقد، والتحكم في الوصول إلى البيانات، وتوحيد منطق الاستعلام
- العروض التي تحتوي على JOINs/التجميع/DISTINCT عادةً غير قابلة للتحديث
- الفهارس هي "جدول المحتويات" لقاعدة البيانات — تسرّع الاستعلامات لكنها تضيف تكلفة تخزين وكتابة
- أنواع الفهارس: فهرس عادي، فهرس فريد، فهرس نصي كامل، فهرس مركب
- قاعدة أقصى يسار: يجب أن تتطابق استعلامات الفهرس المركب من العمود الأيسر
- استخدم
EXPLAINلتحليل ما إذا كان الاستعلام يستخدم فهرسًا
📝 تمارين
التمرين 1 (⭐): أنشئ عرض v_high_salary يعرض معلومات الموظف (الاسم، الراتب، اسم القسم) للموظفين الذين رواتبهم أعلى من 10000، ثم استخدم العرض للاستعلام عن الموظفين ذوي الرواتب المرتفعة في قسم "التكنولوجيا".
التمرين 2 (⭐⭐): أنشئ عرض v_department_report يحتوي على اسم القسم، وعدد الموظفين، ومتوسط الراتب، وأعلى راتب، وأقل راتب. ثم استخدم العرض لإيجاد القسم الذي لديه أعلى متوسط راتب.
التمرين 3 (⭐⭐): أنشئ فهرسًا على عمود customer_id في جدول orders، واستخدم EXPLAIN لمقارنة أداء الاستعلام قبل وبعد إنشاء الفهرس. ثم أنشئ فهرسًا مركبًا على orders(status, order_date) واختبر أي الاستعلامات يمكنها استخدامه.
الدرس التالي
👉 18-practice-aggregate - تطبيق: تحليل البيانات: طبّق الدوال التجميعية، واستعلامات التجميع، والتعبيرات الشرطية، والدوال المتقدمة معًا لتحسين مهارات تحليل البيانات من خلال سيناريوهات عملية!



