> ## 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.

> صُمِّمت محركات الجداول من عائلة `MergeTree` لمعدلات إدخال بيانات مرتفعة وأحجام بيانات هائلة.

# محرك الجدول MergeTree

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            غير مدعوم في ClickHouse Cloud
        </div>;
};

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            ميزة تجريبية. <u><a href="/docs/docs/beta-and-experimental-features#experimental-features">تعرّف على المزيد.</a></u>
        </div>;
};

يُعدّ المحرّك `MergeTree` وغيره من محركات عائلة `MergeTree` (مثل `ReplacingMergeTree` و `AggregatingMergeTree`) من أكثر محركات الجداول استخدامًا وأكثرها متانة في ClickHouse.

صُمِّمت محركات الجداول من عائلة `MergeTree` لدعم معدلات عالية من إدخال البيانات وأحجام بيانات هائلة.
وتُنشئ عمليات الإدخال أجزاءً للجدول، ثم تدمجها عملية تعمل في الخلفية مع أجزاء جدول أخرى.

الميزات الرئيسية لمحركات الجداول من عائلة `MergeTree`.

* يحدّد المفتاح الأساسي للجدول ترتيب الفرز داخل كل جزء من الجدول (فهرس عنقودي). كما أن المفتاح الأساسي لا يشير إلى صفوف فردية، بل إلى كتل من 8192 صفًا تُسمى حبيبات. وهذا يجعل المفاتيح الأساسية لمجموعات البيانات الضخمة صغيرة بما يكفي لتبقى محمّلة في الذاكرة الرئيسية، مع استمرار توفير وصول سريع إلى البيانات المخزّنة على القرص.

* يمكن تقسيم الجداول باستخدام تعبير تقسيم عشوائي. ويضمن تقسيم pruning استبعاد الأقسام من القراءة عندما يتيح الاستعلام ذلك.

* يمكن نسخ البيانات عبر عدة عقد في cluster لتحقيق التوفّر العالي، وfailover، والترقيات من دون downtime. راجع [نسخ البيانات](/docs/ar/reference/engines/table-engines/mergetree-family/replication).

* تدعم محركات الجداول `MergeTree` أنواعًا مختلفة من الإحصاءات وطرائق أخذ العينات للمساعدة في query optimization.

<Note>
  على الرغم من تشابه الاسم، فإن المحرّك [Merge](/docs/ar/reference/engines/table-engines/special/merge) يختلف عن محركات `*MergeTree`.
</Note>

<div id="table_engine-mergetree-creating-a-table">
  ## إنشاء الجداول
</div>

```sql theme={null}
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr1] [COMMENT ...] [CODEC(codec1)] [STATISTICS(stat1)] [TTL expr1] [PRIMARY KEY] [SETTINGS (name = value, ...)],
    name2 [type2] [[NOT] NULL] [DEFAULT|MATERIALIZED|ALIAS|EPHEMERAL expr2] [COMMENT ...] [CODEC(codec2)] [STATISTICS(stat2)] [TTL expr2] [PRIMARY KEY] [SETTINGS (name = value, ...)],
    ...
    INDEX index_name1 expr1 TYPE type1(...) [GRANULARITY value1],
    INDEX index_name2 expr2 TYPE type2(...) [GRANULARITY value2],
    ...
    PROJECTION projection_name_1 (SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY]),
    PROJECTION projection_name_2 (SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY])
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr
    [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx' [, ...] ]
    [WHERE conditions]
    [GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ] ]
[SETTINGS name = value, ...]
```

للاطلاع على وصف مفصل للمعلمات، راجع تعليمة [CREATE TABLE](/docs/ar/reference/statements/create/table)

<div id="mergetree-query-clauses">
  ### عبارات الاستعلام
</div>

<div id="engine">
  #### ENGINE
</div>

`ENGINE` — اسم المحرّك ومعلماته. `ENGINE = MergeTree()`. لا يحتوي محرّك `MergeTree` على أي معلمات.

<div id="order_by">
  #### ORDER BY
</div>

`ORDER BY` — مفتاح الفرز.

`Tuple` من أسماء الأعمدة أو تعبيرات عشوائية. مثال: `ORDER BY (CounterID + 1, EventDate)`.

إذا لم يكن هناك مفتاح أساسي مُعرّف (أي لم يتم تحديد `PRIMARY KEY`)، يستخدم ClickHouse مفتاح الفرز بوصفه المفتاح الأساسي.

