> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> توثيق لعوامل IN باستثناء عوامل NOT IN وGLOBAL IN وGLOBAL NOT IN التي يتم تناولها بشكل منفصل

# عوامل IN

يتم تناول عوامل التشغيل `IN` و`NOT IN` و`GLOBAL IN` و`GLOBAL NOT IN` بشكل منفصل، نظرًا لغنى وظائفها وتعدد إمكانياتها.

الجانب الأيسر من المعامل هو إما عمود واحد أو Tuple.

أمثلة:

```sql theme={null}
SELECT UserID IN (123, 456) FROM ...
SELECT (CounterID, UserID) IN ((34, 123), (101500, 456)) FROM ...
```

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

لا تُدرج قيمًا كثيرة بشكل صريح (أي الملايين منها). إذا كانت مجموعة البيانات كبيرة، ضعها في جدول مؤقت (للاطلاع على مثال، راجع قسم [البيانات الخارجية لمعالجة الاستعلامات](/ar/reference/engines/table-engines/special/external-data))، ثم استخدم استعلامًا فرعيًا.

يمكن أن يكون الجانب الأيمن من المعامل مجموعةً من التعبيرات الثابتة، أو مجموعةً من Tuples تحتوي على تعبيرات ثابتة (كما هو موضح في الأمثلة أعلاه)، أو اسم جدول في قاعدة البيانات، أو استعلاماً فرعياً `SELECT` داخل أقواس.

للتوافق مع الإصدارات السابقة، عندما يكون الجانب الأيمن تعبير `tuple` واحدًا، يمكن تفسيره إما كمجموعة من القيم أو كقيمة tuple واحدة، وذلك بحسب الجانب الأيسر من عامل `IN`. إذا كان الجانب الأيسر قيمةً scalar، فإن ClickHouse يعامل عناصر تعبير `tuple` الواحد هذا في الجانب الأيمن كقيم `IN` منفصلة:

```sql title="Query" theme={null}
SELECT
    1 IN (tuple(1, 2)) AS one_in_tuple,
    2 IN (tuple(1, 2)) AS two_in_tuple,
    3 IN (tuple(1, 2)) AS three_in_tuple;
```

```text title="Response" theme={null}
┌─one_in_tuple─┬─two_in_tuple─┬─three_in_tuple─┐
│            1 │            1 │              0 │
└──────────────┴──────────────┴────────────────┘
```

يعمل هذا مثل `SELECT 1 IN (1, 2)`. إذا كان الجانب الأيسر أيضاً Tuple، فإن الجانب الأيمن يُفسَّر باعتباره مجموعة من قيم Tuple:

```sql title="Query" theme={null}
SELECT tuple(1, 2) IN (tuple(1, 2)) AS tuple_in_tuple;
```

```text title="Response" theme={null}
┌─tuple_in_tuple─┐
│              1 │
└────────────────┘
```

تنطبق هذه المعالجة الخاصة فقط عندما يكون الجانب الأيمن تعبير `tuple` واحداً. لا يمكن مطابقة الجانب الأيسر القياسي (scalar) مع جانب أيمن يحتوي على قيم tuple متعددة:

```sql title="Query" theme={null}
SELECT 1 IN (tuple(1, 2), tuple(3, 4));
```

```text title="Response" theme={null}
Code: 43. DB::Exception: Unsupported types for IN. First argument type UInt8. Second argument type Tuple(Tuple(UInt8, UInt8), Tuple(UInt8, UInt8)). (ILLEGAL_TYPE_OF_ARGUMENT)
```

