INSERT ... VALUES العادي، بل يمكن لـ INSERT ... SELECT أيضًا أن يسلكه. توضّح هذه الصفحة متى يحدث ذلك، وكيف يُحتسب جانب الكتابة، وما الذي يحدث عند إلغاء الاستعلام أو انتهاء مهلته.
الأهلية وتوجيه المسار
يسلك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 ويُدرج في جدول متماثل يسلك مسار الإدراج الموزّع، ولا يصل أبدًا إلى قائمة الانتظار غير المتزامنة. وينطبق الأمر نفسه على النسخ المتماثلة المتوازية.
وضع الإرجاع والانتظار
يتصرفwait_for_async_insert كما في أي عملية إدراج غير متزامنة: تنتظر القيمة 1 (الافتراضية) اكتمال التفريغ؛ أما القيمة 0 فتتيح العودة فور إضافة الكتلة إلى قائمة الانتظار.
لمساعدة استعلام SELECT على إنتاج الكتلة الواحدة التي يتطلبها المسار غير المتزامن، يحدّ optimize_trivial_insert_select استعلامًا بسيطًا من نمط INSERT INTO dest SELECT ... FROM source بين جدولين مختلفين بما لا يتجاوز max_insert_threads من خيوط القراءة. اضبط max_insert_threads = 1، وعندها ينتج استعلام SELECT عادةً كتلة واحدة.
احتساب عمليات الكتابة وإمكانية المراقبة
تُنسَب عمليات الكتابة إلى استعلام التفريغ، لا إلى استعلام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مرة واحدة أثناء التفريغ، ولا يُلغى احتسابها إذا فشل التفريغ.
الإلغاء وانتهاء المهلة
تُضاف الكتلة إلى قائمة الانتظار قبل بدء انتظار تفريغها، لذا فإن إلغاء الاستعلام ينهي انتظار العميل، لكنه لا يمنع تفريغ قائمة الانتظار.- يُرجع
KILL QUERY، أو بلوغmax_execution_timeأثناء الانتظار، رسالة خطأ إلى العميل، لكن قد تُكتب الصفوف رغم ذلك. لا تعتبر إلغاء استعلام أو انتهاء مهلته على هذا المسار دليلًا على عدم كتابة أي صفوف. - مع
timeout_overflow_mode = 'break'، لا يحدث خطأ ولا ينتهي الاستعلام مبكرًا: يواصل الاستعلام انتظار التفريغ بعد تجاوزmax_execution_time، حتىwait_for_async_insert_timeout. فالانتهاء مبكرًا سيُشير إلى نجاح العملية قبل تأكيد الكتابة.
متى تُحسم القرارات
تُحدَّد أهلية استخدام المسار غير المتزامن مرة واحدة عند بدء الاستعلام، قبل وضع الكتلة في قائمة الانتظار. ويتيح التحقق المسبق من أذونات الوصول رفض عمليات الإدراج غير المصرّح بها مبكرًا. أما سلوكINSERT ... SELECT المسار غير المتزامن أصلًا، فيعتمد على بنية الكتلة الناتجة، لا على async_insert وحده.
ويُبحث عن الوجهة ويُتحقَّق من الأذونات عند الربط وقت التفريغ، كما يحدث مع أي عملية إدراج غير متزامنة: فإذا أُرفق عرض مُجسَّد بالوجهة أو أُلغيت أذونات بعد وضع العملية في قائمة الانتظار وقبل تفريغها، فإن ذلك يؤثر في عملية التفريغ.