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

# INSERT ... SELECT غير المتزامن

> كيف يسلك INSERT ... SELECT مسار قائمة انتظار الإدراج غير المتزامن، وما يسري عليه من قواعد التوجيه والاحتساب والإلغاء.

لا يقتصر مسار قائمة انتظار [الإدراج غير المتزامن](/optimize/asynchronous-inserts) على `INSERT ... VALUES` العادي، بل يمكن لـ `INSERT ... SELECT` أيضًا أن يسلكه. توضّح هذه الصفحة متى يحدث ذلك، وكيف يُحتسب جانب الكتابة، وما الذي يحدث عند إلغاء الاستعلام أو انتهاء مهلته.

<h2 id="eligibility-and-routing">
  الأهلية وتوجيه المسار
</h2>

يسلك `INSERT ... SELECT` مسار قائمة الانتظار غير المتزامنة فقط عند استيفاء جميع الشروط التالية:

* `async_insert = 1`.
* `async_insert_select_as_async_insert = 1` (القيمة الافتراضية). هذا هو مفتاح التحكم الرئيسي: عند تعطيله، يكون `INSERT ... SELECT` متزامنًا دائمًا بصرف النظر عن `async_insert`. يؤدي ضبط `compatibility` على إصدار يسبق 26.10 إلى تغيير قيمته الافتراضية إلى `0`؛ ويمكن إعادة تفعيل هذا المسار بضبط `async_insert_select_as_async_insert = 1` صراحةً.
* تكون نتيجة `SELECT` بأكملها في كتلة واحدة لا يتجاوز حجمها `async_insert_max_data_size`.
* تكون الوجهة جدولًا من عائلة `MergeTree` (ويُتتبَّع الاسم البديل إلى هدفه للتحقق من هذا الشرط).

حتى مع استيفاء جميع الشروط أعلاه، يتحوّل الإدراج إلى المسار المتزامن في أيٍّ من الحالات التالية:

* تمتد النتيجة عبر أكثر من كتلة، أو يتجاوز حجمها `async_insert_max_data_size`، أو تكون فارغة.
* يُستخدم نصاب غير متوازٍ: يكون `insert_quorum` مضبوطًا و`insert_quorum_parallel = 0`.
* توجد عروض مُجسَّدة تعتمد على الوجهة.
* تكون الوجهة عرضًا مُجسَّدًا. ينطبق التحقق من `MergeTree` على العرض لا على جدول الهدف الخاص به، لذا لا يكون مؤهلًا.
* تكون الوجهة دالة جدول، أو تستخدم محرك جدول بعيدًا مثل `Distributed`.
* يقرأ `SELECT` من جدول الوجهة نفسه (`INSERT INTO t SELECT ... FROM t`).
* يتعيّن على `insert_null_as_default` استبدال قيمة `NULL` بقيمة افتراضية عند تمرير عمود من النوع `Nullable` في `SELECT` إلى عمود هدف من نوع غير `Nullable`.
* يكون الإدراج داخليًا (تحديث عرض مُجسَّد قابل للتحديث، أو `POPULATE`، أو `CREATE TABLE ... AS SELECT`). وتكون هذه العمليات متزامنة دائمًا، وتتجاهل `async_insert_select_as_async_insert` و`async_insert`.

تختلف المعالجة في حالة المعاملات. فعندما يُنفَّذ الاستعلام داخل معاملة (سواء كانت صريحة أو مع `implicit_transaction = 1`)، لا يكون المسار غير المتزامن مدعومًا، ويرفع ClickHouse افتراضيًا الاستثناء `NOT_IMPLEMENTED` بدلًا من التحوّل إلى المسار المتزامن. ولا يتحوّل الاستعلام إلى الإدراج المتزامن إلا عند ضبط `throw_on_unsupported_query_inside_transaction = 0`.

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

<h2 id="return-mode-and-waiting">
  وضع الإرجاع والانتظار
</h2>