يتيح ClickHouse اختلاف الأنواع بين الجانب الأيسر والجانب الأيمن في الاستعلام الفرعي `IN`.
في هذه الحالة، يُحوِّل النظام قيمة الجانب الأيمن إلى نوع الجانب الأيسر،
كما لو طُبِّقت الدالة [accurateCastOrNull](/ar/reference/functions/regular-functions/type-conversion-functions#accurateCastOrNull) على الجانب الأيمن.

يعني هذا أن نوع البيانات يصبح [Nullable](/ar/reference/data-types/nullable)، وإذا تعذّر إجراء التحويل، فإنه يُرجع [NULL](/ar/reference/settings/formats#input_format_null_as_default).

**مثال**

```sql title="Query" theme={null}
SELECT '1' IN (SELECT 1);
```

```text title="Response" theme={null}
┌─in('1', _subquery49)─┐
│                    1 │
└──────────────────────┘
```

إذا كان الجانب الأيمن من المعامل هو اسم جدول (على سبيل المثال، `UserID IN users`)، فهذا يعادل الاستعلام الفرعي `UserID IN (SELECT * FROM users)`. استخدم هذا عند التعامل مع البيانات الخارجية المُرسَلة مع الاستعلام. على سبيل المثال، يمكن إرسال الاستعلام مصحوبًا بمجموعة من معرّفات المستخدمين المحمَّلة في الجدول المؤقت 'users'، والتي يجب تصفيتها.

إذا كان الجانب الأيمن من المعامل اسمَ جدول يستخدم محرك Set (مجموعة بيانات جاهزة تُحفظ دائمًا في ذاكرة RAM)، فلن تُعاد إنشاء مجموعة البيانات من جديد عند كل استعلام.

قد يحدد الاستعلام الفرعي أكثر من عمود واحد لتصفية المجموعات.

مثال:

```sql title="Query" theme={null}
SELECT (CounterID, UserID) IN (SELECT CounterID, UserID FROM ...) FROM ...
```

يجب أن تكون الأعمدة الواقعة على يسار عامل التشغيل `IN` ويمينه من نفس النوع.

يمكن أن يرد عامل التشغيل `IN` والاستعلام الفرعي في أي جزء من الاستعلام، بما في ذلك داخل الدوال التجميعية ودوال lambda.
مثال:

```sql title="Query" theme={null}
SELECT
    EventDate,
    avg(UserID IN
    (
        SELECT UserID
        FROM test.hits
        WHERE EventDate = toDate('2014-03-17')
    )) AS ratio
FROM test.hits
GROUP BY EventDate
ORDER BY EventDate ASC
```

```text title="Response" theme={null}
┌──EventDate─┬────ratio─┐
│ 2014-03-17 │        1 │
│ 2014-03-18 │ 0.807696 │
│ 2014-03-19 │ 0.755406 │
│ 2014-03-20 │ 0.723218 │
│ 2014-03-21 │ 0.697021 │
│ 2014-03-22 │ 0.647851 │
│ 2014-03-23 │ 0.648416 │
└────────────┴──────────┘
```

لكل يوم بعد 17 مارس، احسب النسبة المئوية لمرات عرض الصفحات التي جاءت من مستخدمين زاروا الموقع في 17 مارس.
يُنفَّذ الاستعلام الفرعي في بند `IN` مرة واحدة فقط دائمًا وعلى خادم واحد. لا توجد استعلامات فرعية معتمدة.

<div id="null-processing">
  ## معالجة NULL
</div>

أثناء معالجة الطلب، يفترض عامل التشغيل `IN` أن ناتج أي عملية على [NULL](/ar/reference/settings/formats#input_format_null_as_default) يساوي دائمًا `0`، بغض النظر عمّا إذا كانت `NULL` على الجانب الأيمن أو الأيسر من المعامل. لا تُدرَج قيم `NULL` في أي مجموعة بيانات، ولا تُعدّ متساوية فيما بينها، ولا يمكن مقارنتها إذا كانت [transform\_null\_in = 0](/ar/reference/settings/session-settings#transform_null_in).

فيما يلي مثال باستخدام الجدول `t_null`:

```text theme={null}
┌─x─┬────y─┐
│ 1 │ ᴺᵁᴸᴸ │
│ 2 │    3 │
└───┴──────┘
```

يُرجع تنفيذ الاستعلام `SELECT x FROM t_null WHERE y IN (NULL,3)` النتيجة التالية:

```text theme={null}
┌─x─┐
│ 2 │
└───┘
```

يمكنك ملاحظة أن الصف الذي تكون فيه `y = NULL` يُستبعَد من نتائج الاستعلام. ويعود ذلك إلى أن ClickHouse لا يستطيع تحديد ما إذا كانت `NULL` ضمن المجموعة `(NULL,3)`، فيُرجِع `0` نتيجةً لهذه العملية، ولذلك يستبعد `SELECT` هذا الصف من المخرجات النهائية.

```sql theme={null}
SELECT y IN (NULL, 3)
FROM t_null
```

```text theme={null}
┌─in(y, tuple(NULL, 3))─┐
│                     0 │
│                     1 │
└───────────────────────┘
```

<div id="distributed-subqueries">
  ## الاستعلامات الفرعية الموزعة
</div>

هناك خياران لعوامل `IN` مع الاستعلامات الفرعية (على غرار عوامل `JOIN`): الصيغة العادية `IN` / `JOIN` والصيغة العامة `GLOBAL IN` / `GLOBAL JOIN`، ويختلفان في طريقة تنفيذهما عند معالجة الاستعلامات الموزعة.

<Note>
  تذكّر أن الخوارزميات الموضّحة أدناه قد تعمل بصورة مختلفة تبعًا لإعداد `distributed_product_mode` ضمن [الإعدادات](/ar/reference/settings/session-settings).
</Note>

عند استخدام `IN` العادية، يُرسَل الاستعلام إلى الخوادم البعيدة، وتُنفِّذ كلٌّ منها الاستعلامات الفرعية الواردة في جملة `IN` أو `JOIN`.

عند استخدام `GLOBAL IN` / `GLOBAL JOIN`، تُنفَّذ أولاً جميع الاستعلامات الفرعية الخاصة بـ `GLOBAL IN` / `GLOBAL JOIN`، وتُجمَّع نتائجها في جداول مؤقتة. ثم تُرسَل هذه الجداول المؤقتة إلى كل خادم بعيد، حيث تُنفَّذ الاستعلامات باستخدام هذه البيانات المؤقتة.

بالنسبة لـ `GLOBAL ... JOIN`، يعتمد تحديد أي جانب من الـ join يُحسب كاستعلام فرعي على نوع الـ join: ففي حالتَي `LEFT` و`INNER`، يُحسب الجدول الأيمن؛ أما في حالة `RIGHT`، فيُحسب الجدول الأيسر بدلًا من ذلك، نظرًا لأن الجدول الأيمن هو الجانب المحفوظ وينبغي قراءته من الأجزاء (shards).

بالنسبة للاستعلام غير الموزَّع، استخدم `IN` / `JOIN` العادي.

توخَّ الحذر عند استخدام الاستعلامات الفرعية في عبارتَي `IN` / `JOIN` عند معالجة الاستعلامات الموزعة.

لنستعرض بعض الأمثلة. افترض أن كل خادم في الكلستر يحتوي على **local\_table** عادية. كما يحتوي كل خادم على جدول **distributed\_table** من نوع **Distributed**، والذي يشمل جميع الخوادم في الكلستر.

عند توجيه استعلام إلى **distributed\_table**، يُرسَل الاستعلام إلى جميع الخوادم البعيدة وينفَّذ عليها باستخدام **local\_table**.

على سبيل المثال، الاستعلام

```sql theme={null}
SELECT uniq(UserID) FROM distributed_table
```

سيتم إرساله إلى جميع الخوادم البعيدة بوصفه

```sql theme={null}
SELECT uniq(UserID) FROM local_table
```

وتُنفَّذ على كلٍّ منها بالتوازي، حتى تصل إلى المرحلة التي يمكن فيها دمج النتائج الوسيطة. عندئذٍ، تُعاد النتائج الوسيطة إلى الخادم الطالب لتُدمج عليه، ثم تُرسَل النتيجة النهائية إلى العميل.

لنفحص الآن استعلامًا يستخدم `IN`:

```sql theme={null}
SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34)
```

* حساب تقاطع قيم audience لموقعين.

سيُرسَل هذا الاستعلام إلى جميع الخوادم البعيدة بوصفه

```sql theme={null}
SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM local_table WHERE CounterID = 34)
```

بمعنى آخر، سيتم تجميع مجموعة البيانات الموجودة في عبارة `IN` على كل خادم بصورة مستقلة، استناداً فقط إلى البيانات المخزنة محلياً على كل خادم من الخوادم.

سيعمل هذا بشكل صحيح وأمثل إذا كنت مستعدًا لهذه الحالة وقد وزّعت البيانات على خوادم الـ cluster بحيث تقع بيانات كل UserID بالكامل على خادم واحد. في هذه الحالة، ستكون جميع البيانات اللازمة متاحةً محليًا على كل خادم. وإلا، فستكون النتيجة غير دقيقة. نشير إلى هذا النوع من الـ query بـ "local IN".

لتصحيح طريقة عمل الاستعلام عندما تكون البيانات موزَّعة عشوائيًا عبر خوادم الكلستر، يمكنك تحديد **distributed\_table** داخل استعلام فرعي. سيبدو الاستعلام كالتالي:

```sql theme={null}
SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34)
```

سيُرسَل هذا الاستعلام إلى جميع الخوادم البعيدة بوصفه

```sql theme={null}
SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID IN (SELECT UserID FROM distributed_table WHERE CounterID = 34)
```

سيبدأ الاستعلام الفرعي بالتنفيذ على كل خادم بعيد. ونظرًا لأن الاستعلام الفرعي يستخدم جدولًا موزعًا، فسيُعاد إرسال الاستعلام الفرعي الموجود على كل خادم بعيد إلى جميع الخوادم البعيدة بالشكل التالي:

```sql theme={null}
SELECT UserID FROM local_table WHERE CounterID = 34
```

على سبيل المثال، إذا كان لديك مجموعة مكوّنة من 100 خادم، فإن تنفيذ الاستعلام بالكامل سيستلزم 10,000 طلب أولي، وهو أمر غير مقبول بشكل عام.

في مثل هذه الحالات، يجب دائمًا استخدام `GLOBAL IN` بدلًا من `IN`. لنرَ كيف يعمل ذلك في الاستعلام:

```sql theme={null}
SELECT uniq(UserID) FROM distributed_table WHERE CounterID = 101500 AND UserID GLOBAL IN (SELECT UserID FROM distributed_table WHERE CounterID = 34)
```

سيُنفّذ الخادم الطالب الاستعلام الفرعي:

```sql theme={null}
SELECT UserID FROM distributed_table WHERE CounterID = 34
```

وستُوضع النتيجة في جدول مؤقت في ذاكرة الوصول العشوائي (RAM). ثم يُرسَل الطلب إلى كل خادم بعيد على النحو التالي:

```sql theme={null}
SELECT uniq(UserID) FROM local_table WHERE CounterID = 101500 AND UserID GLOBAL IN _data1
```

سيُرسَل الجدول المؤقت `_data1` إلى كل خادم بعيد مع الاستعلام (اسم الجدول المؤقت يعتمد على التنفيذ).

هذا أكثر كفاءة من استخدام `IN` العادي. ومع ذلك، ضع النقاط التالية في الاعتبار:

1. عند إنشاء جدول مؤقت، لا تصبح البيانات مميّزة تلقائيًا. لتقليل حجم البيانات المنقولة عبر الشبكة، حدِّد DISTINCT في الاستعلام الفرعي. (لا تحتاج إلى فعل ذلك مع `IN` العادي.)
2. سيُرسَل الجدول المؤقت إلى جميع الخوادم البعيدة. ولا يراعي الإرسال طوبولوجيا الشبكة. على سبيل المثال، إذا كانت 10 خوادم بعيدة موجودة في مركز بيانات بعيد جدًا عن خادم الطالب، فستُرسَل البيانات 10 مرات عبر القناة إلى مركز البيانات البعيد. حاول تجنب مجموعات البيانات الكبيرة عند استخدام `GLOBAL IN`.
3. عند نقل البيانات إلى الخوادم البعيدة، لا يمكن تهيئة القيود المفروضة على عرض نطاق الشبكة. وقد يؤدي ذلك إلى إرهاق الشبكة.
4. حاول توزيع البيانات على الخوادم بحيث لا تضطر إلى استخدام `GLOBAL IN` بانتظام.
5. إذا كنت بحاجة إلى استخدام `GLOBAL IN` كثيرًا، فخطط لموقع عنقود ClickHouse بحيث لا توجد مجموعة واحدة من النسخ المتماثلة إلا في مركز بيانات واحد، مع توفر شبكة سريعة بينها، بحيث يمكن معالجة الاستعلام بالكامل داخل مركز بيانات واحد.

ومن المنطقي أيضًا تحديد جدول محلي في عبارة `GLOBAL IN`، إذا كان هذا الجدول المحلي متاحًا فقط على خادم الطالب وكنت تريد استخدام بياناته على الخوادم البعيدة.

<div id="distributed-subqueries-and-max_rows_in_set">
  ### الاستعلامات الفرعية الموزعة و max\_rows\_in\_set
</div>

يمكنك استخدام [`max_rows_in_set`](/ar/reference/settings/session-settings#max_rows_in_set) و [`max_bytes_in_set`](/ar/reference/settings/session-settings#max_bytes_in_set) للتحكم في مقدار البيانات المنقولة أثناء الاستعلامات الموزعة.

وتزداد أهمية ذلك بشكل خاص إذا كان استعلام `GLOBAL IN` يُرجِع كمية كبيرة من البيانات. انظر عبارة SQL التالية:

```sql theme={null}
SELECT * FROM table1 WHERE col1 GLOBAL IN (SELECT col1 FROM table2 WHERE <some_predicate>)
```

إذا لم يكن `some_predicate` انتقائيًا بدرجة كافية، فسيُرجع كمية كبيرة من البيانات ويتسبب في مشكلات بالأداء. في مثل هذه الحالات، من الحكمة الحدّ من نقل البيانات عبر الشبكة. لاحظ أيضًا أن [`set_overflow_mode`](/ar/reference/settings/session-settings#set_overflow_mode) مُعيَّن إلى `throw` (افتراضيًا)، ما يعني أنه يتم رفع استثناء عند بلوغ هذه العتبات.

<div id="distributed-subqueries-and-max_parallel_replicas">
  ### الاستعلامات الفرعية الموزعة و max\_parallel\_replicas
</div>

عندما تكون قيمة [max\_parallel\_replicas](#distributed-subqueries-and-max_parallel_replicas) أكبر من 1، تخضع الاستعلامات الموزعة لمزيد من التحويل.

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

```sql theme={null}
SELECT CounterID, count() FROM distributed_table_1 WHERE UserID IN (SELECT UserID FROM local_table_2 WHERE CounterID < 100)
SETTINGS max_parallel_replicas=3
```

يُحوَّل على كل خادم إلى:

```sql theme={null}
SELECT CounterID, count() FROM local_table_1 WHERE UserID IN (SELECT UserID FROM local_table_2 WHERE CounterID < 100)
SETTINGS parallel_replicas_count=3, parallel_replicas_offset=M
```

حيث تكون `M` بين `1` و`3` بحسب النسخة المتماثلة التي يُنفَّذ عليها الاستعلام المحلي.

تؤثر هذه الإعدادات في كل جدول من عائلة MergeTree ضمن الاستعلام، ولها التأثير نفسه كما لو جرى تطبيق `SAMPLE 1/3 OFFSET (M-1)/3` على كل جدول.

لذلك، فإن إضافة الإعداد [max\_parallel\_replicas](#distributed-subqueries-and-max_parallel_replicas) لن تُنتج نتائج صحيحة إلا إذا كان للجدولين مخطط النسخ المتماثل نفسه، وكان أخذ العينات فيهما يتم باستخدام UserID أو مفتاح فرعي له. وعلى وجه الخصوص، إذا لم يكن لدى `local_table_2` مفتاح أخذ عينات، فستنتج نتائج غير صحيحة. وتنطبق القاعدة نفسها على `JOIN`.

أحد الحلول البديلة، إذا كان `local_table_2` لا يستوفي المتطلبات، هو استخدام `GLOBAL IN` أو `GLOBAL JOIN`.

إذا لم يكن لدى الجدول مفتاح أخذ عينات، فيمكن استخدام خيارات أكثر مرونة لـ [parallel\_replicas\_custom\_key](/ar/reference/settings/session-settings#parallel_replicas_custom_key)، وقد ينتج عنها سلوك مختلف وأكثر ملاءمة.
