الحالة التجريبية
تُصدر واجهات العميل الرئيسي ومصدر البيانات وsession والعمليات، إلى جانب امتدادات حقن التبعيات، تحذير المصرّفCHTCP0001. للإقرار بهذا التحذير أثناء تقييم واجهة برمجة التطبيقات، أضفه
إلى NoWarn في ملف مشروعك:
إصدارات .NET المدعومة
يدعم العميل الذي يعمل عبر البروتوكول الأصلي إصدارات .NET التالية:- .NET 8.0
- .NET 9.0
- .NET 10.0
إصدارات ClickHouse المدعومة
يدعم عميل TCP رسميًا أحدث إصدارين من إصدارات الدعم طويل الأمد (LTS)، وأحدث ثلاثة إصدارات من خادم ClickHouse.التثبيت
يتوفر عميل البروتوكول الأصلي عبر TCP ضمن حزمةClickHouse.Driver. ثبّت الحزمة من NuGet:
البدء السريع
الترحيل من عميل HTTP
واجهة برمجة تطبيقات TCP مستقلة عنIClickHouseClient؛ فهي ليست خيارًا لوسيلة النقل في
ClickHouseClient أو ClickHouseConnection. يمكن إعادة استخدام معظم شيفرات SQL، لكن عليك إنشاء
ClickHouseTcpClient وترحيل كل عملية إلى نظيرتها عبر TCP.
الطرق المكافئة
على سبيل المثال، حلقة قارئ HTTP:
الخيارات والمعلمات
لا يمكن استخدامQueryOptions وClickHouseParameterCollection الخاصّين بـ HTTP بالتبادل مع نظيريهما في TCP.
انقل القيم إلى ClickHouseTcpQueryOptions، حيث تكون الإعدادات سلاسل نصية
وتكون المعلمات جزءًا من كائن الخيارات نفسه:
{name:Type}، لكنه لا يعيد كتابة
العناصر النائبة بنمط ADO.NET مثل @name. كما أنه لا يتيح تحديد قاعدة بيانات أو دور أو رمز Bearer أو ترويسة
مخصصة أو محلّل معلمات أو منسّق أو محوّل قراءة على مستوى كل استعلام. راجع القيود للاطلاع على
الميزات التي لا تزال مقتصرة على HTTP.
دورة حياة الاتصال والنتيجة
كلا العميلين عاليَي المستوى آمن للاستخدام عبر خيوط تنفيذ متعددة، وينبغي إعادة استخدامهما. يحتفظ عميل TCP باتصالات أصلية دائمة بدلًا من اتصالات HTTP، وينفّذIAsyncDisposable، وينبغي عادةً
التخلّص منه بصورة غير متزامنة عند إيقاف تشغيل التطبيق.
صفوف QueryAsync مملوكة للجهة المستدعية. أما كتل StreamAsync وأعمدتها فهي مُعارة، ولا تبقى صالحة
إلا خلال التكرار الحالي؛ انسخ أي قيم تحتاج إليها بعد انتهائه. احرص دائمًا على إكمال التعداد أو التخلّص منه
ليعود الاتصال إلى مجمّع الاتصالات. استخدم OpenSessionAsync عندما يلزم تنفيذ عدة عمليات
على الاتصال نفسه مع الاحتفاظ بحالة session.
راجع
المثال الكامل للترحيل من HTTP إلى TCP
للاطلاع على استخدام كلا العميلين مع الجدول نفسه.
التهيئة
يمكن تهيئة عميل يستخدم البروتوكول الأصلي عبر TCP بطريقتين:- سلسلة الاتصال: أزواج مفاتيح وقيم تفصل بينها فواصل منقوطة، تحدد نقطة نهاية الخادم، وبيانات اعتماد المصادقة، وخيارات الاتصال الأخرى.
- كائن
ClickHouseTcpClientOptions: كائن تهيئة محدد الأنواع وغير قابل للتغيير، يُعرَّف في الشيفرة.
ClickHouseTcpClient. استخدم
ClickHouseTcpConnectionStringBuilder لتحليل سلسلة اتصال أو إنشائها وتحويلها إلى
ClickHouseTcpClientOptions.
إعدادات الاتصال
تُحدَّد قيم خصائصTimeSpan في سلسلة الاتصال بالثواني.
صيغة البيانات والتسلسل
تجميع الاتصالات
ينفّذ الاتصال الواحد عملية واحدة في كل مرة. ويتيح مجمّع الاتصالات تشغيل العمليات بشكل متزامن، مع إعادة استخدام الاتصالات فيما بينها.الأمان
للبروتوكول الأصلي الآمن نقطة نهاية منفصلة على الخادم، ولا يُفعَّل بترقية الاتصال القائم. يجب على عميل TLS
الاتصال بمنفذ آمن للبروتوكول الأصلي؛ ولا يتحول تلقائيًا إلى اتصال بنص صريح. يُطبَّق
ConfigureTls
أخيرًا، ويمكنه تجاوز التحقق من صلاحية الشهادة واسم المضيف، لذا راجع دوال رد الاتصال المخصصة
بعناية.
التسجيل وتصحيح الأخطاء
يسجّل مسجّل العميل أحداث دورة الحياة والعمليات من جهة العميل. أما حزم سجل الخادم فتُرسل
إلى
ClickHouseTcpQueryCallbacks.OnLog بدلًا من ذلك. قد يحتوي نص العبارة على بيانات حساسة، لذا لا يُضاف
إلى وسوم النشاط افتراضيًا، ويُقتطع معظمه في سجلات تصحيح الأخطاء.
إعدادات مخصصة
تُطبّقClickHouseTcpClientOptions.CustomSettings إعدادات خادم ClickHouse على كل استعلام وعملية
إدراج. وتحلّ قيم ClickHouseTcpQueryOptions.Settings المحددة لكل عملية محلّ القيم المحددة على مستوى العميل إذا كانت
تحمل الاسم نفسه.
set_ إلى بداية كل إعداد من إعدادات الخادم:
set_ عند إضافة إعداد إلى CustomSettings أو إلى
Settings الخاصة بكل عملية.
ClickHouseTcpQueryOptions
تحدّدClickHouseTcpQueryOptions إعدادات خاصة بكل عملية. جميع الخصائص اختيارية.
ClickHouseTcpInsertOptions
يوسّعClickHouseTcpInsertOptions الصنف ClickHouseTcpQueryOptions بإعدادات خاصة بعمليات الإدراج باستخدام كتل
Native. كما تتوفر فيه جميع خصائص خيارات الاستعلام.
ClickHouseTcpClient
ClickHouseTcpClient هي واجهة برمجة التطبيقات عالية المستوى لبروتوكول TCP الأصلي. تنفّذ عبارات SQL واستعلامات
تُرجع قيمة مفردة، وتُتيح النتائج على شكل كتل منظّمة حسب الأعمدة أو صفوف أو كائنات POCO، وتُدرج بيانات منظّمة حسب الأعمدة أو الصفوف،
وتفتح sessions مرتبطة باتصال ثابت.
يمكن استخدام هذا العميل بأمان من خيوط تنفيذ متعددة، وله مجمّع اتصالات خاص به. أنشئ عميلًا واحدًا لكل نقطة نهاية، وشاركه
بين أجزاء التطبيق، وتخلّص منه عند إيقاف التشغيل. يمكن تنفيذ العمليات بالتزامن حتى الحدّ
MaxPoolSize؛ أما العمليات الإضافية فتنتظر توفر اتصال لمدة لا تتجاوز PoolTimeout.
إنشاء عميل
أنشئ عميلًا من سلسلة اتصال أو منClickHouseTcpClientOptions. راجع
التهيئة لمعرفة الإعدادات المتاحة.
باستخدام سلسلة اتصال:
PoolTimeout حتى تكتمل العمليات الجارية، ثم إيقاف ما لم يكتمل منها.
حقن التبعيات
تسجّلAddClickHouseTcpDataSource مصدر بيانات واحدًا يُعاد استخدام مثيله، وتوفّر عميله المشترك عبر
IClickHouseTcpClient وIClickHouseTcpOperations:
LoggerFactory،
يستخدم التسجيل ILoggerFactory الخاص بالحاوية. ويمكن تسجيل عدة
مصادر بيانات مستقلة باستخدام serviceKey.
تنفيذ الاستعلامات
استخدمExecuteAsync لتنفيذ العبارات التي لا تُرجع صفوفًا، مثل عبارات DDL وعمليات التعديل:
ExecuteAsync ويتجاهلها. عند استخدام
INSERT INTO ... VALUES، استخدم InsertAsync أو InsertRowsAsync وأنهِ عبارة SQL عند
VALUES من دون إدراج قيم مباشرةً فيها.
قراءة البيانات
اختر واجهة برمجة تطبيقات القراءة المناسبة لشكل البيانات الذي يحتاجه التطبيق:قراءة القيم المفردة
تُعيدExecuteScalarAsync قيمة العمود الأول من الصف الأول على هيئة object:
null سواء كانت القيمة الأولى NULL أو كان الاستعلام
لا يُرجع أي صفوف.
قراءة الصفوف
تُمرّرQueryAsync الصفوف تباعًا، كلًّا منها في مصفوفة object[] مستقلة، وتُرتّب القيم فيها بحسب ترتيب أعمدة النتيجة:
قراءة البيانات باستخدام POCO
تُطابِقQueryAsync<T> الأعمدة مع الخصائص العامة التي يمكن تعيين قيم لها. وتُطابَق الأسماء بصرف النظر عن حالة الأحرف أو
الشرطات السفلية؛ استخدم ClickHouseTcpColumn لتحديد اسم صريح، وClickHouseTcpNotMapped لاستبعاد خاصية.
قراءة كتل البيانات المخزّنة بالأعمدة
تتيحStreamAsync الوصول إلى النتيجة بتنسيقها العمودي الأصلي كسلسلة من قيم Block. وهي أسرع طريقة لقراءة البيانات.
أكمل التعداد دائمًا أو حرّر المُعدِّد ليعود اتصاله إلى مجمّع الاتصالات.
Block.Column<T> الوصول إلى نوع CLR الذي تنتجه أداة فك الترميز. استخدم Block.ReadAs<T> أو
واجهة متخصصة مثل IDateTimeColumn عند الحاجة إلى التحويل.
إدراج البيانات
ترسل عمليات الإدراج بالتنسيق الأصلي البيانات في كتل عمودية بصيغة ثنائية. يجب أن تكون عبارة SQL بصيغةINSERT INTO ... VALUES
من دون قائمة قيم مضمّنة. استخدم أعمدة ذات أنواع محددة لتقليل المعالجة على جهة العميل، أو الصيغ التي تقبل الصفوف
وكائنات POCO إذا كانت بيانات التطبيق منظّمة بالفعل حسب الصفوف.
الإدراج حسب الأعمدة
تقبلInsertAsync البيانات المنظَّمة مسبقًا في أعمدة ذات أنواع محددة. وهي أسرع طريقة لإدراج البيانات.
InsertAsync، شريطة أن
تكتمل عملية الإدراج قبل تحرير تلك الكتلة.
إدراج الصفوف
تقبلInsertRowsAsync صفوفًا من النوع object[]. وتقابل القيم الأعمدة في قائمة أعمدة SQL بحسب ترتيبها:
Variant أو Dynamic. لا تعدّل الصفوف قبل اكتمال العملية.
عمليات الإدراج باستخدام POCO
يطابق التحميل الزائد العام للدالةInsertRowsAsync<T> أعمدة الهدف مع الخصائص العامة التي يمكن قراءتها، وفق
قواعد التسمية والسمات نفسها المستخدمة عند قراءة POCO:
ClickHouseTcpNotMapped الخصائص التي يقتصر استخدامها على التطبيق، مثل
ImportBatch، من عملية الربط.
معلمات SQL
يربط العميل الأصلي القيم بالعناصر النائبة{name:Type} الأصلية في ClickHouse. ولا يعيد كتابة
العناصر النائبة @name المستخدمة وفق أسلوب ADO.NET.
ClickHouseTcpParameter.ClickHouseType. استخدم النوع Identifier لأسماء الجداول والأعمدة.
إذا كانت قيمة DateTime أو DateTimeOffset تمثّل لحظة زمنية محددة، فأدرج منطقة زمنية مثل
{timestamp:DateTime('UTC')}؛ وإلا فقد يتغيّر معنى القيمة بحسب المنطقة الزمنية لـsession الخادم.
معرّف الاستعلام
لكل عملية معرّف استعلام تستخدمه جداول النظام في ClickHouse وسجلات العميل ووحدات span للتتبّع. إذا كانت قيمةQueryId تساوي null أو كانت فارغة، ينشئ العميل معرّف GUID جديدًا. حدّد قيمته إذا كان لا بد من ربط العملية
بمعرّف التطبيق:
تقدّم الاستعلام والبيانات الوصفية
اضبطClickHouseTcpQueryOptions.Callbacks لتلقّي البيانات الوصفية أثناء تلقّي الاستجابة:
OnLog وOnProfileEvents وOnTotals وOnExtremes مستعارة، ويجب ألّا يُحتفظ بها خارج
دالة الاستدعاء الراجع.
لا يرسل ClickHouse حزم تقدّم الاستعلام للصفوف التي تُحمَّل أثناء الإدراج. استخدم
OnBlockWritten لمراقبة الكتل التي يرسلها العميل؛ فهو يُبلّغ عن تقدّم النقل، لا عن
تثبيت الخادم لعملية الإدراج.
الإلغاء
تقبل كل عمليةCancellationToken:
معلومات الخادم وفحوصات حالته
تُعيدGetServerInfoAsync هوية الخادم وإصداره ومنطقته الزمنية ومعلومات البروتوكول التي جرى التفاوض عليها
أثناء مصافحة الاتصال وفق البروتوكول الأصلي:
ProtocolRevision، وهو رقم المراجعة الذي يتفق عليه العميل
والخادم. واربط إتاحة ميزات SQL، مثل أنواع البيانات والدوال، بـVersion. تستخدم الطريقة اتصالًا قائمًا
إذا توفر، وتفتح اتصالًا جديدًا إذا كان مجمّع الاتصالات فارغًا.
استخدم PingAsync للتحقق من الجاهزية عبر البروتوكول الأصلي:
مزيد من الأمثلة
للاطلاع على أمثلة مكتملة وجاهزة للتشغيل تشمل قراءة البيانات، وإدراجها، وأنواع البيانات، والجلسات، وTLS، وإمكانية المراقبة، ومعالجة الأخطاء، راجع أمثلة البروتوكول الأصلي في مستودع GitHub.sessions
تستعير عمليات العميل المعتادة أي اتصال متاح من مجمّع الاتصالات، لذا فإن الحالة الخاصة بالاتصال ليست معزولة، ولا يُضمن بقاؤها بين الاستدعاءات. وقد تتصل اتصالات مختلفة من المجمّع بخوادم مختلفة. افتح session إذا كان لا بد للجداول المؤقتة أو عباراتSET أو أي سلسلة أخرى من العمليات من استخدام اتصال واحد.
IClickHouseTcpSession واجهات برمجة التطبيقات نفسها التي يتيحها العميل للاستعلام والتنفيذ والإدراج واختبار الاتصال والحصول على معلومات الخادم.
ولا تدعم الـsession الاستخدام المتزامن عبر خيوط تنفيذ متعددة. وتُنفَّذ عملياتها بالتتابع: يُرفض بدء عملية جديدة قبل
انتهاء العملية الحالية. وتظل الـsession مشغولة بنتيجة تُقرأ تدريجيًا حتى يكتمل تعداد عناصر النتيجة أو يُتخلّص من
كائن المُعدِّد الخاص بها.
تشغل كل session خانة واحدة من MaxPoolSize طوال فترة وجودها. ويمكن للعميل مواصلة استخدام اتصالات أخرى من
مجمّع الاتصالات، لكن إذا لم يضمّ المجمّع سوى اتصال واحد، تنتظر عمليات العميل الأخرى
حتى يُتخلّص من الـsession أو تنقضي المهلة المحددة في PoolTimeout.
تخلّص من الـsession قبل التخلّص من العميل التابع له. ويؤدي التخلّص منها إلى إغلاق
الاتصال المخصّص لها بدلًا من إعادته إلى المجمّع، ما يمنع الجهات التي تستخدمه لاحقًا من وراثة
جداولها المؤقتة أو إعداداتها. وقد تصبح الـsession غير قابلة للاستخدام بسبب فشل الاتصال أو البروتوكول، أو الإلغاء، أو عدم اكتمال
دفق النتائج؛ وعندما تصبح قيمة IsOpen هي false، افتح session جديدة.
أفضل الممارسات
عمر العميل وتجميع الاتصالات
أنشئ مثيلًا واحدًا منClickHouseTcpClient أو ClickHouseTcpDataSource لكل نقطة نهاية
وتهيئة مميزتين، وأعد استخدامه طوال عمر التطبيق. يمكن استخدام العميل بأمان عبر خيوط تنفيذ متعددة، وهو يدير
مجمّع اتصالاته؛ أما إنشاء عميل لكل عملية فينشئ مجمّعًا جديدًا في كل مرة ويحول دون إعادة استخدام الاتصالات.
في التطبيقات التي تستخدم حقن التبعيات، سجّل AddClickHouseTcpDataSource مرة واحدة واحقن
IClickHouseTcpClient. يتولى موفّر الخدمات إدارة عمر العميل، لذا يجب ألا تتخلص المكوّنات التي تستخدمه من المثيل
المحقون. أما خارج نطاق حقن التبعيات، فتخلّص من العميل عند إيقاف التطبيق باستخدام await using.
يعالج كل اتصال عبر البروتوكول الأصلي عملية واحدة في كل مرة. لذلك، يحدّ MaxPoolSize من عدد الاتصالات المفتوحة
والعمليات المتزامنة معًا؛ وينتظر المستدعون الآخرون توفّر خانة شاغرة لمدة تصل إلى PoolTimeout.
اختر قيمة تستوعب التزامن الفعلي في التطبيق دون تجاوز حدود الاتصالات والاستعلامات على جانب الخادم.
زيادة هذه القيمة لا تسرّع الاستعلام الواحد.
ضع في اعتبارك كيفية استخدام المكوّنات التالية لمجمّع الاتصالات:
- تحتفظ النتيجة التي تُقرأ تدريجيًا باتصالها حتى يُتخلَّص من معدِّدها.
- تحتفظ session باتصال واحد طوال عمرها، ولا تقبل إلا عملية واحدة في كل مرة.
- يؤدي ترك نتيجة دون إكمال قراءتها، أو إلغاء عملية قيد التنفيذ، أو حدوث فشل في البروتوكول أو الاتصال، إلى إغلاق الاتصال بدلًا من إعادة استخدامه.
ClickHouse.Driver.Tcp.Pool لتشخيص استنفاد مجمّع الاتصالات،
أو إغلاق الاتصالات على نحو غير متوقع، أو تكرار إنشاء اتصالات جديدة.
المهلات الزمنية والإلغاء
يحدد عميل TCP مهلة مستقلة لكل نوع من الانتظار:
قد تستغرق عملية الحصول على اتصال من المجمّع، إذا انتظرت توفر خانة أولًا ثم أنشأت اتصالًا، ما يصل إلى
PoolTimeout + DialTimeout. تُحتسب مهلة ReadTimeout من جديد مع كل قراءة عبر طبقة النقل، لذا قد يستمر استعلام طويل
يتواصل خلاله إرسال معلومات التقدم أو البيانات مدةً تتجاوز هذه القيمة. اضبطها على قيمة تكفي لتغطية
فترات صمت الخادم المتوقعة؛ ولا تضبطها على TimeSpan.Zero إلا إذا كانت مهلة أخرى تقيّد مدة
العملية على نحو موثوق.
استخدم رمز إلغاء عندما تحتاج إلى مهلة تشمل العملية من بدايتها إلى نهايتها:
التعامل مع التاريخ والوقت
يُفضّل استخدامDateTime('UTC') أو DateTime64(S, 'UTC') للطوابع الزمنية، واستخدام DateTimeOffset أو
DateTime بقيمة Kind تساوي Utc في شيفرة التطبيق. فهذا يحدّد اللحظة الزمنية المقصودة بوضوح
ويجنّب الاعتماد على المنطقة الزمنية للخادم أو الـsession.
يطبّق عميل TCP القواعد التالية عند كتابة قيم DateTime:
يُرفَض الوقت غير المحدّد الذي يُتخطّى عند الانتقال إلى التوقيت الصيفي لأنه لا يقابل أي
لحظة زمنية. أما الوقت الملتبس عند العودة إلى التوقيت السابق، فيُختار ظهوره الأول. استخدم
DateTimeOffset عندما
يجب تحديد الاختيار صراحةً.
عند استخدام معلمات SQL لتمثيل لحظة زمنية، أدرج المنطقة الزمنية في العنصر النائب:
DateTime وDateTime64 أعدادهما الخام من نوع uint أو long افتراضيًا.
استخدم Block.ReadAs<DateTimeOffset> أو IDateTimeColumn.GetDateTimeOffset أو خاصية POCO مطابقة
إذا كان التعامل مع قيمة تقويمية أنسب. واحتفظ بالعدد الخام عندما تكون كل خانة مهمة:
تبلغ أصغر وحدة زمنية في DateTimeOffset مقدار 100 نانوثانية، لذا فإن قراءة DateTime64 بمقياس 8 أو 9 من خلاله
تؤدي إلى فقدان الدقة دون تلك الوحدة.
استخدم DateOnly مع Date وDate32. واستخدم TimeSpan مع قيم Time وTime64 التي قد تكون
سالبة أو تتجاوز 24 ساعة؛ ولا يكون TimeOnly مناسبًا إلا إذا كانت قيم العمود تقتصر على
وقت من اليوم.
البث وعمر النتائج
استخدمStreamAsync والأعمدة محددة الأنواع لمعالجة البيانات بمعدل نقل مرتفع. يتماشى ذلك مع تنظيم البيانات
حسب الأعمدة في ClickHouse، ويجنّب إنشاء مصفوفات لكل صف وتغليف القيم وتخصيص كائنات POCO. استخدم QueryAsync<T> عندما تكون
الحاجة إلى نموذج يمتلكه التطبيق أهم من تقليل عمليات تخصيص الذاكرة إلى أدنى حد، واستخدم الإصدار غير محدد النوع
QueryAsync فقط عندما لا يكون المخطط معروفًا وقت التصريف.
الكتل التي يعيدها StreamAsync مستعارة. لا تبقى الكتلة وأعمدتها وأعمدتها الفرعية المركّبة وجميع
وحدات span صالحة إلا أثناء التكرار الحالي للحلقة. عالجها في موضعها أو انسخ القيم التي
يجب الاحتفاظ بها بعد انتهاء التكرار:
await foreach مهمة تحرير المُعدِّد. إذا كنت تحتاج إلى جزء فقط من
النتيجة، فحدّد ذلك في SQL باستخدام LIMIT، واختر الأعمدة المطلوبة فقط. يؤدي التوقف
مبكرًا إلى إلغاء بقية الاستجابة، ويمنع إعادة استخدام ذلك الاتصال.
بنية عملية الإدراج وتجميع الدُفعات
فضّل استخدامInsertAsync مع الأعمدة محددة الأنواع إذا كانت البيانات منظّمة في أعمدة أصلًا، فهو يتطلب أقل قدر من
التحويل من جهة العميل. ويُعدّ InsertRowsAsync<T> الخيار الأنسب لبيانات POCO؛ أما صفوف object[] غير محددة الأنواع
فهي الأكثر مرونة، لكنها تنشئ مصفوفات وتغلّف أنواع القيم.
أرسل عددًا كافيًا من الصفوف في كل استدعاء إدراج بدلًا من تنفيذ عمليات إدراج صغيرة كثيرة. وضمن الاستدعاء الواحد،
يقسّم MaxRowsPerBlock البيانات إلى كتل بصيغة النقل الأصلية. كما تضع قيمته الافتراضية، البالغة 50,000 صف، حدًا
لحجم مخازن الأعمدة المؤقتة المستخدمة عند تحويل مدخلات الصفوف وPOCO. وقد تؤدي زيادة هذه القيمة إلى
تحسين معدل النقل للصفوف قليلة الأعمدة، لكنها ترفع ذروة استهلاك الذاكرة؛ أما ضبطها على null فيؤدي إلى كتابة عملية
الإدراج كاملةً في كتلة واحدة وتحويل جميع المدخلات المنظّمة في صفوف لتلك الكتلة معًا.
يحدّ MaxSendBufferBytes، على نحو مستقل، من كمية البيانات المُرمَّزة المخزّنة مؤقتًا قبل تفريغها إلى
المقبس. وهو حدّ مرن يُفحَص بين الأعمدة، لذا يمكن أن يتجاوزه عمود عريض واحد.
تُحوَّل مدخلات الصفوف وPOCO كتلةً تلو الأخرى. لذا قد لا تُكتشف قيمة غير صالحة في كتلة لاحقة
إلا بعد إرسال الكتل السابقة. تحقّق من السماح بالقيم الفارغة ومن أنواع CLR قبل
الإدراج إذا لم تكن جودة البيانات مضمونة، واضبط DeduplicationToken على قيمة مشتقة من البيانات كلما
كان من الممكن إعادة محاولة إدراج الدفعة المنطقية.
أنواع البيانات المدعومة
توضّح الجداول أدناه الفرق بين النوع الذي يعيدهIColumn<T> مفكك الترميز والأنواع الإضافية
المتاحة بالتحويل عبر Block.ReadAs<T>، أو بربط كائنات POCO عبر QueryAsync<T>، أو بعمليات الإدراج. ويمكنك الاستعلام من
محلّل الربط نفسه الذي تستخدمه هذه العمليات عمّا إذا كان ربط معيّن مدعومًا:
Nullable وArray وTuple وMap وLowCardinality تعاوديًا على
الأنواع الداخلية لكلٍّ منها.
مطابقة الأنواع: القراءة من ClickHouse
يشيرDefault .NET type إلى النوع T الذي تتيحه Block.Column<T> وIColumn<T>. ويمكن قراءة الأنواع المدرجة في العمود
Also readable as باستخدام Block.ReadAs<T> وخصائص POCO.
أنواع الأعداد الصحيحة
أنواع الأعداد ذات الفاصلة العائمة
الأنواع العشرية
يخزّن
ClickHouseTcpDecimal الجزء الدالّ بوصفه عددًا صحيحًا بأي حجم، إلى جانب مقياسه، مما يتيح الاحتفاظ بالقيم
التي تتجاوز دقتها النطاق الذي يدعمه decimal.
النوع المنطقي
أنواع String
استخدم
IStringColumn.GetBytes(row) أو اقرأ البيانات بالنوع byte[] إذا كانت قد لا تكون بترميز UTF-8 صالح.
يحتفظ FixedString(N) بجميع البايتات الـN، بما فيها البايتات الصفرية في نهايتها.
أنواع التاريخ والوقت
التمثيل الافتراضي هو العدد الصحيح الخام، حتى تحتفظ القراءة العمودية بالقيمة كما تُنقل تمامًا. وتستخدم
التحويلات إلى قيم التاريخ والوقت المنطقة الزمنية المحددة في النوع، أو المنطقة الزمنية للجلسة إذا لم يحدد النوع
منطقة زمنية. ترفع قراءة
Time أو Time64 بوصفه TimeOnly استثناءً إذا كانت القيمة سالبة أو بلغت
24 ساعة فأكثر؛ استخدم TimeSpan لتمثيل نطاق قيم ClickHouse كاملًا.
أنواع التعداد
تُتيح
IEnumColumn أيضًا الاطلاع على الربط المُعلَن بين تسميات التعداد وقيمها الرقمية.
أنواع قياسية أخرى
الأنواع المركبة
يمكن أن تضمّ المجموعات المرتبة ما يصل إلى سبعة عناصر. لا يتقيّد عمود
Nested بعدد محدد من العناصر، ويُفضّل قراءته
عبر INestedColumn، الذي يتيح الوصول إلى أعمدة الحقول المسطّحة المسماة وإزاحات الصفوف المشتركة دون
تخصيص سجلات مغلّفة. ومع الإعداد الافتراضي flatten_nested = 1 في ClickHouse، تصل الحقول المتداخلة بدلًا من ذلك
في أعمدة Array(T) منفصلة، تتضمن أسماؤها نقاطًا.
أنواع Variant وDynamic وJSON
تُرجع
Variant وDynamic قيمة CLR للنوع المختار في كل صف، أو null. وتُتيح عروضهما
العمودية الوصول إلى دفق المميّز وعمود فرعي محدد النوع لكل نوع أثناء التنفيذ، مما يغني عن
تغليف القيم عند معالجة البيانات عموديًا.
يقرأ عميل TCP بيانات JSON عبر آلية تسلسل String في ClickHouse. ويُفعّل العميل الإعداد
output_format_native_write_json_as_string = 1 افتراضيًا؛ وتعطيله يجعل قراءة JSON
غير مدعومة. يحلّل ClickHouse بيانات JSON ويوحّد صيغتها، لذا قد يختلف النص الناتج عن النص المُدرج
في ترتيب المفاتيح والمسافات البيضاء وصيغة الأرقام.
الأنواع الهندسية
يُقدَّم
Geometry في صورة IVariantColumn يشمل الأنواع الهندسية الستة.
نوع QBit
يدعم عميل TCP صيغة
QBit(T, N) ذات الوسيطين، من دون stride. أما تخطيط
التخزين ذو الوسائط الثلاثة الذي يستخدم stride فغير مدعوم.
أنواع AggregateFunction
يحتوي العمود من نوع
AggregateFunction على حالة وسيطة خاصة بالدالة. استخرج قيمتها النهائية على
الخادم، مثلًا باستخدام sumMerge(column)، ثم اقرأ القيمة الناتجة بدلًا من الحالة الوسيطة.
مطابقة الأنواع: الكتابة إلى ClickHouse
يمثّل كل إدخال نوع CLR لصف واحد ضمنIColumn المُمرَّر إلى InsertAsync. وهذه المطابقات
دقيقة تمامًا: لا يُجري عميل TCP تحويلات ضمنية على غرار Convert.
أنواع الأعداد الصحيحة
أنواع الأعداد ذات الفاصلة العائمة
عند كتابة
BFloat16، تُقتطع كل قيمة float لتلائم تمثيل Brain Floating Point ذي 16 بت.
الأنواع العشرية
ترفع عملية الكتابة استثناء
OverflowException إذا تجاوز الجزء الدالّ من العدد، بعد تطبيق المقياس، الدقة المعلنة.
النوع المنطقي
أنواع String
لا يقبل
FixedString(N) النوع string عمدًا؛ لذا رمِّز القيمة وأكملها بحشو مناسب صراحةً حتى يكون
تمثيلها الثنائي المحدد واضحًا بلا لبس.
أنواع التاريخ والوقت
تُفسَّر الأعداد الصحيحة الأولية وفق الوحدات الموضحة في جدول القراءة. يحافظ
DateTimeOffset على اللحظة الزمنية نفسها.
ويُفسَّر DateTime بحسب قيمة Kind الخاصة به؛ فإذا كانت القيمة Unspecified، فتُفسَّر على أنها الوقت المحلي بحسب المنطقة الزمنية
للعمود، أو بحسب المنطقة الزمنية للجلسة إذا لم يحدد العمود منطقة زمنية.
أنواع التعداد
تُرفض التسميات غير المعروفة قبل إرسال البيانات.
أنواع البيانات القياسية الأخرى
الأنواع المركبة
البنية المقبولة تعاودية، لذا يقبلArray(Nullable(DateTime)) قيمة من النوع DateTime?[] لكل
صف، ويقبل Map(String, UInt32) قيمة من النوع KeyValuePair<string, uint>[].
تستخدم الكتابة المباشرة إلى
Nested بنية الأعمدة الكثيفة الناتجة عن قراءة سابقة. أما عند إنشاء عمليات الإدراج
في التطبيق، فاحتفظ بالتمثيل الافتراضي flatten_nested = 1، واكتب كل حقل Array(T) يتضمن اسمه نقطةً
كعمود مستقل.
أنواع Variant وDynamic وJSON
في
Variant، يجب أن يطابق نوع القيمة وقت التشغيل نوع CLR الافتراضي لأحد الأنواع البديلة دون لبس. ولا تُستخدم داخل النوع البديل
تعيينات تسهيلية، مثل كتابة قيمة DateTime إلى بديل من نوع DateTime؛
بل استخدم النوع الخام الافتراضي لذلك البديل. يدعم Dynamic القيم المفردة وقيم
المصفوفات والخرائط والصفوف التي تدعمها البنية تعاوديًا.
الأنواع الهندسية
في عمود
Geometry يُنشئه التطبيق، لا يكون شكل CLR مميزًا إلا لـPoint وMultiPolygon.
فكلٌّ من Ring وLineString له الشكل نفسه، وكذلك Polygon وMultiLineString، لذا لا يستطيع العميل
استنتاج النوع الذي تمثّله قيمة object. أما عمود Geometry بعد فك ترميزه، فيحتفظ
بمميّزات أنواعه ويمكن إعادة إدراجه دون هذا الالتباس.
نوع QBit
أنواع AggregateFunction
الضغط
يُفعّل العميل الضغط افتراضيًا ويستخدم LZ4 لضغط الكتل التي يكتبها؛ ويستخدم ClickHouse أيضًا LZ4 افتراضيًا لكتل الاستجابة. يُطبَّق الضغط على كتل النتائج والكتل التي تُحمَّل أثناء عمليات الإدراج، بينما يحتفظ نص الاستعلام ومعلومات التقدّم والاستثناءات وحزم البروتوكول الأخرى بترميزها المعتاد أثناء النقل. استخدم مفتاحCompression في سلسلة الاتصال لاختيار المرمِّز الذي يستخدمه العميل:
IClickHouseCompressor:
Compressor = null لتعطيل الضغط. يجب أن يدعم الضاغط المخصّص تأطير الكتل الأصلي؛
وتُرفض الضواغط التي لا تدعم سوى متون HTTP عند إنشاء العميل.
اختيار مرمِّز الاستجابة
يحدّدCompressor كيفية ضغط الكتل التي يكتبها العميل. تطلب حزمة الاستعلام بالتنسيق الأصلي
من الخادم ضغط الاستجابة، لكنها لا تحدّد مرمِّزًا بعينه؛ لذلك يختار ClickHouse مرمِّز الاستجابة
وفقًا لإعداد network_compression_method. LZ4 هو المرمِّز الافتراضي للخادم.
حدّد مرمِّز الاستجابة لكل عملية عند الحاجة:
معالجة الأخطاء
تُمثَّل حالات الفشل التي يُبلغ عنها ClickHouse أو الاتصال الأصلي باستثناءات ترث منClickHouseTcpException،
الذي يرث بدوره من DbException:
يوفّر
ClickHouseTcpServerException الخاصيتين RawCode، التي تحتوي على الرمز الرقمي كما أرسله الخادم،
وCode، التي تحتوي على قيمة ClickHouseErrorCode المقابلة إذا كان المشغّل يعرّفها. ويتضمّن أيضًا
اسم استثناء الخادم في Name، وتتبع مكدسه في ServerStackTrace، وأي استثناءات متداخلة من الخادم عبر
InnerException.
ClickHouseErrorCode تحمل القيمة Code == ClickHouseErrorCode.Unknown؛ لذا افحص
RawCode ولا تفترض أن التعداد يشمل جميع رموز error في ClickHouse.
تحتفظ أخطاء التحقق من الوسائط وأخطاء دورة حياة الكائنات بأنواع الاستثناءات المعتادة في .NET.
يؤدي الإلغاء إلى إطلاق OperationCanceledException. ويؤدي DialTimeout وReadTimeout إلى إطلاق
ClickHouseTcpConnectionException يتضمن استثناءً داخليًا من نوع TimeoutException، ويُستبعَد الاتصال.
أما PoolTimeout فيؤدي إلى إطلاق TimeoutException عادي، وليس ClickHouseTcpException: إذ لم يفشل أي اتصال،
والحل هو تقليل العمليات المتزامنة، أو زيادة حجم مجمّع الاتصالات، أو إكمال تعداد النتائج.
إعادة محاولة العمليات
إذا فشل الاتصال أو انتهت المهلة أثناء إدراج الصفوف، فلن يُعرف ما إذا نجحت العملية: إذ ربما ثبّت الخادم الصفوف قبل أن يفقد العميل الاستجابة. عيّن قيمة ثابتة لـDeduplicationToken للدفعة المنطقية قبل إعادة محاولتها:
التسجيل والتشخيص
يتكامل عميل TCP معMicrosoft.Extensions.Logging. التسجيل اختياري؛ وعند عدم توفّر
LoggerFactory، لا ينشئ العميل أي مسجّلات ولا ينسّق أي رسائل سجل.
ILoggerFactory الخاص بالحاوية
ما لم تكن الخيارات المقدَّمة قد حدّدت واحدًا بالفعل.
فئات التسجيل
هيّئ الفئات باستخدام تهيئة التسجيل القياسية في .NET:
Debug، وتتضمن من نص SQL ما لا يزيد على StatementMaxLength محرفًا.
القيمة الافتراضية هي خمسة محارف. اضبط القيمة على صفر أو أقل لاستبعاد نص العبارة من السجلات،
ولا ترفعها إلا بعد مراعاة أن المعلمات والقيم الحرفية قد تحتوي على بيانات حساسة.
رسائل سجل الخادم
يرصد تكامل تسجيل الأحداث سلوك جهة العميل. أما حزم سجل الاستعلامات الخاصة بـ ClickHouse، فهي منفصلة وتُرسَل إلىClickHouseTcpQueryCallbacks.OnLog. فعِّل إرسالها باستخدام
إعداد الخادم send_logs_level:
OpenTelemetry
يُصدر عميل TCP وحدات span للتتبّع الموزّع عبر واجهة برمجة التطبيقاتSystem.Diagnostics.Activity في .NET.
اشترك في مصدر نشاط TCP باستخدام موفّر تتبّع OpenTelemetry:
ClickHouse.Driver.Tcp، وهو منفصل عن مصدر عميل HTTP، لذا
يمكن جمع بيانات أيٍّ من وسيلتَي النقل على حدة. وإذا لم يشترك أي مستمع، فلن تُنشئ العمليات
أي أنشطة.
وحدات span والسمات
يُصدر العميل وحدات span لعمليات SQL وطلبات التحقق من الاتصال والاتصالات الجديدة. وتُسمّى وحدة span الخاصة بعبارة SQL باسم أول كلمة مفتاحية فيها، مثلSELECT أو INSERT؛ أما العبارات التي لا يمكن التعرّف على
كلمتها المفتاحية الأولى، فتُسمّى وحدات span الخاصة بها query. وتغطي وحدة span المسماة connect إنشاء اتصال المقبس والتفاوض على TLS
والمصافحة وفق البروتوكول الأصلي. وتشمل وحدات span الخاصة بالعبارات أيضًا الوقت المستغرق في انتظار اتصال متاح من مجمع الاتصالات.
لا تظهر العدادات إلا إذا كانت لدى الخادم أو العميل قيمة ذات معنى للإبلاغ عنها. فعلى سبيل المثال،
تُبلّغ عملية الإدراج التي تُحمّل كتل بيانات عن الصفوف التي أرسلها العميل، لكنها لا تتلقى من
الخادم أي عدادات للقراءة. وتتضمن وحدات span الفاشلة أيضًا حدث
exception يضم نوع الاستثناء ورسالته وتتبّع
المكدس.
نص SQL والبيانات الحساسة
يُستبعَد نص SQL من spans افتراضيًا. ولتضمينه، فعِّله صراحةً واضبط حدًا مناسبًا:StatementMaxLength طول نص SQL في كلٍّ من السمة db.query.text وسجلات تصحيح الأخطاء. وإذا كانت قيمته صفرًا
أو أقل، يُحذف نص SQL من كليهما. راجع أيضًا رسائل الاستثناء المُصدَّرة وتتبّعات المكدس، إذ قد
تتضمن أخطاء الخادم تفاصيل الاستعلام.
تمرير سياق التتبع
عندما يستخدمActivity.Current صيغة معرّف W3C، يضمّن العميل معرّف التتبع ومعرّف span وعلامات التتبع
وحالة التتبع في حزمة الاستعلام الأصلية. ويمكن لـ ClickHouse بعد ذلك إنشاء وحدات span للخادم ضمن
التتبع الموزّع نفسه. ويظل جمع وحدات span على جانب الخادم وأخذ العينات منها محكومَين بتهيئة ClickHouse؛
فعلى سبيل المثال، يمكن ضبط احتمال أخذ العينات لكل استعلام:
system.query_log، وكذلك بجدول system.opentelemetry_span_log في ClickHouse عند تهيئته.
القيود
لا يزال عميل TCP تجريبيًا، ولا يوفّر جميع الميزات المتاحة في عميل HTTP.الميزات المتاحة عبر HTTP فقط
واجهة برمجة تطبيقات TCP ليست موفّر ADO.NET، ولا يمكن استخدامها مع أدوات ربط الكائنات بقواعد البيانات (ORMs). وهي لا تدعم أيضًا الإدخال والإخراج بصيغ CSV أو JSONEachRow أو Parquet أو عبر تدفّق بيانات خام؛ أو المصادقة باستخدام رمز حامل أو ترويسات HTTP مخصّصة؛ أو تخصيص تحديد أنواع المعلمات أو تنسيقها أو تحويلها عند القراءة؛ أو تعيين قاعدة بيانات أو دور لكل استعلام. استخدم عميل HTTP إذا كان التطبيق يحتاج إلى أيٍّ من هذه الميزات.معلمات SQL
لا تُدعَم سوى العناصر النائبة{name:Type} الأصلية في ClickHouse؛ ولا يعيد عميل TCP كتابة
العناصر النائبة @name وفق صيغة ADO.NET. في إصدارات ClickHouse من 25.8 إلى 26.6، قد تُعامَل أسماء المعلمات التي تطابق
إعدادات الخادم، مثل limit أو offset، على أنها إعدادات، ومن ثم تُرفَض. أعد تسمية
هذه المعلمات، مثلًا إلى row_limit، إذا كنت تدعم تلك الإصدارات.
تغطية أنواع البيانات
يوضّح قسم أنواع البيانات المدعومة جميع حالات المطابقة. وللمرمِّز الأصلي الحالي القيود المهمة التالية:- يمكن أن تضمّ أنواع Tuple سبعة عناصر على الأكثر.
- الحالات الوسيطة لـ
AggregateFunction(function, ...)غير مدعومة. احسب قيمها النهائية على الخادم، مثلًا باستخدامsumMerge(column)، واقرأ النتيجة بدلًا منها. - لا يُدعم سوى تخطيط
QBit(T, N)ذي الوسيطين، من دون تقسيم الأبعاد إلى مجموعات ثابتة الحجم. - يستخدم
JSONتسلسل String الخاص بـClickHouse، ويتطلبoutput_format_native_write_json_as_string = 1، وهي قيمة يطلبها العميل افتراضيًا. - لا تتوفّر لعمليات الإدراج التي ينشئها التطبيق بنية موجّهة للصفوف لـ
Nested(...)عندما تكونflatten_nested = 0. استخدم بدلًا منها أعمدةArray(T)المسطّحة ذات الأسماء المنقّطة، وهي الخيار الافتراضي. - لا يمكن لعمود
Geometryينشئه التطبيق التمييز تلقائيًا بين بدائل تشترك في بنية CLR نفسها، مثلRingوLineString. أدرج النوع الهندسي المحدّد، أو أعِد إدراج عمودGeometryمفكك الترميز الذي يحتفظ بمميّزاته.
إعادة المحاولة تلقائيًا
لا يعيد العميل محاولة تنفيذ العمليات الفاشلة تلقائيًا. أعد محاولة تنفيذ العمليات التي يمكن تكرارها بأمان فقط، وحدّد قيمة ثابتة لـDeduplicationToken قبل إعادة محاولة عملية إدراج لم تُعرف نتيجتها.
راجع إعادة محاولة تنفيذ العمليات لمزيد من التفاصيل.