يتصرف `wait_for_async_insert` كما في أي عملية إدراج غير متزامنة: تنتظر القيمة `1` (الافتراضية) اكتمال التفريغ؛ أما القيمة `0` فتتيح العودة فور إضافة الكتلة إلى قائمة الانتظار.

لمساعدة استعلام `SELECT` على إنتاج الكتلة الواحدة التي يتطلبها المسار غير المتزامن، يحدّ [`optimize_trivial_insert_select`](/ar/reference/settings/session-settings/optimize-trivial#optimize_trivial_insert_select) استعلامًا بسيطًا من نمط `INSERT INTO dest SELECT ... FROM source` بين جدولين مختلفين بما لا يتجاوز [`max_insert_threads`](/ar/reference/settings/session-settings/max-insert#max_insert_threads) من خيوط القراءة. اضبط `max_insert_threads = 1`، وعندها ينتج استعلام `SELECT` عادةً كتلة واحدة.

<h2 id="write-accounting-and-observability">
  احتساب عمليات الكتابة وإمكانية المراقبة
</h2>

تُنسَب عمليات الكتابة إلى استعلام التفريغ، لا إلى استعلام `INSERT ... SELECT` الأصلي:

* تُنسَب أحداث الكتابة في `ProfileEvents` ‏(`InsertedRows`، `InsertedBytes`) إلى استعلام التفريغ، ويكون له صف مستقل لعمليات الكتابة في `system.query_log`. أما صف استعلام `INSERT ... SELECT` الأصلي، فتظهر فيه القيمة `0` لهذين الحدثين في `ProfileEvents`. للاطلاع على أرقام الكتابة الخاصة بالتفريغ، راجع صف استعلام التفريغ في `system.query_log` و`system.asynchronous_insert_log`.
* عند ضبط `wait_for_async_insert = 1` (الإعداد الافتراضي)، تعرض قيمتا `written_rows` و`written_bytes` الخاصتان بالاستعلام (وكذلك ترويسة HTTP ‏`X-ClickHouse-Summary`) عدد الصفوف والبايتات المقبولة من `SELECT`، لا إجمالي ما كتبه استعلام التفريغ. وإذا فشل التفريغ، يُبلَّغ العميل بالخطأ.
* عند ضبط `wait_for_async_insert = 0`، لا تُعرض هذه الأرقام، لأن الاستعلام يعيد نتيجته قبل توفّر نتيجة التفريغ.
* تُحتسَب حصة `WRITTEN_BYTES` مرة واحدة أثناء التفريغ، ولا يُلغى احتسابها إذا فشل التفريغ.

<h2 id="cancellation-and-timeouts">
  الإلغاء وانتهاء المهلة
</h2>

تُضاف الكتلة إلى قائمة الانتظار قبل بدء انتظار تفريغها، لذا فإن إلغاء الاستعلام ينهي انتظار العميل، لكنه لا يمنع تفريغ قائمة الانتظار.

* يُرجع `KILL QUERY`، أو بلوغ `max_execution_time` أثناء الانتظار، رسالة خطأ إلى العميل، لكن قد تُكتب الصفوف رغم ذلك. لا تعتبر إلغاء استعلام أو انتهاء مهلته على هذا المسار دليلًا على عدم كتابة أي صفوف.
* مع `timeout_overflow_mode = 'break'`، لا يحدث خطأ ولا ينتهي الاستعلام مبكرًا: يواصل الاستعلام انتظار التفريغ بعد تجاوز `max_execution_time`، حتى `wait_for_async_insert_timeout`. فالانتهاء مبكرًا سيُشير إلى نجاح العملية قبل تأكيد الكتابة.

<h2 id="when-decisions-are-bound">
  متى تُحسم القرارات
</h2>

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

ويُبحث عن الوجهة ويُتحقَّق من الأذونات عند الربط وقت التفريغ، كما يحدث مع [أي عملية إدراج غير متزامنة](/optimize/asynchronous-inserts): فإذا أُرفق عرض مُجسَّد بالوجهة أو أُلغيت أذونات بعد وضع العملية في قائمة الانتظار وقبل تفريغها، فإن ذلك يؤثر في عملية التفريغ.
