> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> توثيق خاص بالتجسيد materialized_view

# العروض المادية

export const ClickHouseSupportedBadge = () => {
  return <div className="ClickHouseSupportedBadge">
            <div className="ClickHouseSupportedIcon">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1.30762 1.39073C1.30762 1.3103 1.37465 1.22986 1.46849 1.22986H2.64824C2.72868 1.22986 2.80912 1.29689 2.80912 1.39073V14.4886C2.80912 14.5691 2.74209 14.6495 2.64824 14.6495H1.46849C1.38805 14.6495 1.30762 14.5825 1.30762 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M4.2832 1.39073C4.2832 1.3103 4.35023 1.22986 4.44408 1.22986H5.62383C5.70427 1.22986 5.7847 1.29689 5.7847 1.39073V14.4886C5.7847 14.5691 5.71767 14.6495 5.62383 14.6495H4.44408C4.36364 14.6495 4.2832 14.5825 4.2832 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M7.25977 1.39073C7.25977 1.3103 7.3268 1.22986 7.42064 1.22986H8.60039C8.68083 1.22986 8.76127 1.29689 8.76127 1.39073V14.4886C8.76127 14.5691 8.69423 14.6495 8.60039 14.6495H7.42064C7.3402 14.6495 7.25977 14.5825 7.25977 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M10.2354 1.39073C10.2354 1.3103 10.3024 1.22986 10.3962 1.22986H11.576C11.6564 1.22986 11.7369 1.29689 11.7369 1.39073V14.4886C11.7369 14.5691 11.6698 14.6495 11.576 14.6495H10.3962C10.3158 14.6495 10.2354 14.5825 10.2354 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M13.2256 6.6057C13.2256 6.52526 13.2926 6.44482 13.3865 6.44482H14.5662C14.6466 6.44482 14.7271 6.51186 14.7271 6.6057V9.27354C14.7271 9.35398 14.6601 9.43442 14.5662 9.43442H13.3865C13.306 9.43442 13.2256 9.36739 13.2256 9.27354V6.6057Z" fill="currentColor" />
                </svg>
            </div>
            متوافق مع ClickHouse
        </div>;
};

<ClickHouseSupportedBadge />

يجب أن يكون تجسيد `materialized_view` عبارة عن استعلام `SELECT` من table (source) موجودة. وعلى خلاف PostgreSQL، فإن عرض مادي في ClickHouse ليس "ثابتًا" (ولا توجد له عملية REFRESH مقابلة). وبدلًا من ذلك، فهو يعمل بوصفه **مشغّل إدراج**، إذ يُدرِج rows جديدة في target table عبر تطبيق تحويل `SELECT` المحدد على rows المُدرجة في source table. راجع [توثيق عرض مادي في ClickHouse](/docs/ar/concepts/features/materialized-views/index) لمزيد من التفاصيل حول كيفية عمل العروض المادية في ClickHouse.

<Note>
  للاطلاع على مفاهيم التجسيد العامة وconfig المشتركة (مثل engine وorder\_by وpartition\_by وما إلى ذلك)، راجع صفحة [التجسيدات](/docs/ar/integrations/connectors/data-ingestion/etl-tools/dbt/materializations).
</Note>

<div id="target-table-management">
  ## كيفية إدارة الجدول الهدف
</div>

عند استخدام تجسيد ‏`materialized_view`، يحتاج dbt-clickhouse إلى إنشاء كلٍّ من **عرض مادي** و**جدول هدف** تُدرج فيه الصفوف المُحوَّلة. توجد طريقتان لإدارة الجدول الهدف:

| النهج            | الوصف                                                                                                                                                                                                                                                                                                                                  | الحالة   |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| **الهدف الضمني** | ينشئ dbt-clickhouse الجدول الهدف ويديره تلقائيًا ضمن النموذج نفسه. ويُستنتج مخطط الجدول الهدف من SQL الخاص بـ MV.                                                                                                                                                                                                                      | مستقرة   |
| **الهدف الصريح** | تُعرِّف الجدول الهدف كتجسيد منفصل من النوع `table`، ثم تشير إليه من نموذج MV باستخدام الماكرو `materialization_target_table()`. ويُنشأ MV مع عبارة `TO` تشير إلى ذلك الجدول. هذه الوظيفة متاحة بدءًا من **dbt-clickhouse version 1.10**. **تحذير**: هذه الميزة في مرحلة بيتا، وقد تتغير واجهة برمجة تطبيقات بناءً على ملاحظات المجتمع. | **بيتا** |

يؤثر النهج الذي تختاره في كيفية التعامل مع تغييرات المخطط، وعمليات التحديث الكامل، وإعدادات MV المتعددة. وتصف الأقسام التالية كل نهج بالتفصيل.

<div id="implicit-target">
  ## التجسيد مع الجدول الهدف الضمني
</div>

هذا هو السلوك الافتراضي. عند تعريف نموذج `materialized_view`، سيقوم المهايئ بما يلي:

1. إنشاء **الجدول الهدف** باسم النموذج
2. إنشاء ClickHouse **عرض مادي** بالاسم `<model_name>_mv`

يُستنتج مخطط الجدول الهدف من الأعمدة الموجودة في عبارة `SELECT` الخاصة بـ MV. وتشترك جميع الموارد (الجدول الهدف + MVs) في تهيئة النموذج نفسها.

```sql theme={null}
-- models/events_mv.sql
{{
    config(
        materialized='materialized_view',
        engine='SummingMergeTree()',
        order_by='(event_date, event_type)'
    )
}}

SELECT
    toStartOfDay(event_time) AS event_date,
    event_type,
    count() AS total
FROM {{ source('raw', 'events') }}
GROUP BY event_date, event_type
```

