-
ClickHouseClient(موصى به): عميل عالي المستوى وآمن للاستخدام من عدة خيوط، ومصمَّم للاستخدام بنمط singleton. يوفّر واجهة برمجة تطبيقات غير متزامنة وبسيطة للاستعلامات وعمليات الإدراج المجمّع. وهو الأنسب لمعظم التطبيقات. -
ADO.NET (
ClickHouseDataSource,ClickHouseConnection,ClickHouseCommand): تجريدات قياسية لقواعد البيانات في .NET. وهي مطلوبة لتكامل ORM (Dapper وLinq2db) وعندما تحتاج إلى التوافق مع ADO.NET. تُعدClickHouseBulkCopyفئة مساعدة لإدراج البيانات بكفاءة باستخدام اتصال ADO.NET. الفئةClickHouseBulkCopyمُهمَلة وستُزال في إصدار مستقبلي؛ استخدمClickHouseClient.InsertBinaryAsyncبدلاً منها.
دليل الترحيل
- حدّث ملف
.csprojلاستخدام اسم الحزمة الجديدClickHouse.Driverوأحدث إصدار على NuGet. - حدّث جميع مراجع
ClickHouse.ClientإلىClickHouse.Driverفي شيفرة مشروعك.
إصدارات .NET المدعومة
ClickHouse.Driver إصدارات .NET التالية:
- .NET 6.0
- .NET 8.0
- .NET 9.0
- .NET 10.0
التثبيت
البدء السريع
التهيئة
- سلسلة الاتصال: أزواج مفتاح/قيمة مفصولة بفواصل منقوطة، تحدد المضيف وبيانات اعتماد المصادقة وخيارات الاتصال الأخرى.
- كائن
ClickHouseClientSettings: كائن تهيئة مضبوط الأنواع يمكن تحميله من ملفات التهيئة أو تعيينه في الشيفرة.
إعدادات الاتصال
تنسيق البيانات والتسلسل
إدارة الجلسات
تؤدي العلامة
UseSession إلى الاحتفاظ بجلسة الخادم، مما يتيح استخدام عبارات SET والجداول المؤقتة. ستُعاد تهيئة الجلسات بعد 60 ثانية من عدم النشاط (المهلة الافتراضية). ويمكن تمديد مدة الجلسة عبر تعيين إعدادات الجلسة باستخدام عبارات ClickHouse أو إعدادات الخادم.تتيح الفئة ClickHouseConnection عادةً التشغيل المتوازي (أي يمكن لعدة خيوط تنفيذ الاستعلامات بالتزامن). ومع ذلك، فإن تمكين العلامة UseSession يقيّد ذلك باستعلام نشط واحد فقط لكل اتصال في أي لحظة (وهذا قيد على جهة الخادم).الأمان
تهيئة عميل HTTP
التسجيل وتصحيح الأخطاء
الإعدادات المخصصة والأدوار
عند استخدام سلسلة اتصال لتعيين إعدادات مخصصة، استخدم البادئة
set_، مثل “set_max_threads=4”. أما عند استخدام كائن ClickHouseClientSettings، فلا تستخدم البادئة set_.للاطلاع على القائمة الكاملة بالإعدادات المتاحة، راجع هنا.أمثلة لسلسلة الاتصال
اتصال بسيط
باستخدام إعدادات ClickHouse مخصّصة
QueryOptions
QueryOptions تجاوز الإعدادات على مستوى العميل لكل استعلام على حدة. جميع الخصائص اختيارية، ولا تستبدل القيم الافتراضية للعميل إلا عند تحديدها.
مثال:
InsertOptions
InsertOptions QueryOptions بإعدادات خاصة بعمليات الإدراج المجمّع عبر InsertBinaryAsync.
تتوفّر أيضًا جميع خصائص
QueryOptions في InsertOptions.
مثال:
تخطي استعلام فحص المخطط
InsertBinaryAsync استعلام SELECT ... WHERE 1=0 قبل كل عملية إدراج لاكتشاف أنواع الأعمدة. في السيناريوهات ذات معدل النقل المرتفع، يمكنك التخلص من هذا العبء الإضافي باستخدام خيارين:
الخيار 1: تحديد أنواع الأعمدة صراحةً
عندما تكون على دراية بمخطط الجدول وقت التجميع، مرّره مباشرةً عبر ColumnTypes. عندها لن يُرسل أي استعلام للمخطط على الإطلاق:
UseSchemaCache = true للاستعلام عن المخطط مرة واحدة ثم إعادة استخدامه في عمليات الإدراج اللاحقة ضمن مثيل ClickHouseClient نفسه:
- يحظى
ColumnTypesبالأولوية علىUseSchemaCache. وإذا تم تعيينهما معًا، فستُستخدم الأنواع المحددة صراحةً. - لا تكتشف ذاكرة التخزين المؤقت للمخطط تغييرات
ALTER TABLE. إذا عدّلت مخطط الجدول، فأنشئClickHouseClientجديدًا أو تجنّب استخدامUseSchemaCacheلهذا الجدول. - يقتصر نطاق ذاكرة التخزين المؤقت على instance الخاصة بـ
ClickHouseClient، ويُعرَّف مفتاحها بواسطة (database, table). وتشترك المجموعات الفرعية المختلفة من الأعمدة في الجدول نفسه في مخطط واحد مخزَّن مؤقتًا.
ClickHouseClient
ClickHouseClient واجهة برمجة التطبيقات الموصى بها للتفاعل مع ClickHouse. وهي آمنة للاستخدام من عدة خيوط، ومصممة للاستخدام كـ singleton، وتدير داخليًا تجمّع اتصالات HTTP.
إنشاء عميل
ClickHouseClient باستخدام سلسلة اتصال أو كائن ClickHouseClientSettings. راجع قسم التهيئة للاطّلاع على الخيارات المتاحة.
تتوفّر تفاصيل خدمة ClickHouse Cloud الخاصة بك في وحدة تحكم ClickHouse Cloud.
حدّد خدمة وانقر على Connect:
اختر C#. ستُعرض تفاصيل الاتصال أدناه.
إذا كنت تستخدم ClickHouse مُدارًا ذاتيًا، فسيُحدِّد مسؤول ClickHouse لديك تفاصيل الاتصال.
باستخدام سلسلة اتصال:
ClickHouseClientSettings:
IHttpClientFactory:
صُمِّم
ClickHouseClient ليكون طويل الأمد ويُستخدم بشكل مشترك عبر تطبيقك. أنشِئه مرة واحدة فقط (عادةً بصفته singleton) وأعِد استخدامه في جميع عمليات قاعدة البيانات. يتولى العميل إدارة تجميع اتصالات HTTP داخليًا.تنفيذ الاستعلامات
ExecuteNonQueryAsync مع التعليمات التي لا تُرجع نتائج:
ExecuteScalarAsync لاسترجاع قيمة واحدة:
إدخال البيانات
عمليات الإدراج باستخدام المعلمات
ExecuteNonQueryAsync. يجب تحديد أنواع المعلمات في SQL باستخدام الصياغة {name:Type}:
عمليات الإدراج المجمّعة
InsertBinaryAsync لإدراج أعداد كبيرة من الصفوف بكفاءة. فهو يمرّر البيانات بتنسيق الصفوف الثنائي الأصلي في ClickHouse، ويدعم تحميل الدُفعات بالتوازي، ويتجنب أخطاء “URL طويل جدًا” التي قد تحدث مع الاستعلامات ذات المعلمات.
InsertOptions:
- يجلب العميل تلقائيًا بنية الجدول عبر
SELECT * FROM <table> WHERE 1=0قبل الإدراج. يجب أن تتوافق القيم المُمرَّرة مع أنواع الأعمدة المستهدفة. لتجاوز هذا الاستعلام، استخدمInsertOptions.ColumnTypesأوInsertOptions.UseSchemaCache. - عندما تكون قيمة
MaxDegreeOfParallelism > 1، تُحمَّل الدفعات بالتوازي. لا تتوافق الجلسات مع الإدراج المتوازي؛ لذا عطّل الجلسات أو عيّنMaxDegreeOfParallelism = 1. - استخدم
RowBinaryFormat.RowBinaryWithDefaultsفيInsertOptions.Formatإذا كنت تريد أن يطبّق الخادم قيم DEFAULT على الأعمدة غير المُمرَّرة.
عمليات إدراج POCO
object[]، يمكنك إدراج كائنات POCO محددة النوع مباشرةً. سجّل النوع مرة واحدة، ثم مرّر IEnumerable<T>:
عندما تحدد جميع الخصائص المعينة
Type صريحًا، يُتخطّى استعلام فحص المخطط بالكامل. وعندما تكون بعض الخصائص فقط ذات أنواع صريحة، يعود برنامج التشغيل إلى فحص المخطط لمجموعة الأعمدة الكاملة.
يدعم InsertBinaryAsync<T> خيارات InsertOptions نفسها (التجميع على دفعات، التوازي، التخزين المؤقت للمخطط) مثل التحميل الزائد object[].
بخلاف التحميل الزائد
object[]، لا يقبل InsertBinaryAsync<T> قائمة أعمدة صريحة. تُحدَّد الأعمدة بواسطة الخصائص المعينة للنوع المسجل. للتحكم في الأعمدة التي تُدرج، استخدم [ClickHouseNotMapped] لاستبعاد الخصائص أو [ClickHouseColumn(Name = "...")] لإعادة تسميتها.إذا تم تعيين ColumnTypes في InsertOptions، فستتجاوز سمات POCO.تطور المخطط
DEFAULT (أو تعبيرات افتراضية أخرى) يملؤها الخادم تلقائيًا. ولا حاجة إلى أي تغييرات في الشيفرة أو إلى إعادة التسجيل.
قراءة البيانات
ExecuteReaderAsync لتنفيذ استعلامات SELECT. يوفّر ClickHouseDataReader المُعاد وصولًا مُحدَّد النوع إلى أعمدة النتائج عبر طرق مثل GetInt64() وGetString() وGetFieldValue<T>().
استدعِ Read() للانتقال إلى الصف التالي. وتُرجع false عند عدم وجود المزيد من الصفوف. ويمكنك الوصول إلى الأعمدة حسب الفهرس (ابتداءً من 0) أو حسب اسم العمود.
معلمات SQL
{parameter_name:DataType}.
أمثلة:
تُمرَّر معلمات SQL ‘bind’ كمعلمات استعلام في HTTP URI، لذا فإن استخدام عدد كبير جدًا منها قد يؤدي إلى ظهور استثناء “URL طويل جدًا”. استخدم
InsertBinaryAsync لإدراج كميات كبيرة من البيانات لتجنّب هذا القيد.معرّف الاستعلام
query_id يمكن استخدامه لجلب البيانات من جدول system.query_log أو لإلغاء الاستعلامات طويلة التشغيل. يمكنك تحديد معرّف استعلام مخصّص عبر QueryOptions:
تعيين نوع المعلمة المخصّص
@ (مثل WHERE id = @id)، يستنتج برنامج التشغيل تلقائيًا نوع ClickHouse من نوع القيمة في .NET. على سبيل المثال، يُعيَّن int إلى Int32، ويُعيَّن DateTime إلى DateTime.
لتجاوز هذه الإعدادات الافتراضية، عيّن ParameterTypeResolver في ClickHouseClientSettings. ويكون ذلك مفيدًا عندما تريد استخدام DateTime64(3) لجميع معلمات DateTime بدقة الملّي ثانية، أو استخدام قيمة scale محددة لجميع قيم Decimal، من دون تعيين ClickHouseType لكل معلمة على حدة.
استخدام DictionaryParameterTypeResolver لتعيينات الأنواع البسيطة:
IParameterTypeResolver مخصّص للحالات المتقدمة:
للاستدلال المعتمد على القيمة أو المستند إلى الاسم، نفِّذ الواجهة IParameterTypeResolver مباشرةً. أرجِع null للانتقال إلى الاستدلال الافتراضي:
QueryOptions.ParameterTypeResolver. وعند تعيينه، تكون له أولوية أعلى من المحلِّل على مستوى العميل.
ترتيب أولوية تحديد النوع:
المحلِّل ليس سوى خطوة ضمن سلسلة ترتيب الأولوية. من الأعلى إلى الأدنى أولوية:
- تعيين
ClickHouseTypeصراحةً على المعلَمة - تلميح نوع SQL من الصيغة
{name:Type}في الاستعلام IParameterTypeResolver(منQueryOptions.ParameterTypeResolver، مع الرجوع إلىClickHouseClientSettings.ParameterTypeResolver)- استنتاج النوع المضمَّن (
TypeConverter.ToClickHouseType)
ClickHouseConnection — إذ ترث الاتصالات المُنشأة من العميل هذه الإعدادات.
البث الخام
ExecuteRawResultAsync لبث نتائج الاستعلام مباشرةً بتنسيق محدد، متجاوزًا قارئ البيانات. يفيد ذلك عند تصدير البيانات إلى ملفات أو تمريرها إلى أنظمة أخرى:
JSONEachRow، CSV، TSV، Parquet، Native. راجع توثيق التنسيقات للتعرّف على جميع الخيارات.
إدراج تدفق خام
InsertRawStreamAsync لإدراج البيانات مباشرةً من تدفقات الملفات أو الذاكرة بتنسيقات مثل CSV وJSON وParquet، أو بأي تنسيق ClickHouse مدعوم.
إدراج من ملف CSV:
راجع وثائق إعدادات الصيغ للاطلاع على خيارات التحكّم في سلوك إدخال البيانات.
المزيد من الأمثلة
ADO.NET
ClickHouseConnection وClickHouseCommand وClickHouseDataReader. وتُعد واجهة برمجة التطبيقات هذه ضرورية للتكامل مع ORM (Dapper وLinq2db)، وكذلك عند الحاجة إلى طبقات تجريد قواعد البيانات القياسية في .NET.
إدارة دورة الحياة باستخدام ClickHouseDataSource
ClickHouseDataSource لضمان الإدارة السليمة لدورة الحياة وتجميع الاتصالات. يدير DataSource مثيل ClickHouseClient واحدًا داخليًا، وتشترك جميع الاتصالات في تجمّع الاتصالات HTTP الخاص به.
استخدام ClickHouseCommand
ExecuteNonQueryAsync()- لعبارات INSERT وUPDATE وDELETE وDDLExecuteScalarAsync()- يعيد أول عمود من أول صفExecuteReaderAsync()- يعيدClickHouseDataReaderللتنقّل بين النتائج
استخدام ClickHouseDataReader
ClickHouseDataReader الوصول إلى نتائج الاستعلام مع الحفاظ على أنواع البيانات:
أفضل الممارسات
مدة الاتصال وتجميع الاتصالات
ClickHouse.Driver المكوّن System.Net.Http.HttpClient في الخلفية. ويحتوي HttpClient على تجمّع اتصالات لكل endpoint. ونتيجة لذلك:
- تُمرَّر جلسات قاعدة البيانات عبر اتصالات HTTP التي يديرها تجمّع الاتصالات.
- يُعيد التجمّع استخدام اتصالات HTTP تلقائيًا.
- قد تظل الاتصالات مفتوحة حتى بعد التخلّص من الكائنات
ClickHouseClientأوClickHouseConnection.
التعامل مع DateTime
-
استخدم UTC كلما أمكن. خزّن الطوابع الزمنية في أعمدة
DateTime('UTC')واستخدمDateTimeKind.Utcفي الشيفرة الخاصة بك. هذا يزيل أي التباس متعلق بالمنطقة الزمنية. -
استخدم
DateTimeOffsetللتعامل الصريح مع المنطقة الزمنية. فهو يمثّل دائمًا لحظة زمنية محددة ويتضمن معلومات الإزاحة. -
حدّد المنطقة الزمنية في تلميحات النوع في SQL. عند استخدام المعلمات مع قيم DateTime من النوع
Unspecifiedوالموجّهة إلى أعمدة غير UTC، ضمّن المنطقة الزمنية في SQL:
عمليات الإدراج غير المتزامنة
CustomSettings أو سلسلة الاتصال:
wait_for_async_insert):
الإعدادات الأساسية:
الجلسات
- الجداول المؤقتة (
CREATE TEMPORARY TABLE) - الحفاظ على سياق الاستعلام عبر عدة تعليمات
- إعدادات على مستوى الجلسة (
SET max_threads = 4)
أنواع البيانات المدعومة
ClickHouse.Driver جميع أنواع بيانات ClickHouse. تُبيّن الجداول أدناه أوجه التوافق بين أنواع ClickHouse وأنواع .NET الأصلية عند قراءة البيانات من قاعدة البيانات.
تعيين الأنواع: عند القراءة من ClickHouse
أنواع الأعداد الصحيحة
أنواع الأعداد ذات الفاصلة العائمة
الأنواع العشرية
يُتحكَّم في تحويل النوع Decimal من خلال الإعداد UseCustomDecimals.
نوع Boolean
أنواع السلاسل النصية
افتراضيًا، يُرجَع كلٌّ من العمودين
String وFixedString(N) على هيئة string. عيّن ReadStringsAsByteArrays=true في سلسلة الاتصال لقراءتهما على هيئة byte[] بدلًا من ذلك. يفيد هذا عند تخزين بيانات ثنائية قد لا تكون بتنسيق UTF-8 صالح.أنواع التاريخ والوقت
يخزّن ClickHouse قيم
DateTime وDateTime64 داخليًا على هيئة طوابع زمنية Unix (بالثواني أو بوحدات أصغر من الثانية منذ حقبة Unix). وعلى الرغم من أن التخزين يكون دائمًا بتوقيت UTC، فقد تكون للأعمدة منطقة زمنية مرتبطة بها تؤثر في كيفية عرض القيم وتفسيرها.
عند قراءة قيم DateTime، تُضبط الخاصية DateTime.Kind بناءً على المنطقة الزمنية للعمود:
بالنسبة إلى الأعمدة التي لا تستخدم UTC، تمثل قيمة
DateTime المُعادة الوقت المحلي في تلك المنطقة الزمنية. استخدم ClickHouseDataReader.GetDateTimeOffset() للحصول على DateTimeOffset مع الإزاحة الصحيحة لتلك المنطقة الزمنية:
DateTime بدلًا من DateTime('Europe/Amsterdam'))، يعيد برنامج التشغيل قيمة DateTime مع Kind=Unspecified. وهذا يحافظ على الوقت المحلي كما تظهره الساعة تمامًا كما هو مخزّن، من دون افتراض أي منطقة زمنية.
إذا كنت بحاجة إلى سلوكٍ مدركٍ للمنطقة الزمنية للأعمدة التي لا تتضمن مناطق زمنية صريحة، فإما أن:
- تستخدم مناطق زمنية صريحة في تعريفات الأعمدة:
DateTime('UTC')أوDateTime('Europe/Amsterdam') - تطبّق المنطقة الزمنية بنفسك بعد القراءة.
نوع JSON
يُحدَّد نوع الإرجاع لأعمدة JSON من خلال الإعداد
JsonReadMode:
-
Binary(الافتراضي): يعيدSystem.Text.Json.Nodes.JsonObject. يوفّر وصولًا منظّمًا إلى بيانات JSON، لكن أنواع ClickHouse المتخصصة (مثل عناوين IP وUUIDs والقيم العشرية الكبيرة) تُحوَّل إلى تمثيلاتها النصية داخل بنية JSON. -
String: يعيد JSON الخام كسلسلةstring. ويحافظ على تمثيل JSON كما هو تمامًا من ClickHouse، وهو ما يكون مفيدًا عندما تحتاج إلى تمرير JSON كما هو دون تحليله، أو عندما تريد التعامل مع فك التسلسل بنفسك.
أنواع أخرى
سيُحوَّل النوعان Dynamic وVariant إلى النوع المقابل للنوع الأساسي الفعلي في كل صف.
أنواع Geometry
نوع Geometry هو نوع Variant يمكن أن يحتوي على أيٍّ من أنواع Geometry. وسيُحوَّل إلى النوع المقابل.
تعيين الأنواع: الكتابة إلى ClickHouse
أنواع الأعداد الصحيحة
أنواع الأعداد ذات الفاصلة العائمة
النوع المنطقي
أنواع String
أنواع التاريخ والوقت
يراعي برنامج التشغيل
DateTime.Kind عند كتابة القيم:
تحافظ قيم
DateTimeOffset دائمًا على اللحظة الزمنية الدقيقة.
مثال: DateTime بتوقيت UTC (تُحفَظ اللحظة الزمنية كما هي)
DateTimeKind.Utc أو DateTimeOffset في جميع عمليات DateTime. يضمن ذلك أن تعمل شيفرتك بشكل متسق بغض النظر عن المنطقة الزمنية للخادم أو العميل أو العمود.
معلمات HTTP مقابل Bulk Copy
Unspecified:
Bulk Copy يعرف المنطقة الزمنية للعمود المستهدف ويفسّر قيم Unspecified بشكل صحيح وفقًا لتلك المنطقة الزمنية.
HTTP Parameters لا تعرف تلقائيًا المنطقة الزمنية للعمود. يجب تحديدها في تلميح نوع SQL:
أنواع Decimal
نوع JSON
يتحكم إعداد
JsonWriteMode في السلوك عند كتابة JSON:
-
String(الافتراضي): يقبلstringوJsonObjectوJsonNodeأو أي كائن. تُسلسَل جميع المدخلات عبرSystem.Text.Json.JsonSerializerوتُرسل كسلاسل JSON لتحليلها على جهة الخادم. هذا هو الوضع الأكثر مرونة ويعمل من دون تسجيل النوع. -
Binary: لا يقبل إلا أنواع POCO المسجّلة. تُحوَّل البيانات إلى تنسيق JSON الثنائي الخاص بـ ClickHouse على جهة العميل مع دعم كامل لتلميحات النوع. ويتطلب استدعاءconnection.RegisterJsonSerializationType<T>()قبل الاستخدام. وتؤدي كتابة قيمstringأوJsonNodeفي هذا الوضع إلى طرحArgumentException.
أعمدة JSON محددة الأنواع
JSON(id UInt64, price Decimal128(2)))، يستخدم برنامج التشغيل هذه التلميحات لتسلسل القيم مع الحفاظ الكامل على سلامة الأنواع. وهذا يحافظ على الدقة في أنواع مثل UInt64 وDecimal وUUID وDateTime64، والتي قد تفقد دقتها لولا ذلك عند تسلسلها بصيغة JSON عامة.
تسلسل كائنات POCO
JsonWriteMode:
String mode (الافتراضي): تُسلسَل كائنات POCO عبر System.Text.Json.JsonSerializer. لا يتطلب ذلك تسجيل الأنواع. هذا هو النهج الأبسط، كما أنه يعمل مع الكائنات المجهولة.
Binary mode: تُسلسَل كائنات POCO باستخدام تنسيق JSON الثنائي الخاص ببرنامج التشغيل مع دعم كامل لتلميحات النوع. يجب تسجيل الأنواع باستخدام connection.RegisterJsonSerializationType<T>() قبل الاستخدام. يدعم هذا الوضع تعيينات مسارات مخصّصة عبر السمات:
-
[ClickHouseJsonPath("path")]: يربط خاصيةً بمسار JSON مخصّص. ويكون ذلك مفيدًا مع البُنى المتداخلة أو عندما يختلف اسم الخاصية عن مفتاح JSON المطلوب. يعمل فقط في Binary mode. -
[ClickHouseJsonIgnore]: يستبعد خاصيةً من التسلسل. يعمل فقط في Binary mode.
UserId لن تتطابق إلا مع تلميح مُعرَّف باسم UserId، وليس userid. وهذا يتوافق مع سلوك ClickHouse الذي يسمح بوجود مسارات مثل userName وUserName معًا كحقول منفصلة.
القيود (في Binary mode فقط):
- يجب تسجيل أنواع POCO على الاتصال باستخدام
connection.RegisterJsonSerializationType<T>()قبل إجراء التسلسل. وستؤدي محاولة تسلسل نوع غير مسجّل إلى ظهور الاستثناءClickHouseJsonSerializationException. - تتطلب خصائص القاموس والمصفوفة/القائمة تلميحات نوع في تعريف العمود لكي تُسلسَل بشكل صحيح. ومن دون هذه التلميحات، استخدم String mode بدلًا من ذلك.
- لا تُكتَب القيم الخالية في خصائص POCO إلا إذا كان للمسار تلميح نوع
Nullable(T)في تعريف العمود. ولا يسمح ClickHouse بأنواعNullableداخل مسارات JSON الديناميكية، لذلك يتم تخطي الخصائص الخالية غير المزوّدة بتلميحات. - يتم تجاهل السمات
ClickHouseJsonPathوClickHouseJsonIgnoreفي String mode (إذ لا تعمل إلا في Binary mode).
أنواع أخرى
أنواع Geometry
غير مدعوم عند الكتابة
التعامل مع النوع Nested
Nested(...)) وكتابته باستخدام دلالات المصفوفات.
التسجيل والتشخيص
Microsoft.Extensions.Logging لتوفير تسجيل خفيف الوزن يُفعَّل عند الحاجة. وعند تمكينه، يُصدر برنامج التشغيل رسائل منظَّمة لأحداث دورة حياة الاتصال، وتنفيذ الأوامر، وعمليات النقل، وعمليات الإدراج المجمّع. ويظل التسجيل اختياريًا بالكامل—فالتطبيقات التي لا تُعدّ مُسجِّلًا تواصل العمل دون أي عبء إضافي.
البدء السريع
استخدام appsettings.json
استخدام تهيئة داخل الذاكرة
الفئات والبواعث
مثال: تشخيص مشكلات الاتصال
- اختيار HTTP client factory (التجمّع default مقابل اتصال واحد)
- تهيئة HTTP handler (SocketsHttpHandler أو HttpClientHandler)
- إعدادات connection pool (MaxConnectionsPerServer وPooledConnectionLifetime وما إلى ذلك)
- إعدادات timeout (ConnectTimeout وExpect100ContinueTimeout وما إلى ذلك)
- تهيئة SSL/TLS
- أحداث فتح الاتصال وإغلاقه
- تتبّع معرّف الجلسة
وضع Debug: تتبّع الشبكة والتشخيص
ClickHouse.Driver.Diagnostic.TraceHelper). ستُسجَّل الأحداث ضمن الفئة ClickHouse.Driver.NetTrace. تحذير: سيؤدي ذلك إلى إنشاء سجلات شديدة التفصيل، وسيؤثر في الأداء. لا يُنصح بتمكين وضع Debug في بيئة الإنتاج.
OpenTelemetry
System.Diagnostics.Activity. وعند تمكينه، يُنشئ برنامج التشغيل spans لعمليات قاعدة البيانات يمكن تصديرها إلى أنظمة observability الخلفية مثل Jaeger أو ClickHouse نفسه (عبر OpenTelemetry Collector).
تمكين التتبّع
ActivitySource الخاص ببرنامج تشغيل ClickHouse إلى تهيئة OpenTelemetry:
سمات span
خيارات التكوين
ClickHouseDiagnosticsOptions:
إعدادات TLS
التحقق المخصص من الشهادات
HttpClient خاصًا بك مع معالج ServerCertificateCustomValidationCallback مُعدّ:
اعتبارات مهمة عند استخدام
HttpClient مخصّص- فك الضغط التلقائي: يجب تمكين
AutomaticDecompressionإذا لم يكن الضغط معطّلًا (فالضغط مفعّل افتراضيًا). - مهلة الخمول: اضبط
PooledConnectionIdleTimeoutعلى قيمة أقل منkeep_alive_timeoutالخاص بالخادم (10 ثوانٍ في ClickHouse Cloud) لتجنّب أخطاء الاتصال الناتجة عن الاتصالات شبه المفتوحة.
دعم ORM
ClickHouseConnection). ولإدارة دورة حياة الاتصالات على النحو الصحيح، أنشئ الاتصالات باستخدام ClickHouseDataSource:
Dapper
ClickHouse.Driver مع Dapper. ويحوّل برنامج التشغيل تلقائيًا صياغة @parameter الخاصة بـ Dapper إلى الصياغة الأصلية في ClickHouse {parameter:Type}، مع استنتاج الأنواع من قيم .NET.
استخدم ClickHouseDataSource لإدارة مدة بقاء الاتصال على نحو صحيح:
أنماط تمرير المَعلمات
DynamicParameters (من قاموس أو كائن مجهول الاسم):
الاستعلام عن POCOs
صياغة المعلمات الأصلية في ClickHouse
{param:Type} الخاصة بـ ClickHouse مع Dictionary<string, object> لقيم المعلمات. لا تجمع بين صياغة @param وصياغة {param:Type} للمعلمة نفسها.
WHERE IN
WHERE id IN (@Ids1, @Ids2, @Ids3)، ويحوّل برنامج التشغيل كل معلمة موسَّعة.
كما تعمل الدالة has() في ClickHouse أيضًا مع معلمة من النوع Array:
معالِجات الأنواع المخصّصة
ITuple وBigInteger وClickHouseDecimal، تسجيل معالِجات عند بدء التشغيل:
Dapper.Contrib
GetAll<T>() وGet<T>(id). أما Insert<T>() فلا يعمل، إذ يولّد صياغة SQL Server (SCOPE_IDENTITY, []). ويُوصى باستخدام الطريقة الأصلية InsertBinaryAsync في ClickHouseClient بدلًا من ذلك.
القيود
Linq2db
DataConnection باستخدام موفّر ClickHouse:
BulkCopyAsync لإجراء عمليات إدراج مجمّعة بكفاءة.
Entity Framework Core
SaveChanges — وكل ذلك باستخدام أنماط EF Core المألوفة.
- NuGet:
ClickHouse.EntityFrameworkCore - المصدر: GitHub
هذا الموفّر قيد التطوير النشط. يدعم الإصدار الحالي استعلامات LINQ (بما في ذلك عمليات JOIN، والاستعلامات الفرعية، وعمليات المجموعات)، و
INSERT عبر SaveChanges / BulkInsertAsync، وعمليات الترحيل مع دعم DDL الكامل (CREATE / ALTER / DROP)، وتهيئة محرك الجدول الخاصة بـ ClickHouse. لا يدعم UPDATE / DELETE.التثبيت
البدء السريع
DbContext، ثم أجرِ استعلامًا باستخدام LINQ:
الأنواع المدعومة
استخدم
ClickHouseDecimal (من ClickHouse.Driver.Numerics) بدلًا من decimal عندما تحتاج إلى الدقة الكاملة لأعمدة Decimal128/Decimal256، لأن decimal في .NET يقتصر على 28–29 رقمًا معنويًا.
عمليات LINQ المدعومة
Where, OrderBy, Take, Skip, Select, First, Single, Any, All, Count, Distinct, AsNoTracking
GROUP BY والتجميع: GroupBy مع Count, LongCount, Sum, Average, Min, Max — بما في ذلك HAVING (استخدام .Where() بعد .GroupBy())، وإجراء عدة عمليات تجميع ضمن إسقاط واحد، واستخدام OrderBy على نتائج التجميع.
عمليات JOIN: Join (INNER)، وأنماط GroupJoin/SelectMany (LEFT وCROSS). تُرجِع LEFT JOIN قيمة null فعلية للصفوف غير المتطابقة (راجع دلالات null في LEFT JOIN أدناه).
الاستعلامات الفرعية: Contains / IN المترابطة، وAny / EXISTS، وAll، والاستعلامات الفرعية scalar ضمن الإسقاطات.
عمليات المجموعات: Concat (→ UNION ALL)، وUnion (→ UNION DISTINCT)، وIntersect، وExcept.
المجموعات المحلية المضمنة: تُترجَم عمليات join وContains على المجموعات الموجودة في الذاكرة (int[], List<T>, إلخ) إلى سلسلة من عمليات UNION.
طرق String: Contains, StartsWith, EndsWith, IndexOf, Replace, Substring, Trim/TrimStart/TrimEnd, ToLower, ToUpper, Length, IsNullOrEmpty, Concat (والمعامل +).
الدوال الرياضية: تُترجَم طرق Math وMathF القياسية إلى ما يقابلها في ClickHouse — بما يشمل الدوال الحسابية واللوغاريتمية والمثلثية ودوال الأدوات المساعدة.
دلالات NULL في LEFT JOIN
set_join_use_nulls=1 تلقائيًا في كل مسار اتصال لمواءمة توقّعات Entity Framework بشأن سلوك JOIN.
إذا كان خادم ClickHouse أو ملف التعريف لديك يمنع تغيير هذا الإعداد (على سبيل المثال، ملف تعريف بقيمة readonly=1)، فأوقِف هذا السلوك باستخدام:
null يعمل كما هو متوقع. استخدم مقارنات صريحة مع 0 / "" بدلًا من == null.
إدراج البيانات
SaveChanges واجهة برمجة تطبيقات InsertBinaryAsync الأصلية لبرنامج التشغيل — بترميز RowBinary مع ضغط GZip، وهو أكثر كفاءة بكثير من عبارات SQL ذات المعلمات:
Added إلى Unchanged بعد الحفظ، تمامًا كما يحدث مع أي موفّر آخر لـ EF Core.
يمكن ضبط حجم الدفعة (الافتراضي 1000):
الإدراج المجمّع
BulkInsertAsync بدلًا من SaveChanges. هذه طريقة امتداد لـ DbContext تتجاوز بالكامل متتبّع التغييرات في EF Core، وآلية حلّ الهوية، وإدارة الحالة — إذ تستدعي مباشرةً InsertBinaryAsync الخاصة ببرنامج التشغيل باستخدام ترميز RowBinary وضغط GZip.
وهذا يجعلها مناسبة لتحميل مجموعات بيانات كبيرة عندما لا تحتاج إلى تتبّع الكيانات بعد الإدراج:
IEnumerable<T> — إذ يمر عبر الكيانات دون تحميلها جميعًا إلى الذاكرة. قيمة الإرجاع هي عدد الصفوف المُدرجة. لا تُرفَق الكيانات بـ DbContext بعد الإدراج، لذلك لا يحدث انتقال في الحالة من Added إلى Unchanged.
التعدادات
Enum8/Enum16 في ClickHouse كخصائص string أو كأنواع enum في C#. وعند استخدام تعدادات C#، يُجري الموفّر التحويل تلقائيًا بين التعداد وتمثيله النصي:
تحويلات الأنواع المخصّصة
ValueConverter في EF Core تعيين الأنواع المخصّصة إلى أنواع يدعمها الموفّر بالفعل. ولا يرى الموفّر نوعك المخصّص مطلقًا، إذ يتولّى EF Core التحويل عند نقطة الفصل.
التحويل على مستوى كل خاصية:
تعليقات توضيحية لنوع العمود
string وint وDateTime وغيرها، يستنتج الموفّر نوع ClickHouse تلقائيًا. أمّا الأنواع ذات المعلمات والأغلفة، فيلزم تحديد نوع ClickHouse صراحةً.
استخدام التعليقات التوضيحية للبيانات (السمات):
OnModelCreating:
Array(Nullable(Int32)) وLowCardinality(Nullable(String)) مدعومة — إذ يفكّ الموفّر تغليف Nullable وLowCardinality تلقائيًا عند كل مستوى من مستويات التداخل.
أعمدة Variant وDynamic
Variant(T1, T2, ...) وDynamic النوع object في .NET. وبما أن object عام جدًا بحيث لا يتيح استنتاج النوع تلقائيًا، يجب التصريح بنوع التخزين صراحةً باستخدام .HasColumnType():
string وulong وulong[]).
أعمدة JSON
Json في ClickHouse، ويعيّنه إلى System.Text.Json.Nodes.JsonNode (بشكل أساسي) أو string (عبر ValueConverter تلقائي):
SaveChanges وBulkInsertAsync:
string مع نوع عمود Json — يطبّق الموفّر ValueConverter تلقائيًا:
- عدم ترجمة JSON path — لا يُترجَم
entity.Data["name"]في LINQ إلى صياغة SQLdata.nameالخاصة بـ ClickHouse. طبّق عامل التصفية على الأعمدة غير JSON وافحص JSON في الذاكرة. - دلالات NULL — يعيد JSON type في ClickHouse القيمة
{}(كائنًا فارغًا) لقيم NULL بدلًا من SQL NULL. - دقة الأعداد الصحيحة — يخزّن JSON في ClickHouse جميع الأعداد الصحيحة بصيغة
Int64. عند القراءة عبرJsonNode، استخدمGetValue<long>()بدلًا منGetValue<int>().
محركات الجداول
ToTable(name, t => ...) بأسلوب الاستدعاءات المتسلسلة. عند عدم ضبط أي محرك، يستخدم الموفّر MergeTree افتراضيًا، مع استمداد ORDER BY من المفتاح الأساسي للكيان.
بنود المحرّك:
WithOrderBy, WithPartitionBy, WithPrimaryKey, WithSampleBy, WithTtl, WithSettings. ترتبط جميعها بمنشئ المحرّك المُعاد من HasXxxEngine().
ميزات على مستوى العمود: HasCodec, HasTtl, HasComment, HasDefault — جميعها تدخل في عمليات الترحيل.
فهارس تخطي البيانات — عبر HasIndex(...).HasSkippingIndexType(...):
عمليات الترحيل
قيود الترحيل
وبالإضافة إلى عمليات الترحيل، لا يزال الموفّر لا يدعم أيضًا ما يلي:
UPDATE/DELETE- المعاملات:
BeginTransactionعملية no-op. لا يوجد دعم لمعاملات ACID في ClickHouse. - ترجمة استعلامات JSON path:
entity.Data["key"]في LINQ لا يُترجم إلى صياغة SQL الخاصة بـ ClickHouse، أيdata.key. استخدم التصفية على أعمدة غير JSON وافحص JSON في الذاكرة.
القيود
أعمدة AggregateFunction
AggregateFunction(...) أو الإدراج فيها مباشرةً.
للإدراج: