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

# مفتاح تقسيم مخصص

<Note>
  في معظم الحالات، لن تحتاج إلى مفتاح تقسيم، وفي أغلب الحالات الأخرى لن تحتاج إلى مفتاح تقسيم أكثر دقة من التقسيم حسب الشهر، إلا إذا كنت تستهدف حالة استخدام observability حيث يكون التقسيم حسب اليوم شائعًا.

  يجب ألا تستخدم تقسيمًا مفرط الدقة أبدًا. لا تقسّم بياناتك حسب معرّفات العملاء أو أسمائهم. وبدلًا من ذلك، اجعل معرّف العميل أو اسمه هو العمود الأول في التعبير `ORDER BY`.
</Note>

التقسيم متاح لجداول [عائلة MergeTree](/docs/ar/reference/engines/table-engines/mergetree-family/mergetree)، بما في ذلك [الجداول المكررة](/docs/ar/reference/engines/table-engines/mergetree-family/replication) و[العروض المادية](/docs/ar/reference/statements/create/view#materialized-view).

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

يُحدَّد القسم في العبارة `PARTITION BY expr` عند [إنشاء جدول](/docs/ar/reference/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-creating-a-table). ويمكن أن يكون مفتاح التقسيم أي تعبير مشتق من أعمدة الجدول. على سبيل المثال، لتحديد التقسيم حسب الشهر، استخدم التعبير `toYYYYMM(date_column)`:

```sql theme={null}
CREATE TABLE visits
(
    VisitDate Date,
    Hour UInt8,
    ClientID UUID
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(VisitDate)
ORDER BY Hour;
```

يمكن أيضًا أن يكون مفتاح التقسيم مجموعة من التعبيرات (على غرار [المفتاح الأساسي](/docs/ar/reference/engines/table-engines/mergetree-family/mergetree#primary-keys-and-indexes-in-queries)). على سبيل المثال:

```sql theme={null}
ENGINE = ReplicatedCollapsingMergeTree('/clickhouse/tables/name', 'replica1', Sign)
PARTITION BY (toMonday(StartDate), EventType)
ORDER BY (CounterID, StartDate, intHash32(UserID));
```

في هذا المثال، نضبط التقسيم بحسب أنواع الأحداث التي وقعت خلال الأسبوع الحالي.

بشكل افتراضي، لا يكون مفتاح التقسيم ذي الفاصلة العائمة مدعومًا. لاستخدامه، فعِّل الإعداد [allow\_floating\_point\_partition\_key](/docs/ar/reference/settings/merge-tree-settings#allow_floating_point_partition_key).

عند إدراج بيانات جديدة في جدول، تُخزَّن هذه البيانات كجزء بيانات منفصل (دفعة) مرتَّب حسب المفتاح الأساسي. وبعد 10 إلى 15 دقيقة من الإدراج، تُدمَج أجزاء البيانات التابعة للقسم نفسه في جزء واحد كامل.

<Info>
  لا تعمل عملية الدمج إلا على أجزاء البيانات التي لها القيمة نفسها لتعبير التقسيم. وهذا يعني **ألا تنشئ أقسامًا شديدة التفصيل** (أكثر من نحو ألف قسم). وإلا فسيكون أداء استعلام `SELECT` ضعيفًا بسبب العدد الكبير على نحو غير معقول من الملفات في نظام الملفات وواصفات الملفات المفتوحة.
</Info>

استخدم جدول [system.parts](/docs/ar/reference/system-tables/parts) لعرض أجزاء الجدول والأقسام. على سبيل المثال، لنفترض أن لدينا جدول `visits` مع تقسيم حسب الشهر. لننفّذ استعلام `SELECT` على جدول `system.parts`:

```sql theme={null}
SELECT
    partition,
    name,
    active
FROM system.parts
WHERE table = 'visits'
```

```text theme={null}
┌─partition─┬─name──────────────┬─active─┐
│ 201901    │ 201901_1_3_1      │      0 │
│ 201901    │ 201901_1_9_2_11   │      1 │
│ 201901    │ 201901_8_8_0      │      0 │
│ 201901    │ 201901_9_9_0      │      0 │
│ 201902    │ 201902_4_6_1_11   │      1 │
│ 201902    │ 201902_10_10_0_11 │      1 │
│ 201902    │ 201902_11_11_0_11 │      1 │
└───────────┴───────────────────┴────────┘
```

يحتوي العمود `partition` على أسماء الأقسام. يوجد قسمان في هذا المثال: `201901` و`201902`. يمكنك استخدام قيمة هذا العمود لتحديد اسم القسم في استعلامات [ALTER ... PARTITION](/docs/ar/reference/statements/alter/partition).

يحتوي العمود `name` على أسماء أجزاء بيانات القسم. يمكنك استخدام هذا العمود لتحديد اسم الجزء في استعلام [ALTER ATTACH PART](/docs/ar/reference/statements/alter/partition#attach-partitionpart).

لنحلّل اسم الجزء: `201901_1_9_2_11`:

* `201901` هو اسم القسم.
* `1` هو الرقم الأدنى لكتلة البيانات.
* `9` هو الرقم الأقصى لكتلة البيانات.
* `2` هو مستوى الجزء (عمق شجرة الدمج التي تكوَّن منها).
* `11` هو إصدار التعديل (إذا خضع الجزء لتعديل)

<Info>
  تحمل أجزاء الجداول من النوع القديم الاسم: `20190117_20190123_2_2_0` (الحد الأدنى للتاريخ - الحد الأقصى للتاريخ - الحد الأدنى لرقم الكتلة - الحد الأقصى لرقم الكتلة - المستوى).
</Info>

يعرض العمود `active` حالة الجزء. تعني `1` أنه نشط، وتعني `0` أنه غير نشط. وتشمل الأجزاء غير النشطة، على سبيل المثال، الأجزاء الأصلية المتبقية بعد دمجها في جزء أكبر. كما تُصنَّف أجزاء البيانات التالفة أيضًا على أنها غير نشطة.

كما ترى في المثال، توجد عدة أجزاء منفصلة للقسم نفسه (على سبيل المثال، `201901_1_3_1` و`201901_1_9_2`). وهذا يعني أن هذه الأجزاء لم تُدمج بعد. يدمج ClickHouse أجزاء البيانات المُدرجة دوريًا، عادةً بعد نحو 15 دقيقة من الإدراج. بالإضافة إلى ذلك، يمكنك إجراء دمج غير مجدول باستخدام استعلام [OPTIMIZE](/docs/ar/reference/statements/optimize). مثال:

```sql theme={null}
OPTIMIZE TABLE visits PARTITION 201902;
```

```text theme={null}
┌─partition─┬─name─────────────┬─active─┐
│ 201901    │ 201901_1_3_1     │      0 │
│ 201901    │ 201901_1_9_2_11  │      1 │
│ 201901    │ 201901_8_8_0     │      0 │
│ 201901    │ 201901_9_9_0     │      0 │
│ 201902    │ 201902_4_6_1     │      0 │
│ 201902    │ 201902_4_11_2_11 │      1 │
│ 201902    │ 201902_10_10_0   │      0 │
│ 201902    │ 201902_11_11_0   │      0 │
└───────────┴──────────────────┴────────┘
```

سيتم حذف الأجزاء غير النشطة بعد الدمج بنحو 10 دقائق.

وثمة طريقة أخرى لعرض مجموعة من الأجزاء والأقسام، وهي الانتقال إلى مجلد الجدول: `/var/lib/clickhouse/data/<database>/<table>/`. على سبيل المثال:

```bash theme={null}
/var/lib/clickhouse/data/default/visits$ ls -l
total 40
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  1 16:48 201901_1_3_1
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201901_1_9_2_11
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 15:52 201901_8_8_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 15:52 201901_9_9_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201902_10_10_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:17 201902_11_11_0
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 16:19 201902_4_11_2_11
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  5 12:09 201902_4_6_1
drwxr-xr-x 2 clickhouse clickhouse 4096 Feb  1 16:48 detached
```

المجلدات '201901\_1\_1\_0' و'201901\_1\_7\_1' وما إلى ذلك هي أدلة الأجزاء. ينتمي كل جزء إلى قسم مقابلة، ولا يحتوي إلا على بيانات شهر معيّن (يستخدم الجدول في هذا المثال التقسيم حسب الشهر).

يحتوي دليل `detached` على الأجزاء التي فُصلت عن الجدول باستخدام استعلام [DETACH](/docs/ar/reference/statements/detach). كما تُنقل الأجزاء التالفة إلى هذا الدليل بدلًا من حذفها. لا يستخدم الخادوم الأجزاء الموجودة في دليل `detached`. يمكنك إضافة البيانات في هذا الدليل أو حذفها أو تعديلها في أي وقت، لكن الخادوم لن يعلم بذلك إلى أن تُشغّل استعلام [ATTACH](/docs/ar/reference/statements/alter/partition#attach-partitionpart).

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

يتيح لك ClickHouse تنفيذ عمليات على الأقسام: حذفها، أو نسخها من جدول إلى آخر، أو إنشاء نسخة احتياطية. راجع قائمة جميع العمليات في قسم [التعامل مع الأقسام والأجزاء](/docs/ar/reference/statements/alter/partition).

<div id="group-by-optimisation-using-partition-key">
  ## تحسين GROUP BY باستخدام مفتاح التقسيم
</div>

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

المثال الشائع هو:

```sql theme={null}
CREATE TABLE session_log
(
    UserID UInt64,
    SessionID UUID
)
ENGINE = MergeTree
PARTITION BY sipHash64(UserID) % 16
ORDER BY tuple();

SELECT
    UserID,
    COUNT()
FROM session_log
GROUP BY UserID;
```

<Note>
  يعتمد أداء مثل هذا الاستعلام على تخطيط الجدول. يكون هذا التحسين مُمكّنًا افتراضيًا بدءًا من الإصدار 26.7؛ وتتخطاه استدلالات وقت التشغيل تلقائيًا عندما يكون تخطيط الأقسام غير ملائم — وتحديدًا عندما يكون عدد الأقسام قليلًا جدًا (أقل من `max_threads / 2`)، أو كبيرًا جدًا (أكثر من `max_number_of_partitions_for_independent_aggregation`)، أو عندما يكون هناك تفاوت كبير في أحجام الأقسام (بحيث يحتوي أكبر قسم على عدد من الصفوف يزيد على ضعفي إجمالي عدد الصفوف مقسومًا على `max_threads`). توضح القائمة أدناه عوامل التخطيط اللازمة لتحقيق أداء جيد بشكل عام؛ ومن بينها، لا تفرض استدلالات وقت التشغيل إلا عدد الأقسام وتفاوت الأحجام.
</Note>

العوامل الأساسية لتحقيق أداء جيد هي:

* يجب أن يكون عدد الأقسام المشاركة في الاستعلام كبيرًا بما يكفي (أكثر من `max_threads / 2`)، وإلا فلن يستفيد الاستعلام من موارد الجهاز على النحو الأمثل
* يجب ألا تكون الأقسام صغيرة جدًا، حتى لا تتحول المعالجة الدفعية إلى معالجة صفًا تلو الآخر
* يجب أن تكون الأقسام متقاربة في الحجم، بحيث تنفذ جميع خيوط التنفيذ مقدارًا متقاربًا من العمل

<Info>
  يُنصح بتطبيق دالة hash على الأعمدة في عبارة `partition by` من أجل توزيع البيانات بالتساوي بين الأقسام.
</Info>

الإعدادات ذات الصلة هي:

* `allow_aggregate_partitions_independently` - يتحكم في ما إذا كان استخدام هذا التحسين مُمكّنًا
* `force_aggregate_partitions_independently` - يفرض استخدامه عندما يكون قابلًا للتطبيق من حيث صحة النتائج، لكن يتم تعطيله بواسطة المنطق الداخلي الذي يقدّر مدى جدواه
* `max_number_of_partitions_for_independent_aggregation` - حد صارم لأقصى عدد من الأقسام يمكن أن يحتويه الجدول