إذا لم تكن هناك حاجة إلى الفرز، يمكنك استخدام الصياغة `ORDER BY tuple()`.
وبدلاً من ذلك، إذا كان الإعداد `create_table_empty_primary_key_by_default` مفعّلًا، فستُضاف `ORDER BY ()` ضمنيًا إلى عبارات `CREATE TABLE`. راجع [Selecting a Primary Key](#selecting-a-primary-key).

<div id="partition-by">
  #### PARTITION BY
</div>

`PARTITION BY` — [مفتاح التقسيم](/docs/ar/reference/engines/table-engines/mergetree-family/custom-partitioning-key). وهو اختياري. في معظم الحالات، لا تحتاج إلى مفتاح تقسيم، وحتى إذا احتجت إلى التقسيم، فغالبًا لا تحتاج إلى مفتاح تقسيم أكثر دقة من التقسيم حسب الشهر. لا يسرّع التقسيم الاستعلامات (على عكس تعبير ORDER BY). يجب ألّا تستخدم مطلقًا تقسيمًا مفرط الدقة. لا تقسّم بياناتك حسب معرّفات العملاء أو الأسماء (وعوضًا عن ذلك، اجعل معرّف العميل أو الاسم هو العمود الأول في تعبير ORDER BY).

للتقسيم حسب الشهر، استخدم التعبير `toYYYYMM(date_column)`، حيث إن `date_column` هو عمود يحتوي على تاريخ من النوع [Date](/docs/ar/reference/data-types/date). وتكون أسماء الأقسام هنا بالتنسيق `"YYYYMM"`.

<div id="primary-key">
  #### PRIMARY KEY
</div>

`PRIMARY KEY` — المفتاح الأساسي إذا كان [يختلف عن مفتاح الفرز](#choosing-a-primary-key-that-differs-from-the-sorting-key). وهو اختياري.

إن تحديد مفتاح فرز (باستخدام عبارة `ORDER BY`) يعني ضمنيًا تحديد مفتاح أساسي.
وعادةً لا تكون هناك حاجة إلى تحديد المفتاح الأساسي إلى جانب مفتاح الفرز.

<div id="sample-by">
  #### SAMPLE BY
</div>

`SAMPLE BY` — تعبير لأخذ العينات. اختياري.

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

مثال: `SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))`.

<div id="ttl">
  #### TTL
</div>

`TTL` — قائمة بالقواعد التي تحدد مدة الاحتفاظ بالصفوف ومنطق [نقل الأجزاء تلقائيًا بين الأقراص ووحدات التخزين](#table_engine-mergetree-multiple-volumes). اختياري.

يجب أن يُرجِع التعبير قيمة من النوع `Date` أو `DateTime`، مثل `TTL date + INTERVAL 1 DAY`.

يحدد نوع القاعدة `DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'|GROUP BY` الإجراء الذي يجب تنفيذه على الجزء عند تحقق التعبير (أي عند بلوغه الوقت الحالي): حذف الصفوف منتهية الصلاحية، أو نقل جزء (إذا تحقق التعبير لجميع الصفوف في الجزء) إلى القرص المحدد (`TO DISK 'xxx'`) أو إلى وحدة التخزين (`TO VOLUME 'xxx'`)، أو تجميع القيم في الصفوف منتهية الصلاحية. النوع الافتراضي للقاعدة هو الحذف (`DELETE`). يمكن تحديد قائمة تضم عدة قواعد، لكن يجب ألا تكون هناك أكثر من قاعدة `DELETE` واحدة.

لمزيد من التفاصيل، راجع [TTL للأعمدة والجداول](#table_engine-mergetree-ttl)

<div id="settings">
  #### الإعدادات
</div>

انظر [إعدادات MergeTree](/docs/ar/reference/settings/merge-tree-settings).

**مثال على إعداد Sections**

```sql theme={null}
ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate, intHash32(UserID)) SAMPLE BY intHash32(UserID) SETTINGS index_granularity=8192
```

في المثال، نضبط التقسيم حسب الشهر.

كما نضبط تعبيرًا لأخذ العينات على هيئة `hash` استنادًا إلى معرّف المستخدم. يتيح لك ذلك توزيع البيانات في الجدول توزيعًا شبه عشوائي لكل من `CounterID` و`EventDate`. وإذا حدّدت عبارة [SAMPLE](/docs/ar/reference/statements/select/sample) عند اختيار البيانات، فسيُرجع ClickHouse عيّنة بيانات شبه عشوائية ومتوازنة لمجموعة فرعية من المستخدمين.

يمكن حذف إعداد `index_granularity` لأن 8192 هي القيمة الافتراضية.

<details markdown="1">
  <summary>طريقة مُهملة لإنشاء جدول</summary>

  <Note>
    لا تستخدم هذه الطريقة في المشاريع الجديدة. وإذا أمكن، انقل المشاريع القديمة إلى الطريقة الموضحة أعلاه.
  </Note>

  ```sql theme={null}
  CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
  (
      name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
      name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
      ...
  ) ENGINE [=] MergeTree(date-column [, sampling_expression], (primary, key), index_granularity)
  ```

  **معلمات MergeTree()**

  * `date-column` — اسم عمود من النوع [Date](/docs/ar/reference/data-types/date). ينشئ ClickHouse الأقسام تلقائيًا حسب الشهر استنادًا إلى هذا العمود. وتكون أسماء الأقسام بالتنسيق `"YYYYMM"`.
  * `sampling_expression` — تعبير لأخذ العينات.
  * `(primary, key)` — المفتاح الأساسي. النوع: [Tuple()](/docs/ar/reference/data-types/tuple)
  * `index_granularity` — دقة الفهرس. وهو عدد صفوف البيانات بين "العلامات" في الفهرس. القيمة 8192 مناسبة لمعظم المهام.

  **مثال**

  ```sql theme={null}
  MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
  ```

  يُهيَّأ محرّك `MergeTree` بالطريقة نفسها المستخدَمة في المثال أعلاه ضمن طريقة تهيئة المحرّك الرئيسية.
</details>

<div id="mergetree-data-storage">
  ## تخزين البيانات
</div>

يتكوّن الجدول من أجزاء بيانات مرتّبة حسب المفتاح الأساسي.

عند إدراج البيانات في جدول، تُنشأ أجزاء بيانات منفصلة، ويُرتَّب كل جزء منها ترتيبًا معجميًا حسب المفتاح الأساسي. على سبيل المثال، إذا كان المفتاح الأساسي هو `(CounterID, Date)`، فإن البيانات داخل الجزء تُرتَّب حسب `CounterID`، وضمن كل `CounterID` تُرتَّب حسب `Date`.

تُفصل البيانات التابعة لتقسيمات مختلفة في أجزاء مختلفة. وفي الخلفية، يدمج ClickHouse أجزاء البيانات لتحقيق تخزين أكثر كفاءة. ولا تُدمج الأجزاء التابعة لتقسيمات مختلفة. كما أن آلية الدمج لا تضمن وجود جميع الصفوف التي لها المفتاح الأساسي نفسه ضمن جزء البيانات نفسه.

يمكن تخزين أجزاء البيانات بتنسيق `Wide` أو `Compact`. ففي تنسيق `Wide` يُخزَّن كل عمود في ملف منفصل ضمن نظام الملفات، أما في تنسيق `Compact` فتُخزَّن جميع الأعمدة في ملف واحد. ويمكن استخدام تنسيق `Compact` لتحسين أداء عمليات الإدراج الصغيرة والمتكررة.

يتحكم في تنسيق تخزين البيانات الإعدادان `min_bytes_for_wide_part` و`min_rows_for_wide_part` الخاصان بمحرك الجدول. فإذا كان عدد البايتات أو الصفوف في جزء البيانات أقل من قيمة الإعداد المقابل، يُخزَّن الجزء بتنسيق `Compact`. وإلا فيُخزَّن بتنسيق `Wide`. وإذا لم يُضبط أيّ من هذين الإعدادين، فتُخزَّن أجزاء البيانات بتنسيق `Wide`.

يُقسَّم كل جزء بيانات منطقيًا إلى حبيبات. والحبيبة هي أصغر مجموعة بيانات غير قابلة للتجزئة يقرؤها ClickHouse عند تحديد البيانات. ولا يُجزِّئ ClickHouse الصفوف أو القيم، لذلك تحتوي كل حبيبة دائمًا على عدد صحيح من الصفوف. ويُعلَّم الصف الأول من الحبيبة بقيمة المفتاح الأساسي لذلك الصف. ولكل جزء بيانات، ينشئ ClickHouse ملف فهرس يخزّن العلامات. ولكل عمود، سواء أكان ضمن المفتاح الأساسي أم لا، يخزّن ClickHouse أيضًا العلامات نفسها. وتتيح لك هذه العلامات العثور على البيانات مباشرةً داخل ملفات الأعمدة.

يُقيَّد حجم الحبيبة بالإعدادين `index_granularity` و`index_granularity_bytes` الخاصين بمحرك الجدول. ويقع عدد الصفوف في الحبيبة ضمن النطاق `[1, index_granularity]`، وذلك بحسب حجم الصفوف. وقد يتجاوز حجم الحبيبة `index_granularity_bytes` إذا كان حجم صف واحد أكبر من قيمة الإعداد. وفي هذه الحالة، يكون حجم الحبيبة مساويًا لحجم الصف.

<div id="primary-keys-and-indexes-in-queries">
  ## المفاتيح الأساسية والفهارس في الاستعلامات
</div>

خذ المفتاح الأساسي `(CounterID, Date)` على سبيل المثال. في هذه الحالة، يمكن توضيح الفرز والفهرس كما يلي:

```text theme={null}
Whole data:     [---------------------------------------------]
CounterID:      [aaaaaaaaaaaaaaaaaabbbbcdeeeeeeeeeeeeefgggggggghhhhhhhhhiiiiiiiiikllllllll]
Date:           [1111111222222233331233211111222222333211111112122222223111112223311122333]
Marks:           |      |      |      |      |      |      |      |      |      |      |
                a,1    a,2    a,3    b,3    e,2    e,3    g,1    h,2    i,1    i,3    l,3
Marks numbers:   0      1      2      3      4      5      6      7      8      9      10
```

إذا كان استعلام البيانات يحدد ما يلي:

* `CounterID in ('a', 'h')`، يقرأ الخادم البيانات ضمن نطاقات العلامات `[0, 3)` و`[6, 8)`.
* `CounterID IN ('a', 'h') AND Date = 3`، يقرأ الخادم البيانات ضمن نطاقات العلامات `[1, 3)` و`[7, 8)`.
* `Date = 3`، يقرأ الخادم البيانات ضمن نطاق العلامات `[1, 10]`.

تُظهر الأمثلة أعلاه أن استخدام فهرس يكون دائمًا أكثر فعالية من إجراء فحص كامل.

يسمح الفهرس المتناثر بقراءة بيانات إضافية. عند قراءة نطاق واحد من المفتاح الأساسي، يمكن قراءة ما يصل إلى `index_granularity * 2` من الصفوف الإضافية في كل كتلة بيانات.

تتيح لك الفهارس المتناثرة العمل مع عدد كبير جدًا من صفوف الجدول، لأن مثل هذه الفهارس تتسع في معظم الحالات داخل RAM الخاصة بالحاسوب.

لا يتطلب ClickHouse مفتاحًا أساسيًا فريدًا. يمكنك إدراج عدة صفوف بالمفتاح الأساسي نفسه.

يمكنك استخدام تعبيرات من النوع `Nullable` في عبارتي `PRIMARY KEY` و`ORDER BY`، ولكن لا يُنصح بذلك بشدة. للسماح بهذه الميزة، فعِّل الإعداد [allow\_nullable\_key](/docs/ar/reference/settings/merge-tree-settings#allow_nullable_key). وينطبق مبدأ [NULLS\_LAST](/docs/ar/reference/statements/select/order-by#sorting-of-special-values) على قيم `NULL` في عبارة `ORDER BY`.

<div id="selecting-a-primary-key">
  ### اختيار مفتاح أساسي
</div>

عدد الأعمدة في المفتاح الأساسي غير محدود صراحةً. وبحسب بنية البيانات، يمكنك تضمين عدد أكبر أو أقل من الأعمدة في المفتاح الأساسي. وقد يترتب على ذلك ما يلي:

* تحسين أداء الفهرس.

  إذا كان المفتاح الأساسي هو `(a, b)`، فإن إضافة عمود آخر `c` ستحسّن الأداء إذا تحققت الشروط التالية:

  * وجود استعلامات تتضمن شرطًا على العمود `c`.
  * شيوع نطاقات بيانات طويلة (أطول عدة مرات من `index_granularity`) ذات القيم المتطابقة لـ `(a, b)`. وبعبارة أخرى، عندما تتيح لك إضافة عمود آخر تخطي نطاقات بيانات طويلة نسبيًا.

* تحسين ضغط البيانات.

  يرتّب ClickHouse البيانات حسب المفتاح الأساسي، لذا كلما زاد التجانس كان الضغط أفضل.

* توفير منطق إضافي عند دمج أجزاء البيانات في المحرّكين [CollapsingMergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/collapsingmergetree) و[SummingMergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/summingmergetree).

  في هذه الحالة، من المنطقي تحديد *مفتاح فرز* يختلف عن المفتاح الأساسي.

يؤثر المفتاح الأساسي الطويل سلبًا في أداء الإدراج واستهلاك الذاكرة، لكن الأعمدة الإضافية في المفتاح الأساسي لا تؤثر في أداء ClickHouse أثناء استعلامات `SELECT`.

يمكنك إنشاء جدول من دون مفتاح أساسي باستخدام الصياغة `ORDER BY tuple()`. في هذه الحالة، يخزّن ClickHouse البيانات بترتيب إدراجها. وإذا كنت تريد الحفاظ على ترتيب البيانات عند إدراجها بواسطة استعلامات `INSERT ... SELECT`، فاضبط [max\_insert\_threads = 1](/docs/ar/reference/settings/session-settings#max_insert_threads).

لاختيار البيانات بالترتيب الأصلي، استخدم استعلامات `SELECT` [أحادية الخيط](/docs/ar/reference/settings/session-settings#max_threads).

<div id="choosing-a-primary-key-that-differs-from-the-sorting-key">
  ### اختيار مفتاح أساسي يختلف عن مفتاح الفرز
</div>

يمكن تحديد مفتاح أساسي (تعبير بقيم تُكتب في ملف الفهرس لكل علامة) يختلف عن مفتاح الفرز (تعبير لفرز الصفوف في أجزاء البيانات). في هذه الحالة، يجب أن تكون مجموعة تعبيرات المفتاح الأساسي بادئةً لمجموعة تعبيرات مفتاح الفرز.

تكون هذه الميزة مفيدة عند استخدام محركات الجداول [SummingMergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/summingmergetree) و
[AggregatingMergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/aggregatingmergetree). في الحالة الشائعة عند استخدام هذه المحركات، يحتوي الجدول على نوعين من الأعمدة: *الأبعاد* و*المقاييس*. عادةً ما تُجمِّع الاستعلامات قيم أعمدة المقاييس باستخدام `GROUP BY` عشوائي، مع التصفية بحسب الأبعاد. ولأن SummingMergeTree وAggregatingMergeTree يدمجان الصفوف التي لها القيمة نفسها لمفتاح الفرز، فمن الطبيعي إضافة جميع الأبعاد إليه. ونتيجةً لذلك، يتكوّن تعبير المفتاح من قائمة طويلة من الأعمدة، ويجب تحديث هذه القائمة باستمرار عند إضافة أبعاد جديدة.

في هذه الحالة، من المنطقي الإبقاء على بضعة أعمدة فقط في المفتاح الأساسي لتوفير مسح نطاقات بكفاءة، وإضافة بقية أعمدة الأبعاد إلى مجموعة مفتاح الفرز.

يُعد [ALTER](/docs/ar/reference/statements/alter/index) لمفتاح الفرز عملية خفيفة، لأنه عند إضافة عمود جديد في الوقت نفسه إلى الجدول وإلى مفتاح الفرز، لا تحتاج أجزاء البيانات الحالية إلى أي تغيير. وبما أن مفتاح الفرز القديم هو بادئة لمفتاح الفرز الجديد، ولا توجد بيانات في العمود المُضاف حديثًا، فإن البيانات تكون مرتبةً وفقًا لمفتاحي الفرز القديم والجديد معًا عند تعديل الجدول.

<div id="use-of-indexes-and-partitions-in-queries">
  ### استخدام الفهارس والتقسيمات في الاستعلامات
</div>

بالنسبة إلى استعلامات `SELECT`، يحلّل ClickHouse ما إذا كان يمكن استخدام فهرس. ويمكن استخدام الفهرس إذا كانت عبارة `WHERE/PREWHERE` تتضمن تعبيرًا (إما كأحد عناصر الاقتران أو بالكامل) يمثّل عملية مقارنة مساواة أو عدم مساواة، أو إذا كانت تتضمن `IN` أو `LIKE` مع بادئة ثابتة على أعمدة أو تعبيرات موجودة في المفتاح الأساسي أو مفتاح التقسيم، أو على بعض الدوال الجزئية التكرار لهذه الأعمدة، أو على العلاقات المنطقية بين هذه التعبيرات.

وبذلك، يصبح من الممكن تنفيذ الاستعلامات بسرعة على نطاق واحد أو عدة نطاقات من المفتاح الأساسي. في هذا المثال، ستكون الاستعلامات سريعة عند تنفيذها لوسم تتبّع محدد، أو لوسم محدد مع نطاق زمني محدد، أو لوسم محدد مع تاريخ محدد، أو لعدة وسوم مع نطاق زمني، وهكذا.

لنلقِ نظرة على الـ محرّك المُعَدّ كما يلي:

```sql theme={null}
ENGINE MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate)
SETTINGS index_granularity=8192
```

في هذه الحالة، ضمن الاستعلامات:

```sql theme={null}
SELECT count() FROM table
WHERE EventDate = toDate(now())
AND CounterID = 34

SELECT count() FROM table
WHERE EventDate = toDate(now())
AND (CounterID = 34 OR CounterID = 42)

SELECT count() FROM table
WHERE ((EventDate >= toDate('2014-01-01')
AND EventDate <= toDate('2014-01-31')) OR EventDate = toDate('2014-05-01'))
AND CounterID IN (101500, 731962, 160656)
AND (CounterID = 101500 OR EventDate != toDate('2014-05-01'))
```

سيستخدم ClickHouse فهرس المفتاح الأساسي لاستبعاد البيانات غير ذات الصلة، ومفتاح التقسيم الشهري لاستبعاد الأقسام الواقعة ضمن نطاقات تاريخ غير ذات صلة.

تُظهر الاستعلامات أعلاه أن الفهرس يُستخدم حتى مع التعبيرات المعقدة. وتُنظَّم القراءة من الجدول بحيث لا يمكن أن يكون استخدام الفهرس أبطأ من إجراء فحص كامل.

في المثال أدناه، لا يمكن استخدام الفهرس.

```sql theme={null}
SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%'
```

للتحقق مما إذا كان ClickHouse يستطيع استخدام الفهرس عند تنفيذ استعلام، استخدم الإعدادين [force\_index\_by\_date](/docs/ar/reference/settings/session-settings#force_index_by_date) و[force\_primary\_key](/docs/ar/reference/settings/session-settings#force_primary_key).

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

<div id="use-of-index-for-deterministic-expressions-in-primary-keys">
  ### استخدام الفهرس مع التعبيرات الحتمية في المفاتيح الأساسية
</div>

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

يُعدّ التعبير **حتميًا** إذا كان يعيد دائمًا النتيجة نفسها لقيم الإدخال نفسها (على سبيل المثال: `length()`, `toDate()`, `lower()`, `left()`, `cityHash64()`, `toUUID()`؛ بخلاف `now()` أو `rand()`). وإذا كان المفتاح الأساسي يحتوي على تعبيرات حتمية، يمكن لـ ClickHouse تطبيقها على القيم الثابتة في الاستعلام واستخدام النتيجة لبناء شروط على فهرس المفتاح الأساسي. وهذا يتيح تخطّي البيانات لعبارات الشرط مثل `=`, `IN`, و `has`.

ومن حالات الاستخدام الشائعة إبقاء المفتاح الأساسي مضغوطًا (مثل تخزين قيمة hash بدلًا من `String` طويل)، مع الاستمرار في إتاحة استخدام الفهرس لعبارات الشرط على العمود الأصلي.

مثال على مفتاح أساسي حتمي (لكن غير حقني):

```sql theme={null}
ENGINE = MergeTree()
ORDER BY length(user_id)
```

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

```sql theme={null}
SELECT * FROM table WHERE user_id = 'alice';
SELECT * FROM table WHERE user_id IN ('alice', 'bob');
SELECT * FROM table WHERE has(['alice', 'bob'], user_id);
```

في هذه الحالات، يحسب ClickHouse قيمة `length('alice')` (وسائر الثوابت) مرةً واحدة، ثم يستخدم قيم الأطوال لتضييق النطاقات في فهرس المفتاح الأساسي. وبما أن طول السلسلة **ليس حقنيًا**، فقد تتشارك سلاسل `user_id` المختلفة الطول نفسه، لذلك قد يقرأ الفهرس حبيبات إضافية (مطابقات إيجابية كاذبة). ومع ذلك، تظل النتيجة صحيحة لأن الشرط الأصلي (`user_id = ...` و`IN` وما إلى ذلك) يظل مطبَّقًا بعد القراءة.

إذا كان التعبير الحتمي أيضًا **حقنيًا** (أي إن المدخلات المختلفة لا يمكن أن تنتج المخرج نفسه لأنواع `argument` المستخدمة)، فبوسع ClickHouse أيضًا استخدام الفهرس بفاعلية مع الصيغ المنفية: `!=` و`NOT IN` و`NOT has(...)`. على سبيل المثال، الدالتان `reverse(p)` و`hex(p)` حقنيتان بالنسبة إلى `String`.

مثال على مفتاح أساسي حقني:

```sql theme={null}
ENGINE = MergeTree()
ORDER BY hex(p)
```

كما تُدعَم أيضًا التعبيرات الحقنية الأكثر تعقيدًا، على سبيل المثال:

```sql theme={null}
ENGINE = MergeTree()
ORDER BY reverse(tuple(reverse(p), hex(p)))
```

أمثلة على الشروط التي يمكن أن تستخدم الفهرس:

```sql theme={null}
SELECT * FROM table WHERE p != 'abc';
SELECT * FROM table WHERE p NOT IN ('abc', '12345');
SELECT * FROM table WHERE NOT has(['abc', '12345'], p);
```

<div id="use-of-index-for-partially-monotonic-primary-keys">
  ### استخدام الفهرس مع المفاتيح الأساسية الرتيبة جزئيًا
</div>

لنأخذ، على سبيل المثال، أيام الشهر. فهي تُشكّل [تسلسلاً رتيبًا](https://en.wikipedia.org/wiki/Monotonic_function) داخل شهر واحد، لكنها لا تكون رتيبة على مدى فترات أطول. هذا تسلسل رتيب جزئيًا. إذا أنشأ المستخدم جدولًا بمفتاح أساسي رتيب جزئيًا، ينشئ ClickHouse فهرسًا متناثرًا كالمعتاد. وعندما يستعلم المستخدم عن بيانات من هذا النوع من الجداول، يحلّل ClickHouse شروط الاستعلام. فإذا أراد المستخدم الحصول على بيانات بين علامتين من الفهرس، وكانت كلتا العلامتين تقعان ضمن شهر واحد، يمكن لـ ClickHouse استخدام الفهرس في هذه الحالة تحديدًا، لأنه يستطيع حساب المسافة بين معلمات الاستعلام وعلامات الفهرس.

لا يمكن لـ ClickHouse استخدام الفهرس إذا كانت قيم المفتاح الأساسي ضمن نطاق معلمات الاستعلام لا تمثل تسلسلاً رتيبًا. في هذه الحالة، يستخدم ClickHouse أسلوب المسح الكامل.

يستخدم ClickHouse هذا المنطق ليس فقط مع تسلسلات أيام الشهر، بل مع أي مفتاح أساسي يمثّل تسلسلاً رتيبًا جزئيًا.

<div id="table_engine-mergetree-data_skipping-indexes">
  ### فهارس تخطي البيانات
</div>

يرد تعريف الفهرس في قسم الأعمدة ضمن استعلام `CREATE`.

```sql theme={null}
INDEX index_name expr TYPE type(...) [GRANULARITY granularity_value]
```

بالنسبة إلى الجداول من عائلة `*MergeTree`، يمكن تحديد فهارس تخطي البيانات.

تجمع هذه الفهارس بعض المعلومات عن التعبير المحدد على مستوى الكتل، التي تتكوّن من `granularity_value` من الحبيبات (ويُحدَّد حجم الحبيبة باستخدام الإعداد `index_granularity` في محرك الجدول). ثم تُستخدم هذه القيم المجمّعة في استعلامات `SELECT` لتقليل كمية البيانات المطلوب قراءتها من القرص، وذلك عبر تخطي كتل كبيرة من البيانات التي لا يمكن لعبارة `where` أن تستوفي الشرط فيها.

يمكن حذف العبارة `GRANULARITY`، والقيمة الافتراضية لـ `granularity_value` هي 1.

**مثال**

```sql theme={null}
CREATE TABLE table_name
(
    u64 UInt64,
    i32 Int32,
    s String,
    ...
    INDEX idx1 u64 TYPE bloom_filter GRANULARITY 3,
    INDEX idx2 u64 * i32 TYPE minmax GRANULARITY 3,
    INDEX idx3 u64 * length(s) TYPE set(1000) GRANULARITY 4
) ENGINE = MergeTree()
...
```

يمكن لـ ClickHouse استخدام الفهارس الواردة في المثال لتقليل حجم البيانات المقروءة من القرص في الاستعلامات التالية:

```sql theme={null}
SELECT count() FROM table WHERE u64 == 10;
SELECT count() FROM table WHERE u64 * i32 >= 1234
SELECT count() FROM table WHERE u64 * length(s) == 1234
```

يمكن أيضًا إنشاء فهارس لتخطي البيانات على الأعمدة المركبة:

```sql theme={null}
-- on columns of type Map:
INDEX map_key_index mapKeys(map_column) TYPE bloom_filter
INDEX map_value_index mapValues(map_column) TYPE bloom_filter

-- on columns of type JSON:
INDEX json_paths_index JSONAllPaths(json_column) TYPE bloom_filter

-- on columns of type Tuple:
INDEX tuple_1_index tuple_column.1 TYPE bloom_filter
INDEX tuple_2_index tuple_column.2 TYPE bloom_filter

-- on columns of type Nested:
INDEX nested_1_index col.nested_col1 TYPE bloom_filter
INDEX nested_2_index col.nested_col2 TYPE bloom_filter
```

<div id="skip-index-types">
  ### أنواع فهارس التخطي
</div>

يدعم محرك الجدول `MergeTree` الأنواع التالية من فهارس التخطي.
لمزيد من المعلومات حول كيفية استخدام فهارس التخطي لتحسين الأداء،
راجِع ["فهم فهارس تخطي البيانات في ClickHouse"](/docs/ar/concepts/features/performance/skip-indexes/skipping-indexes).

* فهرس [`MinMax`](#minmax)
* فهرس [`Set`](#set)
* فهرس [`bloom_filter`](#bloom-filter)
* فهرس [`ngrambf_v1`](#n-gram-bloom-filter) *(مهمل)*
* فهرس [`tokenbf_v1`](#token-bloom-filter) *(مهمل)*
* فهرس [`text`](#text)
* فهرس [`vector_similarity`](#vector-similarity)

<div id="minmax">
  #### فهرس التخطي MinMax
</div>

لكل حبيبة فهرس، تُخزَّن القيمتان الصغرى والكبرى لتعبير ما.
(إذا كان التعبير من النوع `tuple`، فإنه يخزّن القيمتين الصغرى والكبرى لكل عنصر من عناصر الـ `tuple`.)

```text title="Syntax" theme={null}
minmax
```

<div id="set">
  #### Set
</div>

يُخزَّن لكل كتلة فهرس ما يصل إلى `max_rows` من القيم الفريدة للتعبير المحدد.
ويعني `max_rows = 0` "تخزين جميع القيم الفريدة".

```text title="Syntax" theme={null}
set(max_rows)
```

<div id="bloom-filter">
  #### مرشح Bloom
</div>

يُخزَّن [مرشح Bloom](https://en.wikipedia.org/wiki/Bloom_filter) لكل حبيبة فهرس للأعمدة المحددة.

```text title="Syntax" theme={null}
bloom_filter([false_positive_rate])
```

يمكن أن تأخذ المعلمة `false_positive_rate` قيمة بين 0 و1 (القيمة الافتراضية: `0.025`) وتحدّد احتمال توليد نتيجة إيجابية، مما يزيد كمية البيانات المقروءة.

أنواع البيانات التالية مدعومة:

* `(U)Int*`
* `Float*`
* `Enum`
* `Date`
* `DateTime`
* `String`
* `FixedString`
* `Array`
* `LowCardinality`
* `Nullable`
* `UUID`
* `Map`

<Info>
  **نوع البيانات Map: تحديد إنشاء الفهرس على المفاتيح أو القيم**

  بالنسبة إلى نوع البيانات `Map`، يمكن للعميل تحديد ما إذا كان يجب إنشاء الفهرس على المفاتيح أو على القيم باستخدام الدالتين [`mapKeys`](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapKeys) أو [`mapValues`](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapValues).
</Info>

<Info>
  **نوع البيانات JSON: فهرسة مسارات JSON**

  بالنسبة إلى نوع البيانات [`JSON`](/docs/ar/reference/data-types/newjson)، يمكن إنشاء فهرس bloom filter على مجموعة المسارات باستخدام الدالة [`JSONAllPaths`](/docs/ar/reference/functions/regular-functions/json-functions#JSONAllPaths). يتيح ذلك تخطي الحبيبات التي لا يحتوي فيها الاستعلام على مسار JSON موجود. راجع [فهارس تخطي البيانات لـ JSON](/docs/ar/reference/data-types/newjson#data-skipping-indexes-for-json) لمزيد من التفاصيل.
</Info>

<div id="n-gram-bloom-filter">
  #### مرشح Bloom لـ N-gram *(مهمل)*
</div>

<Note>
  مع الوصول إلى مرحلة التوافر العام (GA) لفهرس `text` بدءًا من إصدار ClickHouse 26.2، لم يعد يُوصى باستخدام الفهرس `ngrambf_v1` في البحث في النص الكامل.

  راجع صفحة ["البحث في النص الكامل باستخدام فهارس النص"](/docs/ar/reference/engines/table-engines/mergetree-family/textindexes) لمزيد من التفاصيل.
</Note>

يُخزِّن كل حبيبة فهرس [مرشح Bloom](https://en.wikipedia.org/wiki/Bloom_filter) لـ [n-grams](https://en.wikipedia.org/wiki/N-gram) الخاصة بالأعمدة المحددة.

```text title="Syntax" theme={null}
ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
```

| Parameter                       | Description                                                                                                     |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `n`                             | حجم ngram                                                                                                       |
| `size_of_bloom_filter_in_bytes` | حجم مرشح bloom بالبايتات. يمكنك استخدام قيمة كبيرة هنا، على سبيل المثال `256` أو `512`، لأنه يمكن ضغطه بكفاءة). |
| `number_of_hash_functions`      | عدد دوال hash المستخدمة في مرشح bloom.                                                                          |
| `random_seed`                   | البذرة لدوال hash الخاصة بمرشح bloom.                                                                           |

لا يعمل هذا الفهرس إلا مع أنواع البيانات التالية:

* [`String`](/docs/ar/reference/data-types/string)
* [`FixedString`](/docs/ar/reference/data-types/fixedstring)
* [`Map`](/docs/ar/reference/data-types/map)

لتقدير معلمات `ngrambf_v1`، يمكنك استخدام [الدوال المعرّفة من قبل المستخدم (UDFs)](/docs/ar/reference/statements/create/function) التالية.

```sql title="UDFs for ngrambf_v1" theme={null}
CREATE FUNCTION bfEstimateFunctions [ON CLUSTER cluster]
AS
(total_number_of_all_grams, size_of_bloom_filter_in_bits) -> round((size_of_bloom_filter_in_bits / total_number_of_all_grams) * log(2));

CREATE FUNCTION bfEstimateBmSize [ON CLUSTER cluster]
AS
(total_number_of_all_grams, probability_of_false_positives) -> ceil((total_number_of_all_grams * log(probability_of_false_positives)) / log(1 / pow(2, log(2))));

CREATE FUNCTION bfEstimateFalsePositive [ON CLUSTER cluster]
AS
(total_number_of_all_grams, number_of_hash_functions, size_of_bloom_filter_in_bytes) -> pow(1 - exp(-number_of_hash_functions/ (size_of_bloom_filter_in_bytes / total_number_of_all_grams)), number_of_hash_functions);

CREATE FUNCTION bfEstimateGramNumber [ON CLUSTER cluster]
AS
(number_of_hash_functions, probability_of_false_positives, size_of_bloom_filter_in_bytes) -> ceil(size_of_bloom_filter_in_bytes / (-number_of_hash_functions / log(1 - exp(log(probability_of_false_positives) / number_of_hash_functions))))
```

لاستخدام هذه الدوال، تحتاج إلى تحديد معلَمتين على الأقل:

* `total_number_of_all_grams`
* `probability_of_false_positives`

على سبيل المثال، إذا كان هناك `4300` ngrams في الـ حبيبة، وكنت تتوقع أن تكون الإيجابيات الكاذبة أقل من `0.0001`،
فيمكن بعد ذلك تقدير المعلَمات الأخرى بتنفيذ الاستعلامات التالية:

```sql theme={null}
--- estimate number of bits in the filter
SELECT bfEstimateBmSize(4300, 0.0001) / 8 AS size_of_bloom_filter_in_bytes;

┌─size_of_bloom_filter_in_bytes─┐
│                         10304 │
└───────────────────────────────┘

--- estimate number of hash functions
SELECT bfEstimateFunctions(4300, bfEstimateBmSize(4300, 0.0001)) as number_of_hash_functions

┌─number_of_hash_functions─┐
│                       13 │
└──────────────────────────┘
```

وبالطبع، يمكنك أيضًا استخدام تلك الدوال لتقدير المعلمات الخاصة بشروط أخرى.
وتستند الدوال المذكورة أعلاه إلى حاسبة bloom filter [هنا](https://hur.st/bloomfilter).

<div id="token-bloom-filter">
  #### مرشح bloom للرموز
</div>

<Note>
  مع الإتاحة العامة (GA) للفهرس `text` بدءًا من إصدار ClickHouse 26.2، لم يعد الفهرس `tokenbf_v1` موصى به لعمليات البحث في النص الكامل.

  راجع صفحة ["البحث في النص الكامل باستخدام فهارس النص"](/docs/ar/reference/engines/table-engines/mergetree-family/textindexes) لمزيد من التفاصيل.
</Note>

```text title="Syntax" theme={null}
tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
```

<div id="sparse-grams-bloom-filter">
  #### مرشح Bloom لـ sparse grams
</div>

مرشح Bloom لـ sparse grams مشابه لـ `ngrambf_v1`، لكنه يستخدم [رموز sparse grams](/docs/ar/reference/functions/regular-functions/string-functions#sparseGrams) بدلًا من ngrams.

```text title="Syntax" theme={null}
sparse_grams(min_ngram_length, max_ngram_length, min_cutoff_length, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
```

<div id="text">
  ### فهرس نصي
</div>

ينشئ فهرسًا معكوسًا على بيانات نصية مُجزّأة إلى رموز، مما يتيح بحثًا نصيًا كاملًا بكفاءة وبشكل حتمي. راجع [هنا](/docs/ar/reference/engines/table-engines/mergetree-family/textindexes) لمزيد من التفاصيل.

<div id="vector-similarity">
  #### تشابه المتجهات
</div>

يدعم البحث التقريبي عن أقرب الجيران، راجع [هنا](/docs/ar/reference/engines/table-engines/mergetree-family/annindexes) للاطلاع على التفاصيل.

<div id="functions-support">
  ### دعم الدوال
</div>

تتضمن الشروط في عبارة `WHERE` استدعاءات لدوال تتعامل مع الأعمدة. وإذا كان العمود جزءًا من فهرس، يحاول ClickHouse استخدام هذا الفهرس عند تطبيق هذه الدوال. يدعم ClickHouse مجموعات فرعية مختلفة من الدوال التي يمكن معها استخدام الفهارس.

يمكن استخدام الفهارس من النوع `set` مع جميع الدوال. أما أنواع الفهارس الأخرى، فهي مدعومة على النحو التالي:

| الدالة (المعامل) / الفهرس                                                                                                              | المفتاح الأساسي | minmax | ngrambf\_v1 | tokenbf\_v1 | bloom\_filter | sparse\_grams | text |
| -------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------ | ----------- | ----------- | ------------- | ------------- | ---- |
| [equals (=, ==)](/docs/ar/reference/functions/regular-functions/comparison-functions#equals)                                                | ✔               | ✔      | ✔           | ✔           | ✔             | ✔             | ✔    |
| [notEquals(!=, \<>)](/docs/ar/reference/functions/regular-functions/comparison-functions#notEquals)                                         | ✔               | ✔      | ✔           | ✔           | ✔             | ✔             | ✗    |
| [like](/docs/ar/reference/functions/regular-functions/string-search-functions#like)                                                         | ✔               | ✔      | ✔           | ✔           | ✗             | ✔             | ✔    |
| [notLike](/docs/ar/reference/functions/regular-functions/string-search-functions#notLike)                                                   | ✔               | ✔      | ✔           | ✔           | ✗             | ✔             | ✗    |
| [match](/docs/ar/reference/functions/regular-functions/string-search-functions#match)                                                       | ✗               | ✗      | ✔           | ✔           | ✗             | ✔             | ✔    |
| [startsWith](/docs/ar/reference/functions/regular-functions/string-functions#startsWith)                                                    | ✔               | ✔      | ✔           | ✔           | ✗             | ✔             | ✔    |
| [endsWith](/docs/ar/reference/functions/regular-functions/string-functions#endsWith)                                                        | ✗               | ✗      | ✔           | ✔           | ✗             | ✔             | ✔    |
| [multiSearchAny](/docs/ar/reference/functions/regular-functions/string-search-functions#multiSearchAny)                                     | ✗               | ✗      | ✔           | ✗           | ✗             | ✗             | ✔    |
| [multiSearchAnyUTF8](/docs/ar/reference/functions/regular-functions/string-search-functions#multiSearchAnyUTF8)                             | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [multiMatchAny](/docs/ar/reference/functions/regular-functions/string-search-functions#multiMatchAny)                                       | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [in](/docs/ar/reference/functions/regular-functions/in-functions)                                                                           | ✔               | ✔      | ✔           | ✔           | ✔             | ✔             | ✔    |
| [notIn](/docs/ar/reference/functions/regular-functions/in-functions)                                                                        | ✔               | ✔      | ✔           | ✔           | ✔             | ✔             | ✗    |
| [less (`<`)](/docs/ar/reference/functions/regular-functions/comparison-functions#less)                                                      | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [greater (`>`)](/docs/ar/reference/functions/regular-functions/comparison-functions#greater)                                                | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [lessOrEquals (`<=`)](/docs/ar/reference/functions/regular-functions/comparison-functions#lessOrEquals)                                     | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [greaterOrEquals (`>=`)](/docs/ar/reference/functions/regular-functions/comparison-functions#greaterOrEquals)                               | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [empty](/docs/ar/reference/functions/regular-functions/array-functions#empty)                                                               | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [notEmpty](/docs/ar/reference/functions/regular-functions/array-functions#notEmpty)                                                         | ✗               | ✔      | ✗           | ✗           | ✗             | ✔             | ✗    |
| [has](/docs/ar/reference/functions/regular-functions/array-functions#has)                                                                   | ✔               | ✔      | ✔           | ✔           | ✔             | ✔             | ✔    |
| [hasAny](/docs/ar/reference/functions/regular-functions/array-functions#hasAny)                                                             | ✗               | ✗      | ✔           | ✔           | ✔             | ✔             | ✗    |
| [hasAll](/docs/ar/reference/functions/regular-functions/array-functions#hasAll)                                                             | ✗               | ✗      | ✔           | ✔           | ✔             | ✔             | ✗    |
| [hasToken](/docs/ar/reference/functions/regular-functions/string-search-functions#hasToken)                                                 | ✗               | ✗      | ✗           | ✔           | ✗             | ✗             | ✔    |
| [hasTokenOrNull](/docs/ar/reference/functions/regular-functions/string-search-functions#hasTokenOrNull)                                     | ✗               | ✗      | ✗           | ✔           | ✗             | ✗             | ✔    |
| [hasTokenCaseInsensitive (`*`)](/docs/ar/reference/functions/regular-functions/string-search-functions#hasTokenCaseInsensitive)             | ✗               | ✗      | ✗           | ✔           | ✗             | ✗             | ✗    |
| [hasTokenCaseInsensitiveOrNull (`*`)](/docs/ar/reference/functions/regular-functions/string-search-functions#hasTokenCaseInsensitiveOrNull) | ✗               | ✗      | ✗           | ✔           | ✗             | ✗             | ✗    |
| [hasAnyTokens](/docs/ar/reference/functions/regular-functions/string-search-functions#hasAnyTokens)                                         | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [hasAllTokens](/docs/ar/reference/functions/regular-functions/string-search-functions#hasAllTokens)                                         | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [pointInPolygon](/docs/ar/reference/functions/regular-functions/geo/coordinates#pointinpolygon)                                             | ✔               | ✔      | ✗           | ✗           | ✗             | ✗             | ✗    |
| [mapContains (mapContainsKey)](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapContainsKey)                           | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [mapContainsKeyLike](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapContainsKeyLike)                                 | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [mapContainsValue](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapContainsValue)                                     | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |
| [mapContainsValueLike](/docs/ar/reference/functions/regular-functions/tuple-map-functions#mapContainsValueLike)                             | ✗               | ✗      | ✗           | ✗           | ✗             | ✗             | ✔    |

لا يمكن لـ `ngrambf_v1` استخدام الدوال التي تحتوي على وسيطة ثابتة أصغر من حجم ngram لتحسين الاستعلامات.

(\*) لكي تكون `hasTokenCaseInsensitive` و`hasTokenCaseInsensitiveOrNull` فعّالتين، يجب إنشاء الفهرس `tokenbf_v1` على بيانات محوّلة إلى أحرف صغيرة، على سبيل المثال `INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0)`.

<Note>
  قد تُنتج مرشحات Bloom تطابقات إيجابية كاذبة، لذلك لا يمكن استخدام الفهارس `ngrambf_v1` و`tokenbf_v1` و`sparse_grams` و`bloom_filter` لتحسين الاستعلامات التي يُتوقع أن تكون نتيجة الدالة فيها false.

  على سبيل المثال:

  * يمكن تحسينه:
    * `s LIKE '%test%'`
    * `NOT s NOT LIKE '%test%'`
    * `s = 1`
    * `NOT s != 1`
    * `startsWith(s, 'test')`
  * لا يمكن تحسينه:
    * `NOT s LIKE '%test%'`
    * `s NOT LIKE '%test%'`
    * `NOT s = 1`
    * `s != 1`
    * `NOT startsWith(s, 'test')`
</Note>

<div id="projections">
  ## الإسقاطات
</div>

تشبه الإسقاطات [العروض المُجسَّدة](/docs/ar/reference/statements/create/view)، لكنها تُعرَّف على مستوى الجزء. وهي توفّر ضمانات للاتساق إلى جانب استخدامها تلقائيًا في الاستعلامات.

<Note>
  عند تنفيذ الإسقاطات، ينبغي أيضًا مراعاة الإعداد [force\_optimize\_projection](/docs/ar/reference/settings/session-settings#force_optimize_projection).
</Note>

لا تُدعَم الإسقاطات في عبارات `SELECT` التي تستخدم المُعدِّل [FINAL](/docs/ar/reference/statements/select/from#final-modifier).

<div id="projection-query">
  ### استعلام الإسقاط
</div>

استعلام الإسقاط هو ما يعرّف الإسقاط. وهو يختار البيانات ضمنيًا من الجدول الأصلي.
**البنية**

```sql theme={null}
SELECT <column list expr> [GROUP BY] <group keys expr> [ORDER BY] <expr>
```

يمكن تعديل الإسقاطات أو حذفها باستخدام تعليمة [ALTER](/docs/ar/reference/statements/alter/projection).

<div id="projection-index">
  ### فهارس الإسقاط
</div>

تُوسّع فهارس الإسقاط النظام الفرعي للإسقاط عبر توفير طريقة خفيفة وواضحة لتعريف فهارس على مستوى الإسقاط.
ومن الناحية الظاهرية، يظل فهرس الإسقاط إسقاطًا، ولكن بصياغة أبسط وغرض أوضح: إذ يعرّف تعبيرًا مخصصًا للتصفية، بدلًا من تقديم بيانات مُحتسَبة ومخزَّنة مسبقًا.
أما داخليًا، فلا يقوم فهرس الإسقاط بتمثيل الجدول الأصلي فعليًا بترتيب صفوف مُبدَّل كما يفعل الإسقاط العادي.
وبدلًا من ذلك، يُخزَّن هذا التبديل في صورة عمود رقمي للتبديل `_part_offset`، أي `SELECT _part_offset ORDER BY <index_expr>`.

<div id="projection-index-syntax">
  #### الصياغة
</div>

```sql theme={null}
PROJECTION <name> INDEX <index_expr> TYPE <index_type>
```

مثال:

```sql theme={null}
CREATE TABLE example
(
    id UInt64,
    region String,
    user_id UInt32,
    PROJECTION region_proj INDEX region TYPE basic,
    PROJECTION uid_proj INDEX user_id TYPE basic
)
ENGINE = MergeTree
ORDER BY id;
```

<div id="projection-index-types">
  #### أنواع الفهارس
</div>

الأنواع المدعومة حاليًا:

* **basic**: يعادل فهرس MergeTree عاديًا على التعبير.

يوفّر هذا الإطار إمكانية إضافة المزيد من أنواع الفهارس مستقبلًا.

<div id="projection-storage">
  ### تخزين الإسقاطات
</div>

تُخزَّن الإسقاطات داخل دليل الجزء. وهي تشبه الفهرس، لكنها تتضمن دليلًا فرعيًا يخزّن جزءًا من جدول `MergeTree` مجهول الاسم. ويُشتق هذا الجدول من استعلام تعريف الإسقاط. إذا وُجد بند `GROUP BY`، يصبح محرك التخزين الأساسي هو [AggregatingMergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/aggregatingmergetree)، وتُحوَّل جميع الدوال التجميعية إلى `AggregateFunction`. وإذا وُجد بند `ORDER BY`، يستخدمه جدول `MergeTree` كتعبير المفتاح الأساسي. وأثناء عملية الدمج، يُدمَج جزء الإسقاط عبر إجراء الدمج الخاص بالتخزين التابع له. ويُدمَج المجموع الاختباري لجزء الجدول الأصل مع جزء الإسقاط. أما مهام الصيانة الأخرى فهي مشابهة لفهارس التخطي.

<div id="projection-query-analysis">
  ### تحليل الاستعلام
</div>

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

<div id="concurrent-data-access">
  ## الوصول المتزامن إلى البيانات
</div>

للوصول المتزامن إلى الجدول، نستخدم آلية تعدد الإصدارات. وبعبارة أخرى، عند قراءة جدول وتحديثه في الوقت نفسه، تُقرأ البيانات من مجموعة الأجزاء الحالية وقت تنفيذ الاستعلام. ولا توجد أقفال طويلة الأمد. كما أن عمليات الإدراج لا تعيق عمليات القراءة.

تُنفَّذ القراءة من الجدول بالتوازي تلقائيًا.

<div id="table_engine-mergetree-ttl">
  ## TTL للأعمدة والجداول
</div>

يحدّد مدة بقاء القيم.

يمكن تعيين عبارة `TTL` للجدول بأكمله ولكل عمود على حدة. ويمكن أيضًا لـ `TTL` على مستوى الجدول تحديد آلية نقل البيانات تلقائيًا بين الأقراص ووحدات التخزين، أو إعادة ضغط الأجزاء التي انتهت صلاحية جميع البيانات فيها.

يجب أن ينتج عن تقييم التعبيرات نوع البيانات [Date](/docs/ar/reference/data-types/date) أو [Date32](/docs/ar/reference/data-types/date32) أو [DateTime](/docs/ar/reference/data-types/datetime) أو [DateTime64](/docs/ar/reference/data-types/datetime64).

<Tip>
  **تجنّب الدوال غير الحتمية في تعبيرات TTL**

  يُقيَّم TTL أثناء عمليات الدمج في الخلفية، وليس وقت الإدراج.
  تُعاد تقييم دوال مثل `rand()` و`now()` و`now64()` عند كل عملية دمج، مما يؤدي إلى سلوك حذف غير قابل للتنبؤ.
  يمنع ClickHouse التعبيرات التي لا تعتمد على أي عمود على الإطلاق، لكنه لا يرفض حاليًا الدوال غير الحتمية الممزوجة بإشارة إلى عمود (مثل `ts + rand()`). ينبغي أن تستند تعبيرات TTL فقط إلى قيم حتمية مشتقة من الأعمدة للحصول على نتائج قابلة للتنبؤ.
</Tip>

**البنية**

تعيين مدة بقاء لعمود:

```sql theme={null}
TTL time_column
TTL time_column + interval
```

لتعريف `interval`، استخدم معاملات [الفواصل الزمنية](/docs/ar/reference/operators/index#operators-for-working-with-dates-and-times)، على سبيل المثال:

```sql theme={null}
TTL date_time + INTERVAL 1 MONTH
TTL date_time + INTERVAL 15 HOUR
```

<div id="mergetree-column-ttl">
  ### TTL للعمود
</div>

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

لا يمكن استخدام عبارة `TTL` مع الأعمدة المفتاحية.

**أمثلة**

<div id="creating-a-table-with-ttl">
  #### إنشاء جدول باستخدام `TTL`:
</div>

```sql theme={null}
CREATE TABLE tab
(
    d DateTime,
    a Int TTL d + INTERVAL 1 MONTH,
    b Int TTL d + INTERVAL 1 MONTH,
    c String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d;
```

<div id="adding-ttl-to-a-column-of-an-existing-table">
  #### إضافة TTL إلى عمود في جدول موجود
</div>

```sql theme={null}
ALTER TABLE tab
    MODIFY COLUMN
    c String TTL d + INTERVAL 1 DAY;
```

<div id="altering-ttl-of-the-column">
  #### تعديل TTL للعمود
</div>

```sql theme={null}
ALTER TABLE tab
    MODIFY COLUMN
    c String TTL d + INTERVAL 1 MONTH;
```

<div id="mergetree-table-ttl">
  ### TTL للجدول
</div>

يمكن أن يحتوي الجدول على تعبير لإزالة الصفوف منتهية الصلاحية، وعلى عدة تعبيرات لنقل الأجزاء تلقائيًا بين [الأقراص أو وحدات التخزين](#table_engine-mergetree-multiple-volumes). وعندما تنتهي صلاحية الصفوف في الجدول، يحذف ClickHouse جميع الصفوف المقابلة. أما بالنسبة إلى نقل الأجزاء أو إعادة ضغطها، فيجب أن تستوفي جميع صفوف الجزء معايير تعبير `TTL`.

```sql theme={null}
TTL expr
    [DELETE|RECOMPRESS codec_name1|TO DISK 'xxx'|TO VOLUME 'xxx'][, DELETE|RECOMPRESS codec_name2|TO DISK 'aaa'|TO VOLUME 'bbb'] ...
    [WHERE conditions]
    [GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ]
```

قد يأتي بعد كل تعبير `TTL` نوعٌ من قواعد `TTL`. ويحدد ذلك الإجراء الذي يجب تنفيذه عند تحقق التعبير (أي عند وصوله إلى الوقت الحالي):

* `DELETE` - حذف الصفوف منتهية الصلاحية (الإجراء الافتراضي)؛
* `RECOMPRESS codec_name` - إعادة ضغط جزء البيانات باستخدام `codec_name`؛
* `TO DISK 'aaa'` - نقل الجزء إلى القرص `aaa`؛
* `TO VOLUME 'bbb'` - نقل الجزء إلى القرص `bbb`؛
* `GROUP BY` - تجميع الصفوف منتهية الصلاحية.

يمكن استخدام الإجراء `DELETE` مع عبارة `WHERE` لحذف بعض الصفوف منتهية الصلاحية فقط استنادًا إلى شرط تصفية:

```sql theme={null}
TTL time_column + INTERVAL 1 MONTH DELETE WHERE column = 'value'
```

يجب أن يكون تعبير `GROUP BY` بادئةً للمفتاح الأساسي للجدول.

إذا لم يكن العمود جزءًا من تعبير `GROUP BY` ولم تُعيَّن له قيمة صراحةً في العبارة `SET`، فسيحتوي الصف الناتج على قيمة عشوائية من الصفوف المجمّعة (كما لو طُبِّقت عليه الدالة التجميعية `any`).

**أمثلة**

<div id="creating-a-table-with-ttl-1">
  #### إنشاء جدول مع `TTL`:
</div>

```sql theme={null}
CREATE TABLE tab
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH DELETE,
    d + INTERVAL 1 WEEK TO VOLUME 'aaa',
    d + INTERVAL 2 WEEK TO DISK 'bbb';
```

<div id="altering-ttl-of-the-table">
  #### تعديل `TTL` للجدول:
</div>

```sql theme={null}
ALTER TABLE tab
    MODIFY TTL d + INTERVAL 1 DAY;
```

إنشاء جدول، حيث تنتهي صلاحية الصفوف بعد شهر واحد. وتُحذف الصفوف منتهية الصلاحية التي توافق تواريخها يوم الاثنين:

```sql theme={null}
CREATE TABLE table_with_where
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH DELETE WHERE toDayOfWeek(d) = 1;
```

<div id="creating-a-table-where-expired-rows-are-recompressed">
  #### إنشاء جدول يُعاد فيه ضغط الصفوف منتهية الصلاحية:
</div>

```sql theme={null}
CREATE TABLE table_for_recompression
(
    d DateTime,
    key UInt64,
    value String
) ENGINE MergeTree()
ORDER BY tuple()
PARTITION BY key
TTL d + INTERVAL 1 MONTH RECOMPRESS CODEC(ZSTD(17)), d + INTERVAL 1 YEAR RECOMPRESS CODEC(LZ4HC(10))
SETTINGS min_rows_for_wide_part = 0, min_bytes_for_wide_part = 0;
```

إنشاء جدول تُجمَّع فيه الصفوف منتهية الصلاحية. في صفوف النتيجة، تحتوي `x` على القيمة العظمى عبر الصفوف المجمَّعة، و`y` — على القيمة الصغرى، و`d` — على أي قيمة عشوائية من الصفوف المجمَّعة.

```sql theme={null}
CREATE TABLE table_for_aggregation
(
    d DateTime,
    k1 Int,
    k2 Int,
    x Int,
    y Int
)
ENGINE = MergeTree
ORDER BY (k1, k2)
TTL d + INTERVAL 1 MONTH GROUP BY k1, k2 SET x = max(x), y = min(y);
```

<div id="mergetree-removing-expired-data">
  ### إزالة البيانات منتهية الصلاحية
</div>

تُزال البيانات التي انتهت صلاحية `TTL` الخاصة بها عندما يدمج ClickHouse أجزاء البيانات.

عندما يكتشف ClickHouse أن البيانات منتهية الصلاحية، يُجري عملية دمج خارج الجدول الزمني. وللتحكم في وتيرة عمليات الدمج هذه، يمكنك تعيين `merge_with_ttl_timeout`. وإذا كانت القيمة منخفضة جدًا، فسينفّذ العديد من عمليات الدمج خارج الجدول الزمني، ما قد يستهلك قدرًا كبيرًا من الموارد.

إذا نفّذت استعلام `SELECT` بين عمليات الدمج، فقد تحصل على بيانات منتهية الصلاحية. ولتجنب ذلك، استخدم استعلام [OPTIMIZE](/docs/ar/reference/statements/optimize) قبل `SELECT`.

**انظر أيضًا**

* إعداد [ttl\_only\_drop\_parts](/docs/ar/reference/settings/merge-tree-settings#ttl_only_drop_parts)

<div id="disk-types">
  ## أنواع الأقراص
</div>

بالإضافة إلى أجهزة التخزين الكتلية المحلية، يدعم ClickHouse أنواع التخزين التالية:

* [`s3` لـ S3 وMinIO](#table_engine-mergetree-s3)
* [`gcs` لـ GCS](/docs/ar/integrations/connectors/data-sources/gcs#creating-a-disk)
* [`blob_storage_disk` لـ Azure Blob Storage](/docs/ar/concepts/features/configuration/server-config/storing-data#azure-blob-storage)
* [`hdfs` لـ HDFS](/docs/ar/reference/engines/table-engines/integrations/hdfs)
* [`web` للقراءة فقط عبر الويب](/docs/ar/concepts/features/configuration/server-config/storing-data#web-storage)
* [`cache` للتخزين المؤقت المحلي](/docs/ar/concepts/features/configuration/server-config/storing-data#using-local-cache)
* [`s3_plain` للنسخ الاحتياطية إلى S3](/docs/ar/concepts/features/backup-restore/local-disk)
* [`s3_plain_rewritable` للجداول غير القابلة للتغيير وغير المُكرَّرة في S3](/docs/ar/concepts/features/configuration/server-config/storing-data#s3-plain-rewritable-storage)

<div id="table_engine-mergetree-multiple-volumes">
  ## استخدام عدة أجهزة تخزين كتلية لتخزين البيانات
</div>

<div id="introduction">
  ### المقدمة
</div>

يمكن لمحركات الجداول من عائلة `MergeTree` تخزين البيانات على عدة أجهزة تخزين كتلية. على سبيل المثال، قد يكون ذلك مفيدًا عندما تُقسَّم بيانات جدول معيّن ضمنيًا إلى بيانات "ساخنة" وأخرى "باردة". تُطلَب أحدث البيانات بانتظام، لكنها لا تتطلب سوى مساحة صغيرة. في المقابل، نادرًا ما تُطلَب البيانات التاريخية الممتدة على مدى زمني طويل. وإذا توفرت عدة أقراص، فيمكن وضع البيانات "الساخنة" على أقراص سريعة (مثل أقراص NVMe SSD أو الذاكرة)، بينما تُحفَظ البيانات "الباردة" على أقراص أبطأ نسبيًا (مثل HDD).

ينطبق ذلك على جميع أنواع الأقراص، بما في ذلك S3 وأقراص تخزين الكائنات الأخرى. على سبيل المثال، يمكنك توزيع البيانات عبر عدة حاويات S3 ضمن وحدة تخزين واحدة، أو إنشاء سياسات تخزين متدرجة تنقل البيانات من الأقراص المحلية إلى S3. راجع [استخدام أقراص S3 مع عدة وحدات تخزين](#s3-multiple-volumes) لمزيد من التفاصيل.

يُعد جزء البيانات أصغر وحدة قابلة للنقل في الجداول التي تستخدم المحرك `MergeTree`. وتُخزَّن البيانات التابعة لجزء واحد على قرص واحد. ويمكن نقل أجزاء البيانات بين الأقراص في الخلفية (وفقًا لإعدادات المستخدم)، وكذلك باستخدام استعلامات [ALTER](/docs/ar/reference/statements/alter/partition).

<div id="terms">
  ### المصطلحات
</div>

* القرص — جهاز تخزين كتلي مُركَّب على نظام الملفات.
* القرص الافتراضي — القرص الذي يخزّن المسار المحدد في إعداد الخادم [path](/docs/ar/reference/settings/server-settings/settings#path).
* وحدة التخزين — مجموعة مرتبة من أقراص متماثلة (مشابهة لـ [JBOD](https://en.wikipedia.org/wiki/Non-RAID_drive_architectures)).
* سياسة التخزين — مجموعة من وحدات التخزين والقواعد الخاصة بنقل البيانات بينها.

يمكن العثور على الأسماء المخصَّصة للكيانات الموصوفة في جداول النظام [system.storage\_policies](/docs/ar/reference/system-tables/storage_policies) و[system.disks](/docs/ar/reference/system-tables/disks). لتطبيق إحدى سياسات التخزين المُعدّة على جدول، استخدم الإعداد `storage_policy` في جداول عائلة المحرك `MergeTree`.

<div id="table_engine-mergetree-multiple-volumes_configure">
  ### التكوين
</div>

يجب تعريف الأقراص ووحدات التخزين وسياسات التخزين داخل الوسم `<storage_configuration>`، سواء في ملف ضمن الدليل `config.d`.

<Tip>
  يمكن أيضًا تعريف الأقراص في قسم `SETTINGS` ضمن استعلام. ويكون ذلك مفيدًا
  في التحليلات المخصصة لإرفاق قرص مؤقتًا يكون مستضافًا، على سبيل المثال، على عنوان URL.
  راجع [التخزين الديناميكي](/docs/ar/concepts/features/configuration/server-config/storing-data#dynamic-configuration) لمزيد من التفاصيل.
</Tip>

بنية التكوين:

```xml theme={null}
<storage_configuration>
    <disks>
        <disk_name_1> <!-- disk name -->
            <path>/mnt/fast_ssd/clickhouse/</path>
        </disk_name_1>
        <disk_name_2>
            <path>/mnt/hdd1/clickhouse/</path>
            <keep_free_space_bytes>10485760</keep_free_space_bytes>
        </disk_name_2>
        <disk_name_3>
            <path>/mnt/hdd2/clickhouse/</path>
            <keep_free_space_bytes>10485760</keep_free_space_bytes>
        </disk_name_3>

        ...
    </disks>

    ...
</storage_configuration>
```

الوسوم:

* `<disk_name_N>` — اسم القرص. يجب أن تختلف الأسماء بين جميع الأقراص.
* `path` — المسار الذي سيخزّن الخادم البيانات تحته (مجلدا `data` و`shadow`)، ويجب أن ينتهي بـ '/'.
* `keep_free_space_bytes` — مقدار مساحة القرص الحرة التي يجب الاحتفاظ بها.

ترتيب تعريف القرص غير مهم.

بنية إعداد سياسات التخزين:

```xml theme={null}
<storage_configuration>
    ...
    <policies>
        <policy_name_1>
            <volumes>
                <volume_name_1>
                    <disk>disk_name_from_disks_configuration</disk>
                    <max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
                    <load_balancing>round_robin</load_balancing>
                </volume_name_1>
                <volume_name_2>
                    <!-- configuration -->
                </volume_name_2>
                <!-- more volumes -->
            </volumes>
            <move_factor>0.2</move_factor>
        </policy_name_1>
        <policy_name_2>
            <!-- configuration -->
        </policy_name_2>

        <!-- more policies -->
    </policies>
    ...
</storage_configuration>
```

الوسوم:

* `policy_name_N` — اسم السياسة. يجب أن تكون أسماء السياسات فريدة.
* `volume_name_N` — اسم وحدة التخزين. يجب أن تكون أسماء وحدات التخزين فريدة.
* `disk` — قرص ضمن وحدة تخزين.
* `max_data_part_size_bytes` — الحد الأقصى لحجم الجزء الذي يمكن تخزينه على أيٍّ من أقراص وحدة التخزين. إذا كان الحجم التقديري لجزء مدموج أكبر من `max_data_part_size_bytes`، فسيُكتب هذا الجزء في وحدة التخزين التالية. تتيح هذه الميزة أساسًا الاحتفاظ بالأجزاء الجديدة/الصغيرة على وحدة تخزين سريعة (SSD) ثم نقلها إلى وحدة تخزين بطيئة (HDD) عندما يصبح حجمها كبيرًا. لا تستخدم هذا الإعداد إذا كانت سياستك تحتوي على وحدة تخزين واحدة فقط.
* `move_factor` — عندما تنخفض المساحة المتاحة عن هذه النسبة، تبدأ البيانات تلقائيًا بالانتقال إلى وحدة التخزين التالية إن وُجدت (القيمة الافتراضية 0.1). يرتّب ClickHouse الأجزاء الموجودة حسب الحجم من الأكبر إلى الأصغر (ترتيبًا تنازليًا)، ثم يحدّد الأجزاء التي يكفي حجمها الإجمالي لتحقيق شرط `move_factor`. وإذا لم يكن الحجم الإجمالي لجميع الأجزاء كافيًا، فستنقل جميع الأجزاء.
* `perform_ttl_move_on_insert` — يعطّل TTL move عند تنفيذ INSERT لجزء بيانات. افتراضيًا (إذا كان مُمكّنًا)، إذا أدرجنا جزء بيانات انتهت صلاحيته بالفعل وفق قاعدة TTL move، فإنه ينتقل فورًا إلى وحدة التخزين/القرص المعرَّف في قاعدة النقل. وقد يؤدي ذلك إلى إبطاء عملية INSERT بشكل كبير إذا كانت وحدة التخزين/القرص الوجهة بطيئة (مثل S3). وإذا كان معطّلًا، فسيُكتب جزء البيانات المنتهي الصلاحية أولًا في وحدة التخزين الافتراضية، ثم يُنقل مباشرة بعد ذلك إلى وحدة تخزين TTL.
* `load_balancing` - سياسة موازنة الأقراص، `round_robin` أو `least_used`.
* `least_used_ttl_ms` - يضبط مهلة التحديث (بالملي ثانية) للمساحة المتاحة على جميع الأقراص (`0` - التحديث دائمًا، `-1` - عدم التحديث مطلقًا، والقيمة الافتراضية هي `60000`). لاحظ أنه إذا كان القرص مستخدمًا من ClickHouse فقط وغير خاضع لتوسيع/تقليص نظام الملفات أثناء التشغيل، فيمكنك استخدام `-1`. أما في جميع الحالات الأخرى فلا يُنصح بذلك، لأنه سيؤدي في النهاية إلى توزيع غير صحيح للمساحة.
* `prefer_not_to_merge` — يجب ألا تستخدم هذا الإعداد. فهو يعطّل دمج أجزاء البيانات على وحدة التخزين هذه (وهذا ضار ويؤدي إلى تراجع الأداء). عند تمكين هذا الإعداد (لا تفعل ذلك)، لا يعود دمج البيانات على وحدة التخزين هذه مسموحًا به (وهذا أمر سيئ). يتيح هذا الإعداد (لكنك لا تحتاج إليه) التحكّم (وإذا كنت تريد التحكّم في شيء هنا، فأنت ترتكب خطأً) في كيفية تعامل ClickHouse مع الأقراص البطيئة (لكن ClickHouse يعرف الأفضل، لذا يُرجى عدم استخدام هذا الإعداد).
* `volume_priority` — يحدّد الأولوية (الترتيب) الذي تُملأ به وحدات التخزين. القيمة الأقل تعني أولوية أعلى. يجب أن تكون قيم المعلَمة أعدادًا طبيعية، وأن تغطي مجتمعةً النطاق من 1 إلى N (بحيث تُمنح أقل أولوية) من دون تخطي أي أرقام.
  * إذا كانت *جميع* وحدات التخزين موسومة، فستُرتَّب أولوياتها وفق الترتيب المحدد.
  * إذا كانت *بعض* وحدات التخزين فقط موسومة، فستكون الوحدات غير الموسومة ذات الأولوية الأدنى، وتُرتَّب حسب ترتيب تعريفها في `config`.
  * إذا لم تكن *أي* من وحدات التخزين موسومة، فتُحدَّد أولويتها وفق ترتيب التصريح بها في التهيئة.
  * لا يمكن أن تكون لوحدتي تخزين قيمة الأولوية نفسها.

أمثلة على التهيئة:

```xml theme={null}
<storage_configuration>
    ...
    <policies>
        <hdd_in_order> <!-- policy name -->
            <volumes>
                <single> <!-- volume name -->
                    <disk>disk1</disk>
                    <disk>disk2</disk>
                </single>
            </volumes>
        </hdd_in_order>

        <moving_from_ssd_to_hdd>
            <volumes>
                <hot>
                    <disk>fast_ssd</disk>
                    <max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
                </hot>
                <cold>
                    <disk>disk1</disk>
                </cold>
            </volumes>
            <move_factor>0.2</move_factor>
        </moving_from_ssd_to_hdd>

        <small_jbod_with_external_no_merges>
            <volumes>
                <main>
                    <disk>jbod1</disk>
                </main>
                <external>
                    <disk>external</disk>
                </external>
            </volumes>
        </small_jbod_with_external_no_merges>
    </policies>
    ...
</storage_configuration>
```

في المثال المذكور، تنفّذ سياسة التخزين `hdd_in_order` أسلوب [التوزيع بالتناوب](https://en.wikipedia.org/wiki/Round-robin_scheduling). لذلك لا تحدد هذه السياسة سوى وحدة تخزين واحدة (`single`)، وتُخزَّن أجزاء البيانات على جميع أقراصها بالتتابع الدوري. يمكن أن تكون هذه السياسة مفيدة جدًا إذا كانت هناك عدة أقراص متشابهة مركّبة على النظام، ولكن RAID غير مهيأ. ضع في اعتبارك أن كل قرص على حدة غير موثوق، وقد تحتاج إلى تعويض ذلك بعامل replication مقداره 3 أو أكثر.

إذا كانت هناك أنواع مختلفة من الأقراص متاحة في النظام، فيمكن استخدام سياسة `moving_from_ssd_to_hdd` بدلًا من ذلك. تتكوّن وحدة التخزين `hot` من قرص SSD (`fast_ssd`)، ويبلغ الحد الأقصى لحجم جزء يمكن تخزينه على هذه الوحدة 1GB. ستُخزَّن جميع الأجزاء التي يزيد حجمها على 1GB مباشرةً على وحدة التخزين `cold`، التي تحتوي على قرص HDD باسم `disk1`.
كذلك، بمجرد أن تتجاوز نسبة امتلاء القرص `fast_ssd` 80%، ستُنقل البيانات إلى `disk1` بواسطة عملية تعمل في الخلفية.

يُعد ترتيب سرد وحدات التخزين داخل سياسة التخزين مهمًا إذا كانت واحدة على الأقل من وحدات التخزين المدرجة لا تحتوي على المعامل `volume_priority` بشكل صريح.
وبمجرد امتلاء إحدى وحدات التخزين بشكل زائد، تُنقل البيانات إلى الوحدة التالية. ويُعد ترتيب سرد الأقراص مهمًا أيضًا لأن البيانات تُخزَّن عليها بالتناوب.

عند إنشاء table، يمكن تطبيق إحدى سياسات التخزين المهيأة عليها:

```sql theme={null}
CREATE TABLE table_with_non_default_policy (
    EventDate Date,
    OrderID UInt64,
    BannerID UInt64,
    SearchPhrase String
) ENGINE = MergeTree
ORDER BY (OrderID, BannerID)
PARTITION BY toYYYYMM(EventDate)
SETTINGS storage_policy = 'moving_from_ssd_to_hdd'
```

تعني سياسة التخزين `default` استخدام وحدة تخزين واحدة فقط، تتكوّن من قرص واحد فقط محدَّد في `<path>`.
يمكنك تغيير سياسة التخزين بعد إنشاء الجدول باستخدام استعلام \[ALTER TABLE ... MODIFY SETTING]، ويجب أن تتضمن السياسة الجديدة جميع الأقراص ووحدات التخزين القديمة نفسها وبالأسماء نفسها.

يمكن تغيير عدد الخيوط التي تنفّذ عمليات نقل أجزاء البيانات في الخلفية عبر الإعداد [background\_move\_pool\_size](/docs/ar/reference/settings/server-settings/settings#background_move_pool_size).

<div id="details">
  ### التفاصيل
</div>

في حالة جداول `MergeTree`، تصل البيانات إلى القرص بطرق مختلفة:

* نتيجةً لعملية insert (استعلام `INSERT`).
* أثناء عمليات الدمج في الخلفية و[الطفرات](/docs/ar/reference/statements/alter/index#mutations).
* عند التنزيل من نسخة متماثلة أخرى.
* نتيجةً لتجميد القسم [ALTER TABLE ... FREEZE PARTITION](/docs/ar/reference/statements/alter/partition#freeze-partition).

في جميع هذه الحالات، باستثناء الطفرات وتجميد القسم، يُخزَّن الجزء على وحدة تخزين وقرص وفقًا لسياسة التخزين المحددة:

1. تُختار أول وحدة تخزين (بحسب ترتيب تعريفها) تتوفر فيها مساحة قرص كافية لتخزين جزء (`unreserved_space > current_part_size`) وتسمح بتخزين أجزاء بهذا الحجم (`max_data_part_size_bytes > current_part_size`).
2. ضمن وحدة التخزين هذه، يُختار القرص الذي يلي القرص المستخدم لتخزين الجزء السابق من البيانات، والذي تكون فيه المساحة الحرة أكبر من حجم الجزء (`unreserved_space - keep_free_space_bytes > current_part_size`).

داخليًا، تستخدم الطفرات وتجميد القسم [الروابط الصلبة](https://en.wikipedia.org/wiki/Hard_link). لا تُدعَم الروابط الصلبة بين الأقراص المختلفة، لذلك في مثل هذه الحالات تُخزَّن الأجزاء الناتجة على الأقراص نفسها التي توجد عليها الأجزاء الأصلية.

في الخلفية، تُنقَل الأجزاء بين وحدات التخزين استنادًا إلى مقدار المساحة الحرة (المعامل `move_factor`) وفقًا لترتيب تعريف وحدات التخزين في ملف الإعدادات.
ولا تُنقَل البيانات مطلقًا من الأخيرة إلى الأولى. يمكن استخدام جداول النظام [system.part\_log](/docs/ar/reference/system-tables/part_log) (الحقل `type = MOVE_PART`) و[system.parts](/docs/ar/reference/system-tables/parts) (الحقلان `path` و`disk`) لمراقبة عمليات النقل في الخلفية. كما يمكن العثور على معلومات تفصيلية في سجلات الخادم.

يمكن للمستخدم فرض نقل جزء أو قسم من وحدة تخزين إلى أخرى باستخدام الاستعلام [ALTER TABLE ... MOVE PART|PARTITION ... TO VOLUME|DISK ...](/docs/ar/reference/statements/alter/partition)، مع مراعاة جميع القيود الخاصة بالعمليات التي تعمل في الخلفية. يبدأ الاستعلام عملية النقل بنفسه ولا ينتظر اكتمال العمليات في الخلفية. سيتلقى المستخدم رسالة خطأ إذا لم تتوفر مساحة حرة كافية أو إذا لم تتحقق أي من الشروط المطلوبة.

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

بعد اكتمال عمليات الدمج في الخلفية والطفرات، لا تُزال الأجزاء القديمة إلا بعد مرور مدة زمنية معينة (`old_parts_lifetime`).
وخلال هذه المدة، لا تُنقَل إلى وحدات تخزين أو أقراص أخرى. لذلك، وحتى تُزال الأجزاء نهائيًا، فإنها تظل محسوبة عند تقييم مساحة القرص المشغولة.

يمكن للمستخدم إسناد الأجزاء الكبيرة الجديدة إلى أقراص مختلفة ضمن وحدة تخزين من نوع [JBOD](https://en.wikipedia.org/wiki/Non-RAID_drive_architectures) بطريقة متوازنة باستخدام الإعداد [min\_bytes\_to\_rebalance\_partition\_over\_jbod](/docs/ar/reference/settings/merge-tree-settings#min_bytes_to_rebalance_partition_over_jbod).

<div id="table_engine-mergetree-s3">
  ## استخدام التخزين الخارجي لتخزين البيانات
</div>

يمكن لمحركات الجداول من عائلة [MergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/mergetree) تخزين البيانات في `S3` و`AzureBlobStorage` و`HDFS` باستخدام قرص من النوع `s3` أو `azure_blob_storage` أو `hdfs` على الترتيب. راجع [إعداد خيارات التخزين الخارجي](/docs/ar/concepts/features/configuration/server-config/storing-data#configuring-external-storage) لمزيد من التفاصيل.

مثال على استخدام [S3](https://aws.amazon.com/s3/) كتخزين خارجي باستخدام قرص من النوع `s3`.

صيغة التكوين:

```xml theme={null}
<storage_configuration>
    ...
    <disks>
        <s3>
            <type>s3</type>
            <support_batch_delete>true</support_batch_delete>
            <endpoint>https://clickhouse-public-datasets.s3.amazonaws.com/my-bucket/root-path/</endpoint>
            <access_key_id>your_access_key_id</access_key_id>
            <secret_access_key>your_secret_access_key</secret_access_key>
            <region></region>
            <header>Authorization: Bearer SOME-TOKEN</header>
            <server_side_encryption_customer_key_base64>your_base64_encoded_customer_key</server_side_encryption_customer_key_base64>
            <server_side_encryption_kms_key_id>your_kms_key_id</server_side_encryption_kms_key_id>
            <server_side_encryption_kms_encryption_context>your_kms_encryption_context</server_side_encryption_kms_encryption_context>
            <server_side_encryption_kms_bucket_key_enabled>true</server_side_encryption_kms_bucket_key_enabled>
            <proxy>
                <uri>http://proxy1</uri>
                <uri>http://proxy2</uri>
            </proxy>
            <connect_timeout_ms>10000</connect_timeout_ms>
            <request_timeout_ms>5000</request_timeout_ms>
            <retry_attempts>10</retry_attempts>
            <single_read_retries>4</single_read_retries>
            <min_bytes_for_seek>1000</min_bytes_for_seek>
            <metadata_path>/var/lib/clickhouse/disks/s3/</metadata_path>
            <skip_access_check>false</skip_access_check>
        </s3>
        <s3_cache>
            <type>cache</type>
            <disk>s3</disk>
            <path>/var/lib/clickhouse/disks/s3_cache/</path>
            <max_size>10Gi</max_size>
        </s3_cache>
    </disks>
    ...
</storage_configuration>
```

راجع أيضًا [تهيئة خيارات التخزين الخارجي](/docs/ar/concepts/features/configuration/server-config/storing-data#configuring-external-storage).

<div id="s3-multiple-volumes">
  ### استخدام أقراص S3 مع وحدات تخزين متعددة
</div>

يمكن استخدام أقراص S3 (وغيرها من أقراص التخزين الكائني) في سياسات التخزين متعددة الأقراص ومتعددة الوحدات بالطريقة نفسها المستخدمة مع الأقراص المحلية. يتيح لك ذلك توزيع البيانات عبر عدة حاويات S3 ضمن وحدة تخزين واحدة (على نمط JBOD)، أو إعداد سياسات تخزين متعددة الطبقات باستخدام وحدات S3.

على سبيل المثال، لتوزيع البيانات عبر حاويتَي S3 بأسلوب round-robin:

```xml theme={null}
<storage_configuration>
    <disks>
        <s3_bucket1>
            <type>s3</type>
            <endpoint>https://s3.amazonaws.com/bucket-1/data/</endpoint>
            <access_key_id>your_access_key_id</access_key_id>
            <secret_access_key>your_secret_access_key</secret_access_key>
        </s3_bucket1>
        <s3_bucket2>
            <type>s3</type>
            <endpoint>https://s3.amazonaws.com/bucket-2/data/</endpoint>
            <access_key_id>your_access_key_id</access_key_id>
            <secret_access_key>your_secret_access_key</secret_access_key>
        </s3_bucket2>
    </disks>
    <policies>
        <s3_multi_bucket>
            <volumes>
                <main>
                    <disk>s3_bucket1</disk>
                    <disk>s3_bucket2</disk>
                </main>
            </volumes>
        </s3_multi_bucket>
    </policies>
</storage_configuration>
```

يمكنك أيضًا الجمع بين وحدات التخزين المحلية ووحدات تخزين S3 ضمن سياسة تخزين متدرجة، على سبيل المثال نقل البيانات من قرص SSD محلي إلى S3 كلما تقادمت:

```xml theme={null}
<storage_configuration>
    <disks>
        <local_ssd>
            <path>/mnt/fast_ssd/clickhouse/</path>
        </local_ssd>
        <s3_cold>
            <type>s3</type>
            <endpoint>https://s3.amazonaws.com/cold-storage/data/</endpoint>
            <access_key_id>your_access_key_id</access_key_id>
            <secret_access_key>your_secret_access_key</secret_access_key>
        </s3_cold>
    </disks>
    <policies>
        <local_to_s3>
            <volumes>
                <hot>
                    <disk>local_ssd</disk>
                    <max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
                </hot>
                <cold>
                    <disk>s3_cold</disk>
                </cold>
            </volumes>
            <move_factor>0.2</move_factor>
        </local_to_s3>
    </policies>
</storage_configuration>
```

<Note>
  عند استخدام `use_environment_credentials` لمصادقة S3، تتم مشاركة بيانات الاعتماد البيئية (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`) بين جميع أقراص S3. ولا يمكن استخدام بيانات اعتماد بيئية مختلفة لأقراص مختلفة. إذا كنت بحاجة إلى بيانات اعتماد مختلفة لكل قرص S3، فاستخدم بدلًا من ذلك إعدادَي `access_key_id` و`secret_access_key` الصريحين لكل قرص.
</Note>

يمكن إعداد جداول MergeTree غير المكررة وفق سيناريو كاتب واحد وعدة قرّاء على وحدة تخزين مشتركة. ويتحقق ذلك عبر التحديث التلقائي لقائمة الأجزاء، الذي يمكن إعداده على القرّاء. لاحظ أن ذلك يتطلب بيانات تعريف نظام ملفات مشتركة عبر النسخ المتماثلة (أو `table_disk = true` مع قرص محلي على مستوى الجدول). راجع [refresh\_parts\_interval and table\_disk](/docs/ar/concepts/features/configuration/server-config/storing-data#refresh-parts-interval-and-table-disk).

<Info>
  **إعدادات cache**

  تستخدم إصدارات ClickHouse من 22.3 إلى 22.7 إعدادات cache مختلفة. راجع [using local cache](/docs/ar/concepts/features/configuration/server-config/storing-data#using-local-cache) إذا كنت تستخدم أحد هذه الإصدارات.
</Info>

<div id="virtual-columns">
  ## الأعمدة الافتراضية
</div>

* `_part` — اسم الجزء.
* `_part_index` — الفهرس التسلسلي للجزء في نتيجة الاستعلام.
* `_part_starting_offset` — صف البداية التراكمي للجزء في نتيجة الاستعلام.
* `_part_offset` — رقم الصف في الجزء.
* `_part_granule_offset` — رقم الـ granule في الجزء.
* `_partition_id` — اسم القسم.
* `_part_uuid` — المعرّف الفريد للجزء (إذا كان إعداد MergeTree ‏`assign_part_uuids` مفعّلًا).
* `_part_data_version` — إصدار بيانات الجزء (إما الحد الأدنى لرقم block أو إصدار mutation).
* `_partition_value` — القيم (`Tuple`) الخاصة بتعبير `partition by`.
* `_sample_factor` — عامل العينة (من الاستعلام).
* `_block_number` — الرقم الأصلي للـ block الخاص بالصف الذي أُسنِد عند insert، ويُحفَظ عبر merges عندما يكون الإعداد `enable_block_number_column` مفعّلًا.
* `_block_offset` — الرقم الأصلي للصف داخل block الذي أُسنِد عند insert، ويُحفَظ عبر merges عندما يكون الإعداد `enable_block_offset_column` مفعّلًا.
* `_disk_name` — اسم الـ قرص المستخدم للتخزين.

<div id="column-statistics">
  ## إحصاءات الأعمدة
</div>

يرد تعريف الإحصاءات في قسم الأعمدة ضمن استعلام `CREATE` للجداول التابعة لعائلة `*MergeTree*`:

```sql theme={null}
CREATE TABLE tab
(
    a Int64 STATISTICS(tdigest, uniq),
    b Float64
)
ENGINE = MergeTree
ORDER BY a
```

يمكننا أيضًا تعديل الإحصاءات باستخدام تعليمات `ALTER`:

```sql theme={null}
ALTER TABLE tab ADD STATISTICS b TYPE tdigest, uniq;
ALTER TABLE tab DROP STATISTICS a;
```

توفّر هذه الإحصاءات خفيفة الوزن معلومات مجمّعة عن توزيع القيم في الأعمدة. وتُخزَّن الإحصاءات في كل جزء وتُحدَّث مع كل عملية إدراج.
ولا يمكن استخدامها لتحسين `PREWHERE` إلا إذا فعّلنا `set use_statistics = 1`.

<div id="part-pruning-with-statistics">
  #### تقليم الأجزاء باستخدام الإحصاءات
</div>

عند تمكين `use_statistics_for_part_pruning`، يمكن استخدام الإحصاءات في تقليم الأجزاء.
حاليًا، لا يدعم تقليم الأجزاء إلا إحصاءات `basic` (وإحصاءات `minmax` المهملة). وعند تعريف مثل هذه الإحصاءات لعمود، يتتبّع ClickHouse القيمتَين الصغرى والكبرى لذلك العمود في كل جزء.
يتيح تقليم الأجزاء تخطي قراءة أجزاء البيانات كاملةً عندما يتعذر على شرط التصفية في الاستعلام مطابقة أي صفوف في ذلك الجزء.

**مثال:**

```sql theme={null}
-- Create a table with basic statistics on the 'value' column
CREATE TABLE test_stats
(
    id UInt64,
    value Int64 STATISTICS(basic)
)
ENGINE = MergeTree
ORDER BY id;

SYSTEM STOP MERGES test_stats;

-- Insert data in separate inserts to create multiple parts
INSERT INTO test_stats SELECT number, number FROM numbers(1000); -- Part 1: value range [0, 999]
INSERT INTO test_stats SELECT number, number + 10000 FROM numbers(1000); -- Part 2: value range [10000, 10999]

SET use_statistics_for_part_pruning = 1;

-- This query will skip Part 1 entirely because its max value (999) < 5000
SELECT count() FROM test_stats WHERE value > 5000;

-- Use EXPLAIN to see the pruning effect
EXPLAIN indexes = 1 SELECT count() FROM test_stats WHERE value > 5000;
-- The output will show "Parts: 1/2" indicating one part was pruned
```

<div id="available-types-of-column-statistics">
  ### الأنواع المتاحة من إحصاءات الأعمدة
</div>

* `basic`

  حزمة مضغوطة من الملخصات ذات القيمة الواحدة المستمدة من عمود. وبحسب نوع العمود، تُعبَّأ العناصر التالية:

  * لأي عمود تُمثَّل قيمه كأعداد (أعداد صحيحة، أعداد فاصلة عائمة، `Decimal*`، `Date*`، `DateTime*`، `Enum*`، `IPv4`، ...): القيمة الدنيا والقيمة القصوى، مما يتيح تقدير انتقائية مرشحات النطاق وتمكين تقليم الأجزاء؛
  * لأعمدة `String` و`FixedString`: إجمالي طول القيم غير `NULL` بالبايت (الذي يمكن اشتقاق متوسط طول السلسلة منه)؛
  * لأعمدة `Nullable` و`LowCardinality(Nullable)`: عدد قيم `NULL`، الذي يستخدمه المُحسِّن لاستبعاد صفوف `NULL` من تقديرات الانتقائية.

    يمكن لإحصائية `basic` واحدة أن تعبّئ عدة عناصر من هذه في الوقت نفسه — فعلى سبيل المثال، في عمود `Nullable(UInt32)`، تتتبّع كلاً من الحد الأدنى/الأقصى الرقمي وعدد قيم `NULL`. وبالمقارنة مع `minmax`، تعمل `basic` أيضاً مع أعمدة `String` / `FixedString`، ويمكن تعريفها على أغلفة `Nullable` لأنواع مثل `UUID` أو `IPv6` فقط لتتبّع عدد قيم `NULL`.

* `minmax` (مهمل)

<Note>
  إحصاءات `minmax` مهملة ولم يعد بالإمكان إنشاؤها (`CREATE TABLE ... STATISTICS(minmax)` و`ALTER TABLE ... ADD/MODIFY STATISTICS ... TYPE minmax` تُرجع خطأ). تظل الجداول والأجزاء الحالية التي تحتوي على إحصاءات `minmax` تعمل. استخدم إحصاءات `basic` بدلاً منها.
</Note>

* `tdigest`

<Warning>
  إحصاءات النوع `tdigest` لها تكاليف إنشاء مرتفعة وقد تؤدي إلى إبطاء استيعاب البيانات.
</Warning>

هياكل [TDigest](https://github.com/tdunning/t-digest) التقريبية التي تتيح حساب النسب المئوية التقريبية (مثل المئين التسعين) للأعمدة الرقمية.

* `uniq`

  هياكل [BJKST](https://people.iith.ac.in/aravind/Files-CS5120/pc-lec14-BJKST.pdf) التقريبية التي توفّر تقديراً لعدد القيم المميزة التي يحتويها العمود. وتستخدم داخلياً [`uniq`](/docs/ar/reference/functions/aggregate-functions/uniq).

* `uniq_v2`

  مشابه لـ `uniq`، لكنه يستخدم داخلياً [`uniqCombined`](/docs/ar/reference/functions/aggregate-functions/uniqCombined)`(12)` (وهو أحد أشكال [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)). يستهلك ذاكرة أقل من `uniq` ويمكن بناؤه بسرعة أكبر.

* `countmin`

<Warning>
  إحصاءات النوع `countmin` لها تكاليف إنشاء مرتفعة وقد تؤدي إلى إبطاء استيعاب البيانات.
</Warning>

هياكل [CountMin](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch) التقريبية التي توفّر عدّاً تقريبياً لتكرار كل قيمة في العمود.

<div id="supported-data-types">
  ### أنواع البيانات المدعومة
</div>

|          | (U)Int\*, Float\*, Decimal(*), Date*, Boolean, Enum\* | IPv4 | String or FixedString |
| -------- | ----------------------------------------------------- | ---- | --------------------- |
| basic    | ✔                                                     | ✔    | ✔                     |
| countmin | ✔                                                     | ✔    | ✔                     |
| minmax   | ✔                                                     | ✔    | ✗                     |
| tdigest  | ✔                                                     | ✗    | ✗                     |
| uniq     | ✔                                                     | ✔    | ✔                     |
| uniq\_v2 | ✔                                                     | ✔    | ✔                     |

كل ما سبق يقبل أيضًا مغلّفات `Nullable` و`LowCardinality(Nullable)` للأنواع المدرجة. ويمكن أيضًا تعريف `Basic` على مغلّفات `Nullable` لأنواع مثل `UUID` أو `IPv6` فقط لتتبّع عدد قيم NULL.

<div id="supported-operations">
  ### العمليات المدعومة
</div>

|          | مرشحات المساواة (==) | مرشحات النطاق (`>, >=, <, <=`) |
| -------- | -------------------- | ------------------------------ |
| basic    | ✗                    | ✔ (للأعمدة الرقمية فقط)        |
| countmin | ✔                    | ✗                              |
| minmax   | ✗                    | ✔ (للأعمدة الرقمية فقط)        |
| tdigest  | ✗                    | ✔ (للأعمدة الرقمية فقط)        |
| uniq     | ✔                    | ✗                              |
| uniq\_v2 | ✔                    | ✗                              |

بالنسبة إلى `basic` على الأعمدة `String` / `FixedString`، لا يسجّل هذا الإحصاء إلا
إجمالي طول البايتات للقيم غير `NULL` (ويُستخدم لتقدير متوسط طول السلسلة النصية) وعدد قيم `NULL`؛
ولا يُعتمد عليه في مرشحات النطاق أو تقليم الأجزاء.

<div id="column-level-settings">
  ## إعدادات على مستوى العمود
</div>

يمكن تجاوز بعض إعدادات MergeTree على مستوى العمود:

* `max_compress_block_size` — الحد الأقصى لحجم كتل البيانات غير المضغوطة قبل ضغطها لكتابتها في جدول.
* `min_compress_block_size` — الحد الأدنى لحجم كتل البيانات غير المضغوطة المطلوب لضغطها عند كتابة العلامة التالية.

مثال:

```sql theme={null}
CREATE TABLE tab
(
    id Int64,
    document String SETTINGS (min_compress_block_size = 16777216, max_compress_block_size = 16777216)
)
ENGINE = MergeTree
ORDER BY id
```

يمكن تعديل إعدادات مستوى العمود أو إزالتها باستخدام [ALTER MODIFY COLUMN](/docs/ar/reference/statements/alter/column)، على سبيل المثال:

* إزالة `SETTINGS` من تعريف العمود:

```sql theme={null}
ALTER TABLE tab MODIFY COLUMN document REMOVE SETTINGS;
```

* عدّل إعدادًا:

```sql theme={null}
ALTER TABLE tab MODIFY COLUMN document MODIFY SETTING min_compress_block_size = 8192;
```

* إعادة تعيين إعداد واحد أو أكثر، مع إزالة تعريف الإعداد أيضًا من تعبير العمود في استعلام CREATE الخاص بالجدول.

```sql theme={null}
ALTER TABLE tab MODIFY COLUMN document RESET SETTING min_compress_block_size;
```