راجع [ملف الاختبار](https://github.com/ClickHouse/dbt-clickhouse/blob/main/tests/integration/adapter/materialized_view/test_materialized_view.py) للاطلاع على مزيد من الأمثلة.

<Tip>
  يمكنك أيضًا تحديد `codec` و`ttl` على مستوى العمود في الجدول الهدف من خلال فرض عقد على النموذج. راجع [إعدادات الأعمدة](/docs/ar/integrations/connectors/data-ingestion/etl-tools/dbt/materializations#column-configuration) لمزيد من التفاصيل.
</Tip>

<div id="multiple-materialized-views">
  ### عدة عروض مادية
</div>

يتيح ClickHouse وجود أكثر من عرض مادي واحد يكتب السجلات إلى جدول الهدف نفسه. ولدعم ذلك في dbt-clickhouse باستخدام نهج الهدف الضمني، يمكنك إنشاء `UNION` في ملف النموذج، مع إحاطة SQL الخاصة بكل عرض مادي بتعليقات بالصيغة `--my_mv_name:begin` و `--my_mv_name:end`.

على سبيل المثال، سيؤدي ما يلي إلى إنشاء عرضين ماديين يكتبان البيانات إلى جدول الوجهة نفسه الخاص بالنموذج. وستكون أسماء العروض المادية بالصيغة `<model_name>_mv1` و `<model_name>_mv2`:

```sql theme={null}
--mv1:begin
select a,b,c from {{ source('raw', 'table_1') }}
--mv1:end
union all
--mv2:begin
select a,b,c from {{ source('raw', 'table_2') }}
--mv2:end
```

<Warning>
  عند تحديث model يتضمّن عدة عروض مادية ‏(MVs)، وخصوصًا عند إعادة تسمية أحد أسماء الـ MV،
  لا يقوم dbt-clickhouse تلقائيًا بحذف الـ MV القديم. وبدلًا من ذلك،
  سيظهر لك التحذير التالي:

  `Warning - Table <previous table name> was detected with the same pattern as model name <your model name> but was not found in this run. In case it is a renamed mv that was previously part of this model, drop it manually (!!!) `
</Warning>

<div id="how-to-iterate-the-target-table-schema">
  ### كيفية تطوير مخطط الجدول الهدف
</div>

بدءًا من **الإصدار 1.9.8 من dbt-clickhouse**، يمكنك التحكّم في كيفية تطوير مخطط الجدول الهدف عندما يواجه `dbt run` أعمدة مختلفة في SQL الخاص بـ MV.

```python theme={null}
{{config(
    materialized='materialized_view',
    engine='MergeTree()',
    order_by='(id)',
    on_schema_change='fail'  # this setting
)}}
```

افتراضيًا، لن يطبّق dbt أي تغييرات على الجدول الهدف (قيمة الإعداد `ignore`)، لكن يمكنك تغيير هذا الإعداد ليعمل وفق السلوك نفسه لإعداد `on_schema_change` [في النماذج التزايدية](https://docs.getdbt.com/docs/build/incremental-models#what-if-the-columns-of-my-incremental-model-change).

ويمكنك أيضًا استخدام هذا الإعداد كآلية أمان. فإذا ضبطته على `fail`، فستفشل عملية البناء إذا كانت الأعمدة في SQL الخاص بـ MV تختلف عن أعمدة الجدول الهدف الذي أُنشئ عند أول `dbt run`.

<div id="data-catch-up">
  ### استكمال البيانات
</div>

افتراضيًا، عند إنشاء عرض مادي (MV) أو إعادة إنشائه، يُملأ الجدول الهدف أولًا بالبيانات التاريخية قبل إنشاء الـ MV نفسه (`catchup=True`). يمكنك تعطيل هذا السلوك بضبط إعداد `catchup` على `False`.

```python theme={null}
{{config(
    materialized='materialized_view',
    engine='MergeTree()',
    order_by='(id)',
    catchup=False  # this setting
)}}
```

| العملية                                   | `catchup: True` (الافتراضي)                          | `catchup: False`                                               |
| ----------------------------------------- | ---------------------------------------------------- | -------------------------------------------------------------- |
| النشر المبدئي (`dbt run`)                 | تُملأ الجدول الهدف بالبيانات التاريخية               | يُنشأ الجدول الهدف فارغًا                                      |
| التحديث الكامل (`dbt run --full-refresh`) | يُعاد إنشاء الجدول الهدف وتعبئته بالبيانات التاريخية | يُعاد إنشاء الجدول الهدف فارغًا، **مع فقدان البيانات الحالية** |
| التشغيل العادي                            | يلتقط العرض المادي عمليات الإدراج الجديدة            | يلتقط العرض المادي عمليات الإدراج الجديدة                      |

<Warning>
  **مخاطر فقدان البيانات مع التحديث الكامل**

  سيؤدي استخدام `catchup: False` مع `dbt run --full-refresh` إلى **حذف جميع البيانات الحالية** في الجدول الهدف. سيُعاد إنشاء الجدول فارغًا ولن يلتقط بعد ذلك سوى البيانات الجديدة. تأكد من توفّر نسخ احتياطية إذا كانت البيانات التاريخية قد تكون مطلوبة لاحقًا.
</Warning>

<div id="explicit-target">
  ## التجسيد مع هدف محدد صراحةً (بيتا)
</div>

<Warning>
  **بيتا**

  هذه الميزة في مرحلة بيتا، وهي متاحة بدءًا من **الإصدار 1.10 من dbt-clickhouse**. قد تتغير واجهة برمجة التطبيقات بناءً على ملاحظات المجتمع.
</Warning>

ينشئ dbt-clickhouse افتراضيًا ويدير كلًا من الجدول الهدف والعروض المادية ضمن نموذج واحد (وهو نهج [الهدف الضمني](#implicit-target) الموضح أعلاه). لكن لهذا النهج بعض القيود:

* تشترك جميع الموارد (الجدول الهدف + MVs) في الإعدادات نفسها. وإذا كانت عدة MVs تشير إلى الجدول الهدف نفسه، فيجب تعريفها معًا باستخدام صياغة `UNION ALL`.
* لا يمكن التعامل مع أي من هذه الموارد بشكل منفصل، إذ يجب إدارة جميعها باستخدام ملف النموذج نفسه.
* لا يمكنك بسهولة التحكم في اسم كل MV.
* تتشارك جميع الإعدادات بين الجدول الهدف وMVs، مما يصعّب تهيئة كل مورد على حدة ويجعل من الصعب تحديد التهيئة التي تخص كل مورد.

تتيح لك ميزة **الهدف المحدد صراحةً** تعريف الجدول الهدف بشكل منفصل كتجسيد `table` عادي، ثم الرجوع إليه من نماذج العرض المادي لديك.

<div id="explicit-target-benefits">
  ### الفوائد
</div>

* **موارد منفصلة بالكامل**: أصبح الآن بالإمكان تعريف كل مورد على حدة، مما يحسّن سهولة القراءة.
* **تطابق 1:1 بين موارد dbt وCH**: يمكنك الآن استخدام أدوات dbt لإدارتها وتكرارها كلٌّ على حدة.
* **إتاحة تهيئات مختلفة**: أصبح الآن بالإمكان تطبيق تهيئة مختلفة على كل مورد.
* **لم تعد هناك حاجة للالتزام باتفاقيات التسمية**: تُنشأ الآن جميع الموارد باستخدام الاسم الذي تحدده لها، وليس الاسم المخصّص المضاف إليه اللاحقة \_mv في MVs.

<div id="explicit-target-limitations">
  ### القيود
</div>

* تعريف الجدول الهدف ليس نهجًا طبيعيًا في dbt: فهو ليس استعلام SQL يقرأ من جدول مصدر، لذا تفقد هنا عمليات التحقق الخاصة بـ dbt. سيظل SQL الخاص بـ MV خاضعًا للتحقق باستخدام أدوات dbt المساعدة، كما سيُتحقق من توافقه مع أعمدة الجدول الهدف على مستوى CH.
* **وجدنا بعض المشكلات المرتبطة بقيود الدالة `ref()`**: نحتاج إلى استخدامها للإشارة إلى النماذج فيما بينها، لكن لا يمكن استخدامها إلا للإشارة إلى النماذج upstream، وليس downstream. وهذا يسبب بعض المشكلات في هذا التنفيذ. لقد أنشأنا issue في مستودع dbt-core، ونجري حاليًا نقاشًا معهم [للبحث عن حلول ممكنة (dbt-labs/dbt-core#12319)](https://github.com/dbt-labs/dbt-core/issues/12319):
  * عند استدعاء `ref()` من داخل كتلة config، فإنها تُرجع النموذج الحالي، لا النموذج المُشار إليه. وهذا يمنعنا من تعريفه في قسم config()، ويجبرنا على استخدام comment لإضافة هذه التبعية. ونحن نتبع النمط نفسه الموضح في وثائق dbt باستخدام [أسلوب "--depends\_on:"](https://docs.getdbt.com/reference/dbt-jinja-functions/ref#forcing-dependencies).
  * تعمل `ref()` بالنسبة لنا لأنها تفرض إنشاء الجدول الهدف أولًا، ولكن في مخطط التبعيات في الوثائق المُولَّدة، سيُرسَم الجدول الهدف على أنه تبعية upstream أخرى، وليس downstream، مما يجعل فهمه أكثر صعوبة قليلًا.
  * يفرض `unit-test` علينا أيضًا تعريف بعض البيانات للجدول الهدف حتى عندما تكون الفكرة ألا نقرأ منه. والحل البديل هنا هو ببساطة ترك بيانات هذا الجدول فارغة.

<div id="explicit-target-usage">
  ### الاستخدام
</div>

**الخطوة 1: عرِّف جدول هدف كنموذج جدول عادي**

النموذج `events_daily.sql`:

```sql theme={null}
{{
    config(
        materialized='table',
        engine='SummingMergeTree()',
        order_by='(event_date, event_type)',
        partition_by='toYYYYMM(event_date)'
    )
}}

SELECT
    toDate(now()) AS event_date,
    '' AS event_type,
    toUInt64(0) AS total
WHERE 0  -- Creates empty table with correct schema
```

هذا هو الحل الالتفافي الذي نذكره في قسم القيود. قد تفقد هنا بعض عمليات التحقق الخاصة بـ dbt، لكن سيظل المخطط خاضعًا للتحقق على مستوى ClickHouse.

**الخطوة 2: تعريف العروض المُجسَّدة التي تشير إلى جدول الهدف**

على سبيل المثال، يمكنك تعريف عدة MVs مختلفة في نماذج مختلفة كما يلي، ويمكن أن تشير حتى إلى جدول الهدف نفسه. لاحظ استدعاء الماكرو الجديد `{{ materialization_target_table(ref('events_daily')) }}`، الذي يضبط جدول الهدف لـ MV.

النموذج `page_events_aggregator.sql`:

```sql theme={null}
{{ config(materialized='materialized_view') }}
{{ materialization_target_table(ref('events_daily')) }}

SELECT
    toStartOfDay(event_time) AS event_date,
    event_type,
    count() AS total
FROM {{ source('raw', 'page_events') }}
GROUP BY event_date, event_type
```

النموذج `mobile_events_aggregator.sql`:

```sql theme={null}
{{ config(materialized='materialized_view') }}
{{ materialization_target_table(ref('events_daily')) }}

SELECT
    toStartOfDay(event_time) AS event_date,
    event_type,
    count() AS total
FROM {{ source('raw', 'mobile_events') }}
GROUP BY event_date, event_type
```

<div id="explicit-target-configuration">
  ### خيارات الإعداد
</div>

عند استخدام جداول هدف صريحة، فبالإضافة إلى [إعدادات التجسيد العامة](/docs/ar/integrations/connectors/data-ingestion/etl-tools/dbt/materializations#general-materialization-configurations) و[الإعدادات الخاصة بالجدول](/docs/ar/integrations/connectors/data-ingestion/etl-tools/dbt/materializations#materialization-table)، تنطبق الإعدادات التالية:

**على الجدول الهدف (`materialized='table'`):**

| الخيار                                | الوصف                                                                                                                                                                                                                                                         | القيمة الافتراضية                                                                                                                                                                                                                                                              |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `mv_on_schema_change`                 | كيفية التعامل مع تغييرات المخطط عند استخدام الجدول بواسطة MVs مُدارة عبر dbt. ويتبع السلوك نفسه لإعداد `on_schema_change` [في النماذج incremental](https://docs.getdbt.com/docs/build/incremental-models#what-if-the-columns-of-my-incremental-model-change). | **تحذير**: سيتصرف نموذج `materialized='table'` كالمعتاد إذا لم تكن هناك MVs تشير إليه، لذا حتى إذا تم تعريف هذا الإعداد فسيتم تجاهله. وإذا كان الجدول هو الهدف لـ MVs، فستكون القيمة الافتراضية لهذا الإعداد هي `mv_on_schema_change='fail'` لحماية البيانات داخل هذه الجداول. |
| `repopulate_from_mvs_on_full_refresh` | عند استخدام `--full-refresh`، بدلًا من تشغيل SQL الخاص بالجدول، أعد إنشاء الجدول بتنفيذ عمليات INSERT-SELECT باستخدام SQL من جميع MVs التي تشير إليه.                                                                                                         | `False`                                                                                                                                                                                                                                                                        |

**على العرض المادي (`materialized='materialized_view'`):**

| الخيار    | الوصف                                                          | القيمة الافتراضية |
| --------- | -------------------------------------------------------------- | ----------------- |
| `catchup` | ما إذا كان سيتم تحميل البيانات التاريخية الفائتة عند إنشاء MV. | `True`            |

<Note>
  عادةً ما تحتاج فقط إلى تعيين `catchup` على `True` في MVs، أو تعيين `repopulate_from_mvs_on_full_refresh` على `True` في جداولها الهدف. وإذا عيّنت كليهما على `True`، فقد يؤدي ذلك إلى تكرار البيانات.
</Note>

<div id="explicit-target-common-operations">
  ### العمليات الشائعة
</div>

<div id="explicit-target-full-refresh">
  #### التحديث الكامل باستخدام الجداول الهدف المحددة صراحةً
</div>

عند استخدام `--full-refresh`، ستُعاد إنشاء الجداول الهدف المحددة صراحةً (لذا قد تفقد بعض البيانات إذا كان إدخال البيانات جارياً أثناء هذه العملية). وسيختلف ذلك بحسب إعدادات التكوين لديك:

**الخيار 1: السلوك الافتراضي لـ `--full-refresh`. ستُعاد إنشاء كل شيء، ولكن أثناء إعادة إنشاء MVs، سيكون الجدول الهدف فارغًا أو محمّلًا جزئيًا.**

سيُحذف كل شيء ثم يُعاد إنشاؤه. إذا كنت تريد إعادة إدراج البيانات باستخدام SQL الخاص بـ MVs، فأبقِ الإعداد `catchup=True`:

```sql theme={null}
-- models/page_events_aggregator.sql
{{ config(
    materialized='materialized_view',
    catchup=True  -- this is the default value so you don't need to actually set it.
) }}
{{ materialization_target_table(ref('events_daily')) }}
...
```

**الخيار 2: أريد إعادة إنشاء الجدول الهدف ولا أريد أن أقرأ بيانات فارغة أثناء إعادة إنشاء MVs.**

إذا كنت بحاجة أولًا إلى تحديث SQL الخاص بـ MVs، فيمكنك ضبط `catchup=False` فيها ثم تنفيذ `dbt run` أو `dbt run --full-refresh` على MVs. تأكد من إنشاء MVs قبل تشغيل `--full-refresh` على نموذج الجدول الهدف، لأنه يستخدم تعريفات MV من ClickHouse.

عيّن `repopulate_from_mvs_on_full_refresh=True` في نموذج الجدول الهدف. عند تنفيذ `dbt run --full-refresh`، سيؤدي ذلك إلى:

1. إنشاء جدول مؤقت جديد
2. تنفيذ INSERT-SELECT باستخدام SQL الخاص بكل MV
3. تبديل الجدولين ذريًا

وبذلك لن تظهر بيانات فارغة في جدولك أثناء إعادة إنشاء MVs.

```sql theme={null}
-- models/events_daily.sql
{{
    config(
        materialized='table',
        engine='SummingMergeTree()',
        order_by='(event_date, event_type)',
        repopulate_from_mvs_on_full_refresh=True
    )
}}
...
```

<div id="explicit-target-changing">
  #### تغيير الجدول الهدف
</div>

لا يمكنك تغيير الجدول الهدف الخاص بـ MV بدون `--full-refresh`. إذا حاولت تشغيل أمر `dbt run` عاديًا بعد تغيير المرجع `materialization_target_table()`، فستفشل عملية البناء وستظهر رسالة خطأ تشير إلى أن الهدف قد تغيّر.

لتغيير الهدف:

1. حدِّث استدعاء `materialization_target_table()`
2. شغِّل `dbt run --full-refresh -s your_mv_model`

<div id="explicit-target-troubleshooting">
  ### استكشاف المشكلات الشائعة وإصلاحها
</div>

<div id="target-table-empty">
  #### يكون الجدول الهدف فارغًا أثناء/بعد تنفيذ `run`
</div>

هناك عدة أسباب قد تؤدي إلى ذلك:

* قد تكون العروض المادية مهيأة باستخدام `catchup=False`، أو قد يكون الجدول الهدف مهيأ باستخدام `repopulate_from_mvs_on_full_refresh=False`، ولذلك لا يتم تنفيذ تحميل البيانات التاريخية عند إنشاء العروض المادية أو عند إعادة إنشاء الجدول الهدف. هذا هو السلوك المتوقع، لذا إذا كنت تريد إعادة إدراج البيانات باستخدام SQL الخاص بالعروض المادية، فتأكد من ضبط `catchup=True` في العرض المادي (وهذه هي القيمة الافتراضية) أو `repopulate_from_mvs_on_full_refresh=True` في الجدول الهدف. وتأكد من عدم تفعيل الخيارين معًا في الوقت نفسه لتجنب التكرار. راجع [قسم التهيئة](#explicit-target-configuration) لمزيد من التفاصيل.
* أثناء تنفيذ `dbt run --full-refresh`، إذا كانت العروض المادية تستخدم القيمة الافتراضية `catchup=True`، فسيُعاد إنشاء الهدف، وستُعيد العروض المادية إدراج البيانات تباعًا. لتجنب هذا الوضع، راجع [التحديث الكامل مع الأهداف الصريحة](#explicit-target-full-refresh).

<div id="full-refresh-with-repopulate-from-mvs-on-full-refresh">
  #### يستخدم `dbt run --full-refresh` على جدول الهدف مع `repopulate_from_mvs_on_full_refresh=True` المنطقَ المستمد من إصدارات العرض المادي القديمة، وليس من SQL الموجود حاليًا في المشروع
</div>

يستخدم `repopulate_from_mvs_on_full_refresh=True` SQL الخاص بـ MV الموجود والمُعرّف مسبقًا في ClickHouse. وللتأكد من استخدام تعريف العرض المادي الجديد، نفّذ `dbt run` لكل عرض مادي قبل تنفيذ `dbt run --full-refresh` على جدول الهدف.

<div id="duplicate-data">
  #### توجد بيانات مكررة بعد تنفيذ عملية تشغيل
</div>

الأسباب المحتملة:

* قد يكون كلٌّ من `catchup=True` على العروض المادية و`repopulate_from_mvs_on_full_refresh=True` على الجدول الهدف مفعّلًا: أبقِ واحدًا منهما فقط بحسب العمليات التي تريد تشغيلها. راجع [قسم الإعدادات](#explicit-target-configuration) لمزيد من التفاصيل.
* لم يتم تعريف الجدول الهدف باستخدام `WHERE 0`: يجب إنشاء الجدول الهدف فارغًا، لكن قد يُدرج الاستعلام الداخلي بيانات إذا لم يتم تضمين `WHERE 0`. تأكد من تضمين العبارة.

<div id="data-loss-active-ingestion">
  #### فقدان البيانات أثناء الاستيعاب النشط بعد تنفيذ `dbt run --full-refresh`
</div>

تكون بعض الصفوف من الجدول المصدر مفقودة في الجدول الهدف بعد تنفيذ `dbt run --full-refresh`.
تعمل العروض المادية في ClickHouse كمشغّلات insert — فهي لا تلتقط البيانات إلا أثناء وجودها. أثناء التحديث الكامل، توجد نافذة قصيرة يُزال فيها الـ MV ثم يُعاد إنشاؤه («النافذة العمياء»). وأي صفوف تُدرج في الجدول المصدر خلال هذه النافذة لن يتم التقاطها. راجع قسم [السلوك أثناء الاستيعاب النشط](#behavior-during-active-ingestion) لمزيد من التفاصيل.

<div id="debugging-techniques">
  ### تقنيات تصحيح الأخطاء
</div>

<div id="check-mv-target">
  #### تحقّق من الوجهة الحالية لـ MV في ClickHouse
</div>

استعلم عن `system.tables` لمعرفة الجهة التي يكتب فيها العرض المادي:

```sql theme={null}
SELECT
    name as mv_name,
    replaceRegexpOne(
        create_table_query,
        '.*TO\\s+`?([^`\\s(]+)`?\\.`?([^`\\s(]+)`?.*',
        '\\1.\\2'
    ) AS target_table
FROM system.tables
WHERE database = 'your_schema'
  AND engine = 'MaterializedView'
```

<div id="check-dbt-recognition">
  #### تحقّق مما إذا كان dbt يتعرّف على جدول كجدول هدف لعرض مادي
</div>

أثناء تشغيل dbt، ابحث عن رسالة السجل التالية:

> الجدول `<table_name>` يُستخدم كجدول هدف بواسطة عرض مادي يديره dbt. سيتم ضبط mv\_on\_schema\_change تلقائيًا على "fail" لمنع فقدان البيانات.

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

* يعرّف نموذج العرض المادي `{{ materialization_target_table(ref('your_target')) }}` بشكل صحيح
* يتضمن نموذج العرض المادي `materialized='materialized_view'` في إعداداته
* تم تشغيل كلٍّ من العرض المادي والجدول الهدف مرة واحدة على الأقل

<div id="migration-implicit-to-explicit">
  ### الترحيل من الهدف الضمني إلى الهدف المعرّف صراحةً
</div>

إذا كانت لديك نماذج عرض مادي حالية تستخدم نهج الهدف الضمني وتريد الترحيل إلى نهج الهدف المعرّف صراحةً، فاتبع الخطوات التالية:

**1. أنشئ نموذج الجدول الهدف**

أنشئ ملف نموذج جديدًا باستخدام `materialized='table'` يعرّف المخطط نفسه للجدول الهدف الحالي الخاص بـ MV. استخدم عبارة `WHERE 0` لإنشاء جدول فارغ. استخدم الاسم نفسه لنموذج العرض المادي الضمني الحالي. ستتمكن الآن من استخدام هذا النموذج لإجراء تعديلات متكررة على الجدول الهدف.

```sql theme={null}
-- models/events_daily.sql
{{
    config(
        materialized='table',
        engine='MergeTree()',
        order_by='(event_date, event_type)'
    )
}}

SELECT
    toDate(now()) AS event_date,
    '' AS event_type,
    toUInt64(0) AS total
WHERE 0
```

**2. حدِّث نماذج MV لديك**

أنشئ نماذج جديدة يتضمّن كلٌّ منها SQL الخاص بـ MV واستدعاء الماكرو `materialization_target_table()` للإشارة إلى الجدول الهدف الجديد. إذا كنت تستخدم `UNION ALL` سابقًا، فأزل ذلك الجزء والتعليقات.

بالنسبة إلى أسماء النماذج، ستحتاج إلى اتباع اصطلاح التسمية التالي:

* إذا كان هناك MV واحد فقط مُعرَّف، فسيكون اسمه: `<old_model_name>_mv`
* إذا كانت هناك عدة MVs مُعرَّفة، فسيكون اسم كلٍّ منها: `<old_model_name>_mv_<name_in_comments>`

سابقًا في `my_model.sql` (الهدف الضمني، نموذج واحد مع UNION ALL):

```sql theme={null}
--mv1:begin
select a, b, c from {{ source('raw', 'table_1') }}
--mv1:end
union all
--mv2:begin
select a, b, c from {{ source('raw', 'table_2') }}
--mv2:end
```

بعد (الهدف المُصرَّح به، ملفات نماذج منفصلة):

```sql theme={null}
-- models/my_model_mv_mv1.sql
{{ config(materialized='materialized_view') }}
{{ materialization_target_table(ref('events_daily')) }}

select a, b, c from {{ source('raw', 'table_1') }}
```

```sql theme={null}
-- models/my_model_mv_mv2.sql
{{ config(materialized='materialized_view') }}
{{ materialization_target_table(ref('events_daily')) }}

select a, b, c from {{ source('raw', 'table_2') }}
```

**3. كرّر هذه العملية حسب الحاجة باتباع الإرشادات الواردة في قسم [الهدف المحدَّد صراحةً](#explicit-target).**

<div id="behavior-comparison">
  ## مقارنة السلوك بين نهجَي الهدف الضمني والهدف الصريح
</div>

<div id="general-behavior">
  ### كيفية عملها بشكل عام
</div>

| العملية                | الهدف الضمني                                                                                                                                                                                                                                                                                                 | الهدف الصريح                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| أول تشغيل لـ dbt       | تُنشأ جميع الموارد                                                                                                                                                                                                                                                                                           | تُنشأ جميع الموارد                                                                                                                                                                                                                                                                                                                                                                                                                              |
| تشغيل dbt التالي       | **لا يمكن إدارة الموارد بشكل منفصل، إذ تتم جميع التغييرات معًا:**<br /><br />**الجدول الهدف**: <br />تُدار التغييرات باستخدام الإعداد `on_schema_change`. وتكون قيمته الافتراضية `ignore`، لذا لا تُعالَج الأعمدة الجديدة.<br /><br />**العروض المادية**: تُحدَّث جميعها بعمليات `alter table modify query`  | **يمكن تطبيق التغييرات بشكل منفصل:<br /><br />الجدول الهدف**: <br />يُكتشَف تلقائيًا ما إذا كانت هذه الجداول جداولَ هدف لعروض مادية معرّفة في dbt. وإذا كانت كذلك، فتُدار تغييرات الأعمدة افتراضيًا باستخدام الإعداد `mv_on_schema_change` بالقيمة `fail`، لذلك ستفشل العملية عند حدوث تغييرات في الأعمدة. وقد أضفنا هذه القيمة الافتراضية كطبقة حماية<br /><br />**العروض المادية**: يُحدَّث SQL الخاص بها بعمليات `alter table modify query`. |
| dbt run --full-refresh | **لا يمكن إدارة الموارد بشكل منفصل، إذ تتم جميع التغييرات معًا:<br /><br />الجدول الهدف**: <br />يُعاد إنشاء الجدول الهدف فارغًا. ويتوفر `catchup` لتهيئة backfill باستخدام SQL الخاص بجميع العروض المادية معًا. وتكون قيمة `catchup` هي `True` افتراضيًا<br /><br />**العروض المادية**: يُعاد إنشاء جميعها. | **ستُطبَّق التغييرات بشكل منفصل:<br /><br />الجدول الهدف:** سيُعاد إنشاؤه كالمعتاد.<br /><br />**العروض المادية**: حذف وإعادة إنشاء. يتوفر `catchup` لإجراء backfill أولي. وتكون قيمة `catchup` هي `True` افتراضيًا. <br /><br />**ملاحظة: أثناء العملية، سيكون الجدول الهدف فارغًا أو محمّلًا جزئيًا إلى أن يُعاد إنشاء العروض المادية. لتجنّب ذلك، راجع القسم التالي لمعرفة كيفية التكرار على الجدول الهدف.**                                 |

<div id="behavior-during-active-ingestion">
  ### السلوك أثناء الإدراج النشط
</div>

عند تكرار نماذجك، يجب أن تكون على دراية بكيفية تفاعل العمليات المختلفة مع البيانات التي يجري إدراجها:

* بما أن العروض المادية في ClickHouse تعمل بوصفها **مشغلات إدراج**، فهي لا تلتقط البيانات إلا ما دامت موجودة. وإذا حُذف عرض مادي وأُعيد إنشاؤه (على سبيل المثال أثناء `--full-refresh`)، فلن تُعالَج أي صفوف أُدرجت في جدول المصدر خلال تلك الفترة بواسطة العرض المادي. ويُشار إلى ذلك بأن العرض المادي يكون "أعمى".
* تستند جميع عمليات `catchup` المختلفة إلى عمليات `INSERT INTO ... SELECT` باستخدام SQL الخاص بالعروض المادية، وهي مستقلة عن آلية عمل العروض المادية. وبمجرد بدء `INSERT`، فإنه لا يلتقط البيانات الجديدة، لكن العرض المادي المُرفَق سيلتقطها.

يلخّص الجدول التالي مدى أمان كل عملية عندما تحدث عمليات الإدراج بشكل نشط على جدول المصدر.

<div id="ingestion-implicit-target">
  #### عمليات الهدف الضمني
</div>

| العملية                  | العملية الداخلية                                                                                                                                             | السلامة أثناء تنفيذ عمليات الإدراج                                                                                                               |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| أول `dbt run`            | 1. إنشاء الجدول الهدف<br />2. إدراج البيانات (إذا كانت `catchup=True`)<br />3. إنشاء العروض المادية                                                          | ⚠️ **يكون العرض المادي غير ملتقط للبيانات بين الخطوتين 1 و3.** أي صفوف تُدرج في المصدر خلال هذه الفترة لن يتم التقاطها.                          |
| عمليات `dbt run` اللاحقة | `ALTER TABLE ... MODIFY QUERY`                                                                                                                               | ✅ آمن. يتم تحديث العرض المادي بشكل ذري.                                                                                                          |
| `dbt run --full-refresh` | 1. إنشاء جدول احتياطي<br />2. إدراج البيانات (إذا كانت `catchup=True`)<br />3. حذف العروض المادية<br />4. EXCHANGE TABLES<br />5. إعادة إنشاء العروض المادية | ⚠️ **يكون العرض المادي غير ملتقط للبيانات أثناء إعادة الإنشاء.** البيانات التي تُدرج في المصدر بين الخطوتين 3 و5 لن تظهر في الجدول الهدف الجديد. |

<div id="ingestion-explicit-target">
  #### عمليات الهدف المحدَّد صراحةً
</div>

**نماذج العرض المادي:**

| العملية                          | العملية الداخلية                                                                     | الأمان أثناء حدوث عمليات الإدراج                                                                                                                                                                                                                                  |
| -------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| أول `dbt run`                    | 1. إنشاء MV (باستخدام العبارة `TO`)<br />2. تشغيل الاستدراك (إذا كان `catchup=True`) | ✅ يتم إنشاء MV أولًا، لذا تُلتقط عمليات الإدراج الجديدة فورًا.<br />⚠️ **قد يؤدي الاستدراك إلى تكرار البيانات** — فقد يتداخل استعلام التحميل التاريخي مع الصفوف التي تعالجها MV بالفعل. ويكون ذلك آمنًا عند استخدام محرك يزيل التكرار (مثل `ReplacingMergeTree`). |
| عمليات `dbt run` اللاحقة         | `ALTER TABLE ... MODIFY QUERY`                                                       | ✅ آمن. يتم تحديث MV بشكل ذري.                                                                                                                                                                                                                                     |
| `dbt run --full-refresh` على MVs | 1. حذف MV وإعادة إنشائها<br />2. تشغيل الاستدراك (إذا كان `catchup=True`)            | ⚠️ **تكون MV غير قادرة على الالتقاط أثناء إعادة الإنشاء** (بين الحذف والإنشاء).<br />⚠️ **قد يؤدي الاستدراك إلى تكرار البيانات** إذا كانت عمليات الإدراج تحدث بالتزامن.                                                                                           |

**نموذج الجدول الهدف:**

| العملية                                                                | العملية الداخلية                                                                                      | الأمان أثناء حدوث عمليات الإدراج                                                                                                                                  |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dbt run`                                                              | تُطبَّق تغييرات المخطط وفقًا للإعداد `mv_on_schema_change`                                            | ✅ آمن. لا توجد حركة بيانات.                                                                                                                                       |
| `dbt run --full-refresh` (الافتراضي)                                   | إعادة إنشاء الجدول (مع تركه فارغًا)                                                                   | ⚠️ **يكون الجدول الهدف فارغًا** إلى أن تعيد MVs تعبئته بالبيانات التاريخية. وتواصل MVs الإدراج في الجدول الجديد بمجرد إنشائه.                                     |
| `dbt run --full-refresh` مع `repopulate_from_mvs_on_full_refresh=True` | 1. إنشاء جدول احتياطي<br />2. إدراج البيانات باستخدام SQL الخاص بكل MV<br />3. تبديل الجداول بشكل ذري | ⚠️ **تكون MV غير قادرة على الالتقاط أثناء إعادة الإنشاء.** البيانات التي تُدرج بين الخطوتين 1 و3 لن تظهر في الجدول الجديد. **قد يتغير هذا في الإصدارات القادمة**. |

<Tip>
  **توصيات لبيئات الإنتاج ذات استيعاب البيانات النشط**

  * **أوقف استيعاب البيانات أثناء عمليات dbt إن أمكن**: فهذا يجعل جميع العمليات آمنة ويمنع فقدان أي بيانات.
  * **استخدم محركًا يزيل التكرار إن أمكن** (مثل `ReplacingMergeTree`) في الجدول الهدف للتعامل مع التكرارات المحتملة الناتجة عن تداخلات الاستدراك.
  * **فضّل `ALTER TABLE ... MODIFY QUERY`** (أي `dbt run` العادي بدون `--full-refresh`) متى أمكن — فهذا آمن دائمًا.
  * **انتبه إلى الفترات الحرجة** أثناء عمليات dbt.
</Tip>

<div id="refreshable-materialized-views">
  ## العروض المادية القابلة للتحديث
</div>

تُعد [العروض المادية القابلة للتحديث](/docs/ar/concepts/features/materialized-views/refreshable-materialized-view) نوعًا خاصًا من العروض المادية في ClickHouse، إذ تعيد تنفيذ الاستعلام دوريًا وتخزّن النتيجة، على غرار طريقة عمل العروض المادية في قواعد البيانات الأخرى. ويكون ذلك مفيدًا في الحالات التي تحتاج فيها إلى لقطات أو تجميعات دورية بدلًا من مشغّلات الإدراج الآنية.

<Tip>
  يمكن استخدام العروض المادية القابلة للتحديث مع كلٍّ من نهج [الهدف الضمني](#implicit-target) ونهج [الهدف الصريح](#explicit-target). ويكون إعداد `refreshable` مستقلًا عن طريقة إدارة الجدول الهدف.
</Tip>

لاستخدام عرض مادي قابل للتحديث، أضف كائن إعداد `refreshable` إلى نموذج MV لديك مع الخيارات التالية:

| Option                  | Description                                                                                                                                             | Required | Default Value |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------- |
| refresh\_interval       | عبارة interval (مطلوبة)                                                                                                                                 | نعم      |               |
| randomize               | عبارة التوزيع العشوائي، وتظهر بعد `RANDOMIZE FOR`                                                                                                       |          |               |
| append                  | إذا ضُبطت على `True`، فسيُدرِج كل تحديث صفوفًا في الجدول من دون حذف الصفوف الموجودة. ولا تكون عملية الإدراج ذرية، تمامًا كما في `INSERT SELECT` العادي. |          | False         |
| depends\_on             | قائمة تبعيات للعرض المادي القابل للتحديث. يُرجى تقديم التبعيات بالتنسيق التالي `{schema}.{view_name}`                                                   |          |               |
| depends\_on\_validation | ما إذا كان يجب التحقق من وجود التبعيات المحددة في `depends_on`. وإذا كانت إحدى التبعيات لا تتضمن schema، فسيُجرى التحقق على schema `default`            |          | False         |

<div id="refreshable-implicit-example">
  ### مثال على الوجهة الضمنية
</div>

```python theme={null}
{{
    config(
        materialized='materialized_view',
        engine='MergeTree()',
        order_by='(event_date)',
        refreshable={
            "interval": "EVERY 5 MINUTE",
            "randomize": "1 MINUTE",
            "append": True,
            "depends_on": ['schema.depend_on_model'],
            "depends_on_validation": True
        }
    )
}}

SELECT
    toStartOfDay(event_time) AS event_date,
    count() AS total
FROM {{ source('raw', 'events') }}
GROUP BY event_date
```

<div id="refreshable-explicit-example">
  ### مثال مع وجهة محددة صراحةً
</div>

```python theme={null}
{{
    config(
        materialized='materialized_view',
        refreshable={
            "interval": "EVERY 1 HOUR",
            "append": False
        }
    )
}}
{{ materialization_target_table(ref('events_daily')) }}

SELECT
    toStartOfDay(event_time) AS event_date,
    event_type,
    count() AS total
FROM {{ source('raw', 'events') }}
GROUP BY event_date, event_type
```

<div id="explicit-target-limitations">
  ### القيود
</div>

* عند إنشاء عرض مادي قابل للتحديث (MV) في ClickHouse وله تبعية، لا يُصدر ClickHouse
  خطأ إذا كانت التبعية المحددة غير موجودة وقت الإنشاء. وبدلًا من ذلك، يظل
  العرض المادي القابل للتحديث في حالة غير نشطة، منتظرًا استيفاء التبعية قبل أن يبدأ
  في معالجة التحديثات أو إجراء التحديث. هذا السلوك مقصود من حيث التصميم، لكنه قد يؤدي إلى
  تأخر توفر البيانات إذا لم تُعالَج التبعية المطلوبة بسرعة. لذا ينبغي التأكد من أن جميع
  التبعيات معرّفة بشكل صحيح وموجودة قبل إنشاء عرض مادي قابل للتحديث.
* حتى الآن، لا يوجد "ربط dbt" فعلي بين mv وتبعياته، ولذلك لا يكون ترتيب الإنشاء
  مضمونًا.
* لم تُختبَر ميزة التحديث مع عدة mvs تُوجَّه إلى النموذج الهدف نفسه.
