PostgreSQL: طرق العرض وطرق العرض المادية في PostgreSQL
آخر تحديث: 2026-08-26
1. ما ستتعلمه
- CREATE VIEW / ALTER VIEW / DROP VIEW
- طرق العرض القابلة للتحديث (طرق العرض البسيطة تدعم INSERT/UPDATE/DELETE)
- WITH CHECK OPTION لمنع الصفوف من الهروب من طريقة العرض
- طرق العرض المادية (MATERIALIZED VIEW) — ميزة خاصة بـ PostgreSQL
- REFRESH MATERIALIZED VIEW / CONCURRENTLY
- الاختيار بين طرق العرض وطرق العرض المادية والجداول المؤقتة
2. القصة
Alice هي مهندسة بيانات في منصة تجارة إلكترونية. فريق العمليات يراجع تقرير ملخص المبيعات كل يوم في الساعة 8:00، والذي يضم 5 جداول، ويجمع 3 ملايين سجل طلب، ويستغرق ساعتين للاستعلام.
قال رئيسها: "هل يمكن أن يعود التقرير فورياً؟"
عرّفت Alice الاستعلام كـ طريقة عرض مادية، تُحدث تلقائياً كل يوم في الساعة 4:00 صباحاً. استعلام التقرير المحسوب مسبقاً انخفض من ساعتين إلى 3 ثوانٍ. لكن بيانات طريقة العرض المادية ليست فورية — هذه هي المقايضة بين طرق العرض العادية وطرق العرض المادية.
3. المفهوم: طرق العرض العادية
(1) صيغة CREATE VIEW
CREATE [OR REPLACE] VIEW view_name [(column_aliases)] AS
SELECT ...;
طريقة العرض هي تعريف استعلام مخزن — لا تخزن بيانات. كل مرة تستعلم طريقة عرض، تقوم PostgreSQL بتوسيع (إعادة كتابة) تعريف طريقة العرض إلى الاستعلام الأساسي وتنفيذه.
| الخاصية | الوصف |
|---|---|
| ما يُخزن | نص الاستعلام فقط |
| حداثة البيانات | فورية، تعكس دائماً أحدث بيانات الجدول الأساسي |
| الأداء | نفس تنفيذ الاستعلام الأساسي مباشرة |
| المساحة المستخدمة | لا شيء تقريباً |
(1) ▶ مثال
CREATE VIEW v_daily_sales AS
SELECT
order_date,
region,
COUNT(*) AS order_count,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_order_value
FROM orders
GROUP BY order_date, region;
Output:
count
-------
5
(1 row)
(2) ▶ مثال
SELECT * FROM v_daily_sales
WHERE order_date >= '2025-01-01'
ORDER BY total_revenue DESC;
Output:
id | name | value
----+----------+-------
1 | example | 42
(1 row)
مكافئ لكتابة SELECT الأساسي مباشرة — PostgreSQL توسعه تلقائياً.
(2) ALTER VIEW و DROP VIEW
| العملية | الصيغة | الوصف |
|---|---|---|
| إعادة تسمية | ALTER VIEW v RENAME TO v_new |
إعادة تسمية طريقة العرض |
| تعيين عمود افتراضي | ALTER VIEW v ALTER COLUMN c SET DEFAULT d |
تغيير افتراضي عمود |
| تعيين المالك | ALTER VIEW v OWNER TO role |
تغيير المالك |
| حذف | DROP VIEW [IF EXISTS] v [CASCADE] |
CASCADE يحذف طرق العرض التابعة |
(3) ▶ مثال
ALTER VIEW v_daily_sales RENAME TO v_daily_summary;
DROP VIEW IF EXISTS v_daily_summary CASCADE;
Output:
-- SQL statement executed successfully
(3) آلية توسيع طريقة العرض
flowchart LR
A["SELECT * FROM v_daily_sales"] --> B["إعادة كتابة<br/>توسيع تعريف طريقة العرض"]
B --> C["SELECT order_date, region, COUNT(*)...<br/>FROM orders<br/>GROUP BY ..."]
C --> D[المحسن]
D --> E[تنفيذ]
style B fill:#fff9c4
style D fill:#c8e6c9
4. المفهوم: طرق العرض القابلة للتحديث
(1) أي طرق العرض قابلة للتحديث
في PostgreSQL، طرق العرض البسيطة التي تحقق جميع الشروط التالية قابلة للتحديث تلقائياً (تدعم INSERT / UPDATE / DELETE):
| الشرط | الوصف |
|---|---|
| FROM جدول أساسي واحد فقط | لا JOIN |
| لا GROUP BY / HAVING | لا تجميع |
| لا DISTINCT | لا إزالة تكرار |
| لا دوال النوافذ | لا OVER |
| أعمدة SELECT هي أعمدة الجدول الأساسي | لا تعبيرات/أعمدة محسوبة |
(4) ▶ مثال
CREATE VIEW v_active_users AS
SELECT user_id, name, email, status
FROM users
WHERE status = 'active';
Output:
CREATE TABLE
UPDATE v_active_users SET name = 'Alice Wang' WHERE user_id = 1;
DELETE FROM v_active_users WHERE user_id = 99;
INSERT INTO v_active_users (user_id, name, email, status)
VALUES (101, 'Charlie', 'charlie@example.com', 'active');
(2) WITH CHECK OPTION
| الخيار | السلوك |
|---|---|
| بدون CHECK OPTION | الهروب مسموح؛ الصفوف المحدثة قد لا تعود تظهر في طريقة العرض |
| WITH CHECK OPTION | الهروب ممنوع؛ الصفوف المحدثة يجب أن تظل تحقق شرط طريقة العرض |
| WITH CASCADED CHECK OPTION | طريقة العرض الحالية + طرق العرض التابعة تُفحص (تكراري) |
| WITH LOCAL CHECK OPTION | فقط شرط طريقة العرض الحالية يُفحص |
(5) ▶ مثال
CREATE VIEW v_active_users_strict AS
SELECT user_id, name, email, status
FROM users
WHERE status = 'active'
WITH CHECK OPTION;
UPDATE v_active_users_strict SET status = 'inactive' WHERE user_id = 1;
ERROR: new row violates check option for view "v_active_users_strict"
DETAIL: Failing row contains (1, ..., inactive).
(6) ▶ مثال
INSERT INTO v_active_users (user_id, name, email, status)
VALUES (200, 'Bob', 'bob@example.com', 'active');
SELECT * FROM v_active_users WHERE user_id = 200;
user_id | name | email | status
---------+------+--------------------+--------
200 | Bob | bob@example.com | active
5. المفهوم: طرق العرض المادية
(1) نظرة عامة على MATERIALIZED VIEW
طريقة العرض المادية تخزن نتيجة الاستعلام فعلياً على القرص؛ الاستعلامات تقرأ البيانات المحسوبة مسبقاً مباشرة، بدون إعادة تنفيذ الاستعلام الأساسي. هذه ميزة خاصة بـ PostgreSQL.
| الخاصية | طريقة العرض العادية | طريقة العرض المادية |
|---|---|---|
| ما يُخزن | نص الاستعلام | نص الاستعلام + بيانات النتيجة |
| حداثة البيانات | فورية | تُحدث فقط عند التحديث |
| أداء الاستعلام | نفس الاستعلام الأساسي | سريع جداً (يقرأ المحسوب مسبقاً) |
| المساحة المستخدمة | لا شيء تقريباً | نفس حجم مجموعة النتائج |
| قابلة للتحديث | طرق العرض البسيطة يمكنها | لا DML مباشر |
| طريقة التحديث | غير مطلوبة | REFRESH MATERIALIZED VIEW |
(7) ▶ مثال
CREATE MATERIALIZED VIEW mv_monthly_sales AS
SELECT
DATE_TRUNC('month', order_date)::date AS month,
region,
COUNT(*) AS order_count,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_order_value
FROM orders
GROUP BY DATE_TRUNC('month', order_date), region
WITH DATA;
Output:
count
-------
5
(1 row)
(8) ▶ مثال
SELECT * FROM mv_monthly_sales
WHERE month >= '2025-01-01'
ORDER BY total_revenue DESC;
Output:
id | name | value
----+----------+-------
1 | example | 42
(1 row)
يعيد بالمللي ثانية، لأن البيانات محسوبة مسبقاً ومخزنة.
(2) REFRESH
| الصيغة | السلوك | القفل | السرعة |
|---|---|---|---|
REFRESH MATERIALIZED VIEW mv |
تحديث كامل، يستبدل جميع البيانات | يأخذ قفلاً حصرياً، يحظر القراءة | أبطأ |
REFRESH MATERIALIZED VIEW CONCURRENTLY mv |
تحديث تزايدي (يحتاج فهرس فريد) | لا يحظر القراءة | أسرع |
CONCURRENTLY هي ميزة خاصة بـ PostgreSQL: طريقة العرض تبقى قابلة للاستعلام أثناء التحديث — العمل لا يُحظر.
(9) ▶ مثال
REFRESH MATERIALIZED VIEW mv_monthly_sales;
Output:
-- SQL statement executed successfully
جميع SELECTs على طريقة العرض المادية هذه تُحظر أثناء التحديث.
(10) ▶ مثال
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_monthly_sales;
Output:
-- SQL statement executed successfully
الشرط المسبق: طريقة العرض المادية يجب أن يكون لديها فهرس فريد واحد على الأقل.
CREATE UNIQUE INDEX idx_mv_monthly_sales_pk
ON mv_monthly_sales (month, region);
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_monthly_sales;
(3) WITH DATA مقابل WITH NO DATA
| الخيار | السلوك |
|---|---|
| WITH DATA | ملء البيانات فوراً عند الإنشاء (افتراضي) |
| WITH NO DATA | لا تملأ عند الإنشاء؛ يجب REFRESH قبل أول استعلام |
(11) ▶ مثال
CREATE MATERIALIZED VIEW mv_expensive_report AS
SELECT ... FROM ... WITH NO DATA;
REFRESH MATERIALIZED VIEW mv_expensive_report;
Output:
CREATE TABLE
(12) ▶ مثال
SELECT cron.schedule(
'refresh_monthly_sales',
'0 4 * * *',
$$REFRESH MATERIALIZED VIEW CONCURRENTLY mv_monthly_sales$$
);
Output:
id | name | value
----+----------+-------
1 | example | 42
(1 row)
يُحدث تلقائياً كل يوم في الساعة 4:00 صباحاً.
6. طرق العرض مقابل طرق العرض المادية مقابل الجداول المؤقتة
| البعد | طريقة عرض عادية | طريقة عرض مادية | جدول مؤقت |
|---|---|---|---|
| يخزن تعريف الاستعلام | نعم | نعم | لا |
| يخزن البيانات | لا | نعم | نعم |
| حداثة البيانات | فورية | تحديث يدوي | صيانة يدوية |
| أداء الاستعلام | يعتمد على الاستعلام الأساسي | سريع جداً | سريع |
| استمرار عبر الجلسات | نعم | نعم | لا (يختفي بعد الجلسة) |
| يدعم الفهارس | لا (يستخدم فهارس الجدول الأساسي) | نعم | نعم |
| يدعم DML | طرق العرض البسيطة قابلة للتحديث | لا | نعم |
| السيناريو النموذجي | تبسيط الاستعلامات | حساب مسبق للتقارير | نتائج وسيطة مؤقتة |
classDiagram
class View {
+يخزن نص الاستعلام
+بيانات فورية
+طريقة عرض بسيطة قابلة لـ DML
+WITH CHECK OPTION
}
class MaterializedView {
+يخزن نص الاستعلام+البيانات
+تحديث REFRESH
+CONCURRENTLY
+قابل للفهرسة
+WITH DATA/NO DATA
}
class TempTable {
+يخزن البيانات فقط
+يختفي بعد الجلسة
+DML كامل
+قابل للفهرسة
}
View <|-- MaterializedView : extends
MaterializedView ..|> TempTable : أداء مشابه
7. أفضل ممارسات إدارة طرق العرض
(1) اصطلاحات التسمية
| النوع | البادئة الموصى بها | مثال |
|---|---|---|
| طريقة عرض عادية | v_ |
v_active_users |
| طريقة عرض مادية | mv_ |
mv_monthly_sales |
| جدول مؤقت | tmp_ |
tmp_import_data |
(2) تبعيات طرق العرض والأمان
| العملية | الخطر | الحل |
|---|---|---|
| حذف الجدول الأساسي | تصبح طريقة العرض غير صالحة | DROP TABLE CASCADE يحذف تلقائياً طرق العرض التابعة |
| تعديل عمود الجدول الأساسي | قد تخطئ طريقة العرض | حدث التعريف بـ CREATE OR REPLACE VIEW |
| التحكم في الصلاحيات | طريقة العرض يمكنها تحديد رؤية الأعمدة | GRANT SELECT ON view TO role |
(13) ▶ مثال
CREATE VIEW v_user_public AS
SELECT user_id, name
FROM users;
GRANT SELECT ON v_user_public TO reporter_role;
REVOKE SELECT ON users FROM reporter_role;
Output:
CREATE TABLE
reporter_role يمكنه فقط رؤية user_id و name، ليس الأعمدة الحساسة مثل email.
8. مثال شامل
CREATE MATERIALIZED VIEW mv_sales_report AS
SELECT
DATE_TRUNC('month', o.order_date)::date AS month,
p.category,
o.region,
COUNT(*) AS order_count,
COUNT(DISTINCT o.customer_id) AS unique_customers,
SUM(o.amount) AS total_revenue,
SUM(o.amount) FILTER (WHERE o.amount >= 50000) AS big_deal_revenue,
AVG(o.amount) AS avg_order_value,
SUM(oi.quantity * oi.unit_price) AS total_gmv
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
GROUP BY DATE_TRUNC('month', o.order_date), p.category, o.region
WITH DATA;
CREATE UNIQUE INDEX idx_mv_sales_report_pk
ON mv_sales_report (month, category, region);
CREATE VIEW v_sales_dashboard AS
SELECT
month,
region,
SUM(total_revenue) AS region_revenue,
SUM(order_count) AS region_orders,
SUM(unique_customers) AS region_customers
FROM mv_sales_report
GROUP BY month, region;
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_sales_report;
9. تدفق التنفيذ
تدفق إنشاء وتحديث طريقة العرض المادية:
flowchart TD
A[CREATE MATERIALIZED VIEW] --> B[تنفيذ الاستعلام الأساسي]
B --> C[كتابة النتائج على القرص]
C --> D[يمكن إنشاء فهارس]
D --> E[الاستعلام يقرأ بيانات القرص مباشرة]
E --> F{بحاجة لتحديث؟}
F -->|REFRESH| G[إعادة تنفيذ الاستعلام الأساسي]
G --> H[استبدال البيانات القديمة]
H --> E
F -->|CONCURRENTLY| I[تحديث تزايدي بالمقارنة]
I --> J[لا يحظر القراءة]
J --> E
style A fill:#e1f5fe
style E fill:#c8e6c9
style I fill:#fff9c4
| الخطوة | الوصف |
|---|---|
| إنشاء | تنفيذ الاستعلام الأساسي، استمرار النتيجة على القرص |
| استعلام | قراءة بيانات القرص مباشرة، لا استعلام أساسي منفذ |
| تحديث | إعادة تنفيذ الاستعلام الأساسي، استبدال البيانات القديمة |
| CONCURRENTLY | تحديث تزايدي، لا يحظر الاستعلامات أثناء التحديث |
❓ أسئلة شائعة
...
📖 ملخص
📝 تمارين
- تمرين أساسي
- تمرين متوسط
- تمرين صعب
ملخص
- طريقة العرض العادية تخزن فقط نص الاستعلام، تتوسع عند الاستعلام، البيانات دائماً فورية
- طرق العرض البسيطة (جدول واحد، لا تجميع) قابلة للتحديث تلقائياً، تدعم INSERT/UPDATE/DELETE
- WITH CHECK OPTION تمنع DML من التسبب في هروب الصفوف من نطاق طريقة العرض
- طريقة العرض المادية تخزن نتيجة الاستعلام على القرص، سريعة جداً لكن ليست فورية
- REFRESH MATERIALIZED VIEW يقوم بتحديث كامل؛ CONCURRENTLY يقوم بتحديث تزايدي لا يحظر القراءة
- شرط تحديث CONCURRENTLY: طريقة العرض المادية يجب أن يكون لديها فهرس فريد
- طرق العرض يمكنها فرض صلاحيات على مستوى العمود، إخفاء الأعمدة الحساسة