الوصف
pg_clickhouse هو امتداد لـ PostgreSQL يتيح تنفيذ الاستعلامات عن بُعد على قواعد بيانات ClickHouse، بما في ذلك [مغلف البيانات الخارجية]. وهو يدعم PostgreSQL 14 والإصدارات الأحدث وClickHouse 23.3 والإصدارات الأحدث.البدء
أبسط طريقة لتجربة pg_clickhouse هي استخدام [صورة Docker]، والتي تتضمن صورة Docker القياسية لـ PostgreSQL، إلى جانب امتدادي pg_clickhouse و[re2][re2 extension]:الاستخدام
سياسة الإصدارات
يلتزم pg_clickhouse بـ[الإصدار الدلالي] في إصداراته العامة.- يُزاد الرقم الرئيسي للإصدار عند إجراء تغييرات على API
- يُزاد الرقم الثانوي للإصدار عند إجراء تغييرات SQL المتوافقة مع الإصدارات السابقة
- يُزاد رقم التصحيح عند إجراء تغييرات تقتصر على الملف التنفيذي
- إصدار المكتبة (المعرّف بواسطة
PG_MODULE_MAGICفي PostgreSQL 18 والإصدارات الأحدث) يتضمن الإصدار الدلالي الكامل، ويظهر في مخرجات الدالةpgch_version()أو دالة Postgrespg_get_loaded_modules(). - إصدار الامتداد (المعرّف في ملف التحكم) يتضمن فقط الرقمين الرئيسي
والثانوي، ويظهر في الجدول
pg_catalog.pg_extension، وفي مخرجات الدالةpg_available_extension_versions()، وفي\dx pg_clickhouse.
v0.1.0 إلى v0.1.1، يفيد جميع قواعد البيانات التي حمّلت v0.1، ولا
تحتاج إلى تشغيل ALTER EXTENSION للاستفادة من الترقية.
أما الإصدار الذي يزيد الرقم الثانوي أو الرئيسي، فسيكون
مصحوبًا بسكربتات ترقية SQL، ويجب على جميع قواعد البيانات الحالية التي تحتوي على
الامتداد تشغيل ALTER EXTENSION pg_clickhouse UPDATE للاستفادة من
الترقية.
مرجع DDL في SQL
تستخدم تعبيرات DDL التالية في SQL الامتداد pg_clickhouse.CREATE EXTENSION
استخدم CREATE EXTENSION لإضافة pg_clickhouse إلى إحدى قواعد البيانات:WITH SCHEMA لتثبيته في مخطط محدد (يوصى به):
ALTER EXTENSION
استخدم ALTER EXTENSION لتعديل pg_clickhouse. أمثلة:-
بعد تثبيت إصدار جديد من pg_clickhouse، استخدم العبارة
UPDATE: -
استخدم
SET SCHEMAلنقل الامتداد إلى مخطط جديد:
DROP EXTENSION
استخدم DROP EXTENSION لحذف pg_clickhouse من قاعدة بيانات:CASCADE لحذفها أيضًا:
CREATE SERVER
استخدم CREATE SERVER لإنشاء خادم خارجي يتصل بخادم ClickHouse. مثال:driver: مشغّل اتصال ClickHouse المراد استخدامه، إما “binary” أو “http”. مطلوب.compression: ضغط البروتوكول الأصلي لمشغّل “binary”، ويكون إحدى القيم “none” أو “lz4” أو “zstd”. القيمة الافتراضية هي “lz4”. ويتجاهله مشغّل “http”.dbname: قاعدة بيانات ClickHouse التي ستُستخدم عند الاتصال. القيمة الافتراضية هي “default”.host: اسم مضيف خادم ClickHouse. القيمة الافتراضية هي “localhost”;port: المنفذ المطلوب الاتصال به على خادم ClickHouse. تكون القيم الافتراضية كما يلي:- 9440 إذا كان
driverهو “binary” وكانhostمضيف ClickHouse Cloud - 9004 إذا كان
driverهو “binary” ولم يكنhostمضيف ClickHouse Cloud - 8443 إذا كان
driverهو “http” وكانhostمضيف ClickHouse Cloud - 8123 إذا كان
driverهو “http” ولم يكنhostمضيف ClickHouse Cloud
- 9440 إذا كان
min_tls_version: الحد الأدنى لإصدار بروتوكول TLS الذي يجب التفاوض عليه في الاتصالات التي تستخدم TLS. إحدى القيمTLSv1أوTLSv1.1أوTLSv1.2أوTLSv1.3. القيمة الافتراضية هي الحد الأدنى الذي تعتمده مكتبة TLS نفسها. وينطبق ذلك على كلا المشغّلين.secure: يحدّد استخدام TLS للاتصال. إحدى القيم التالية:auto(الافتراضي): استخدم TLS عندما يكونhostمضيف ClickHouse Cloud أو يكونportمنفذًا آمنًا؛ وإلا فاستخدم اتصالًا غير مشفّر.on(أوtrue/yes/1): استخدم TLS دائمًا. وتكون القيمة الافتراضية لـportهي 8443 (“http”) أو 9440 (“binary”).off(أوfalse/no/0): لا تستخدم TLS مطلقًا. وتكون القيمة الافتراضية لـportهي 8123 (“http”) أو 9000 (“binary”).
encoding_check: يحدّد طريقة التعامل مع المحارف غير الصالحة وفق [ترميز قاعدة البيانات] عند تحويل قيم String وJSON في ClickHouse. إحدى القيم التالية:fail(الافتراضي): يُطلق errorremove: يزيل البايتات غير الصالحةreplace: في ترميز UTF-8، يستبدل البايتات غير الصالحة بمحرف الاستبدال في Unicode (�)؛ ويعمل مثلremoveفي الترميزات الأخرىtruncate: يقتطع النص عند أول بايت غير صالح
ALTER SERVER
استخدم ALTER SERVER لتغيير خادم خارجي. مثال:DROP SERVER
استخدم DROP SERVER لإزالة خادم خارجي:CASCADE لكي
تُسقِط هذه التبعيات أيضًا:
CREATE USER MAPPING
استخدم CREATE USER MAPPING لربط مستخدم في PostgreSQL بمستخدم في ClickHouse. على سبيل المثال، لربط مستخدم PostgreSQL الحالي بمستخدم ClickHouse البعيد عند الاتصال بـ خادم خارجي taxi_srv:
user: اسم مستخدم ClickHouse. والقيمة الافتراضية هي “default”.password: كلمة مرور مستخدم ClickHouse.
ALTER USER MAPPING
استخدم ALTER USER MAPPING لتغيير تعريف تعيين المستخدم:DROP USER MAPPING
استخدم DROP USER MAPPING لحذف تعيين مستخدم:IMPORT FOREIGN SCHEMA
استخدم IMPORT FOREIGN SCHEMA لاستيراد جميع الجداول المعرَّفة في قاعدة بيانات ClickHouse كجداول خارجية إلى مخطط PostgreSQL:LIMIT TO لحصر الاستيراد في جداول محددة:
EXCEPT لاستثناء الجداول:
-
تحتفظ الأعمدة المستوردة بمُعدِّل النوع الخاص بنوع ClickHouse، بما في ذلك
المُعدِّلات داخل
Array. بعبارة أخرى، يُستوردArray(Decimal(12,6))بالصيغةnumeric(12,6)[]. -
تُستورد أعمدة
NullableدونNOT NULL؛ أمّاNullableداخلArrayفلا ينطبق عليه ذلك، لأن مصفوفات PostgreSQL تسمح دائمًا بعناصر NULL. -
تُستورد أعمدة
AggregateFunctionوSimpleAggregateFunctionدونNOT NULLبغض النظر عن تعريفها في ClickHouse، راجع أعمدة الحالة andNOT NULL. -
تُستورد أعمدة
Tupleبالصيغةtext[]. وتُستورد أعمدةMapوأعمدةNestedالمُنشأة باستخدامflatten_nested=0بالصيغةtext[][]. ويُصدر كل تحويل إشعارNOTICE. ونظرًا لأنه لا يمكن استخدام النوع الزائفrecordفي PostgreSQL لتعريف عمود جدول، تصبح كل Tuple مصفوفة من القيم، وتصبح كل Map مصفوفة ثنائية الأبعاد من أزواج المفتاح-القيمة، وتصبح كل قيمة Nested مصفوفة ثنائية الأبعاد من الصفوف. لقراءة الحقول كسجلات، عدّل العمود إلى مصفوفة من نوع مركّب مطابق، وراجع Manual Type Mappings للاطلاع على مثال. -
تُطلق أعمدة
DateTime64وTime64ذات الدقة الأكبر من 6 (ميكروثانية) أيضًا إشعارNOTICE، لأن PostgreSQL يحدّ الدقة القصوى بـtimestamp(6)وtime(6). -
تؤدي أنواع الأعمدة التي ليس لها نظير في PostgreSQL إلى حدوث خطأ، بما في ذلك النوع القديم
Object('json')الذي سبق ظهورJSONفي ClickHouse.
CREATE FOREIGN TABLE
استخدم CREATE FOREIGN TABLE لإنشاء جدول خارجي يتيح الاستعلام عن البيانات من قاعدة بيانات ClickHouse:database: اسم قاعدة البيانات البعيدة. تكون القيمة الافتراضية هي قاعدة البيانات المعرّفة للخادم الخارجي.table_name: اسم الجدول البعيد. تكون القيمة الافتراضية هي الاسم المحدد للجدول الخارجي.engine: [محرك الجدول] المستخدم في جدول ClickHouse. بالنسبة إلىCollapsingMergeTree()وAggregatingMergeTree()، يطبّق pg_clickhouse المعلمات تلقائيًا على تعبيرات الدوال التي تُنفَّذ على الجدول.
-
column_name: اسم العمود على جهة ClickHouse، ويُستخدم بدلًا من اسم السمة في PostgreSQL عند إعادة توليد الاستعلامات و عمليات الإدراج. وهو مفيد لربط أسماء أعمدة PostgreSQL المكتوبة بأحرف صغيرة وغير الموضوعة بين علامتَي اقتباس بأعمدة ClickHouse الحساسة لحالة الأحرف، على سبيل المثال: -
AggregateFunction: اسم الدالة التجميعية المطبَّقة على عمود من [نوع AggregateFunction]. اربط نوع البيانات بنوع ClickHouse المُمرَّر إلى الدالة، وحدد اسم الدالة التجميعية عبر خيار العمود المناسب، وسيضيف pg_clickhouse تلقائيًاMergeإلى الدالة التجميعية التي تقيّم العمود. عرّف العمود على أنه يقبل القيم الفارغة (nullable) لتجنّب المشكلات الموضّحة في أعمدة الحالة وNOT NULL. -
SimpleAggregateFunction: اسم الدالة التجميعية المطبَّقة على عمود من [نوع SimpleAggregateFunction]. اربط نوع البيانات بنوع ClickHouse المُمرَّر إلى الدالة، وحدد اسم الدالة التجميعية عبر خيار العمود المناسب.
أعمدة الحالة وNOT NULL
احرص على إبقاء أعمدة AggregateFunction وSimpleAggregateFunction قابلة لقيم NULL (nullable).
إذ يستبدل PostgreSQL 19 الاستدعاء count(column) بـ count(*) في أعمدة الحالة المعرّفة بـ NOT NULL،
فيُحتسب عدد الصفوف بدلًا من دمج الحالات.
لنأخذ مثلًا جدول ClickHouse يحتوي على حالة count واحدة لكل مستخدم، وكل حالة منها مبنية
من 1,000 حدث:
NOT NULL، يحتسب PostgreSQL صفوف الحالة (states) أيضًا، مما يؤدي إلى عدد غير صحيح:
NOT NULL، يستخدم pg_clickhouse الدالة countMerge() لدمج الحالات، فيُنتج
العدد الصحيح 1000:
ALTER FOREIGN TABLE لحذف القيد من جدول خارجي قائم:
NOT NULL على PostgreSQL وحده. ولذلك يستورد IMPORT FOREIGN
SCHEMA أعمدة الحالة على أنها تقبل القيم الفارغة (nullable).
ALTER FOREIGN TABLE
استخدم ALTER FOREIGN TABLE لتغيير تعريف جدول خارجي:DROP FOREIGN TABLE
استخدم DROP FOREIGN TABLE لإزالة جدول خارجي:CASCADE لحذفها أيضًا:
مرجع SQL لـ DML
قد تستخدم تعبيرات SQL DML الواردة أدناه pg_clickhouse. وتعتمد الأمثلة على جداول ClickHouse التالية:EXPLAIN
يعمل الأمر EXPLAIN كما هو متوقع، لكن الخيارVERBOSE يؤدي إلى
إظهار استعلام ClickHouse “Remote SQL”:
SELECT
استخدم عبارة SELECT لتنفيذ الاستعلامات على جداول pg_clickhouse، تمامًا كما تفعل مع أي جداول أخرى:nodes ونربط بها بدلًا من الجدول البعيد:
node_id بدلًا من العمود المحلي، ثم الربط
بجدول البحث لاحقًا:
node_id إلى النظام البعيد، مما يقلّل
عدد الصفوف التي يجب سحبها مرة أخرى إلى Postgres من 1000 (كلّها)
إلى 8 فقط، صف واحد لكل عقدة.
الجداول المُقسَّمة
يمكن أن يضم [جدول مُقسَّم] في PostgreSQL تقسيمات محلية وأخرى خارجية تستند إلى ClickHouse. ومن الأنماط الشائعة نقل البيانات الأقدم إلى ClickHouse، مع إبقاء البيانات الأحدث في PostgreSQL:enable_partitionwise_aggregate، ينفّذ PostgreSQL تجميعًا جزئيًا
أسفل Append، ثم تدمج عملية التجميع النهائي أعلاه هذه النتائج الجزئية في نتيجة واحدة.
ويدفع pg_clickhouse التجميع الجزئي للتقسيم الأجنبي إلى ClickHouse:
متى يُدفَع التجميع الجزئي إلى المصدر
يمثّل PostgreSQL التجميع الجزئي بوصفه حالة انتقالية تجمعها خطوة الإنهاء عبر الأقسام. لا يستطيع pg_clickhouse دفع التجميع الجزئي لقسم ما إلى المصدر إلا إذا أمكن تمثيله كقيمة في ClickHouse:- دوال التجميع القابلة للتفكيك التي تكون حالتها الانتقالية هي القيمة
النهائية بالفعل، تُدفَع مباشرةً إلى المصدر:
countوsumوminوmaxوbool_and/everyوbool_orوbit_andوbit_orوbit_xor. - تُدفَع
avgعلى الأعداد الصحيحة إلى المصدر بحالتها{count, sum}على شكل مصفوفة. - تُدفَع
avgوvar_popوvar_sampوstddev_popوstddev_sampعلى الأعداد ذات الفاصلة العائمة إلى المصدر بحالتها{N, sum, sum of squared deviations}على شكل مصفوفة.
FILTER (WHERE …) إلى المصدر مع دوال التجميع هذه.
الحالات التي تلجأ فيها إلى البديل
لا يتوفر للتجميعات التي تكون حالة انتقالها من نوع PostgreSQL المعتمinternal
تمثيل قابل للنقل، لذا يجلب القسم الخارجي صفوفها ويجمعها محليًا بدلًا من ذلك.
يشمل ذلك كل ما يتعلق بـ numeric، إضافةً إلى avg(bigint) وavg(interval).
كما تلجأ تجميعات DISTINCT وتجميعات المجموعات المرتبة والتجميعات متغيرة الوسائط إلى البديل.
PREPARE, EXECUTE, DEALLOCATE
اعتبارًا من الإصدار v0.1.2، يدعم pg_clickhouse الاستعلامات المعلَّمة بمعلمات، ويُنشأ معظمها باستخدام الأمر PREPARE:{param:type}:
INSERT
استخدم الأمر INSERT لإدراج القيم في جدول ClickHouse موجود على خادم بعيد:COPY
استخدم الأمر COPY لإدراج دفعة من الصفوف في جدول ClickHouse على خادم بعيد:⚠️ قيود Batch API لم يوفّر pg_clickhouse بعد دعم واجهة insert الدُفعية الخاصة بـ PostgreSQL FDW. لذلك يستخدم COPY حاليًا عبارات INSERT من أجل إدراج السجلات. وسيُحسَّن ذلك في إصدار مستقبلي.
LOAD
استخدم LOAD لتحميل المكتبة المشتركة pg_clickhouse:SET
استخدم SET لتعيين معلمات الإعداد المخصّصة لـ pg_clickhouse.pg_clickhouse.session_settings
تُستخدم المعلمة pg_clickhouse.session_settings لتحديد [إعدادات
ClickHouse] التي ستُطبَّق على الاستعلامات اللاحقة. مثال:
join_use_nulls لعمليات الربط الخارجي وtransform_null_in لفئة IN
(راجع دلالات IN وNULL).
date_time_output_format: يتطلبhttp driverأن تكون قيمته “iso”format_tsv_null_representation: يتطلبhttp driverالقيمة الافتراضيةoutput_format_tsv_crlf_end_of_lineيتطلبhttp driverالقيمة الافتراضية
pg_clickhouse.session_settings؛ إما باستخدام [التحميل المسبق للمكتبة المشتركة] أو
ببساطة باستخدام أحد الكائنات في الامتداد لضمان تحميله.
pg_clickhouse.pushdown_regex
تتحكم المعلمة pg_clickhouse.pushdown_regex في ما إذا كان pg_clickhouse
يقوم بتمرير دوال التعبيرات النمطية والعوامل إلى النظام البعيد. ويحدث ذلك افتراضيًا؛
اضبط هذه المعلمة على false لمنع تمريرها إلى النظام البعيد:
ALTER ROLE
استخدم الأمرSET في ALTER ROLE لإجراء التحميل المسبق لـ pg_clickhouse
و/أو SET معلماته لأدوار محددة:
RESET في ALTER ROLE لإعادة ضبط التحميل المسبق لـ pg_clickhouse
و/أو المعلمات:
التحميل المسبق
إذا كان كل اتصال بـPostgres أو يكاد كل اتصال يحتاج إلى استخدام pg_clickhouse، ففكّر في استخدام [التحميل المسبق للمكتبات المشتركة] لتحميله تلقائيًا:session_preload_libraries
يُحمِّل المكتبة المشتركة مع كل اتصال جديد بـ PostgreSQL:
shared_preload_libraries
يحمّل المكتبة المشتركة إلى العملية الرئيسية لـ PostgreSQL عند بدء التشغيل:
أنواع البيانات
يعرض هذا الجدول التعيين المفضّل بين أنواع البيانات في ClickHouse وأنواع البيانات في PostgreSQL. يعتمد IMPORT FOREIGN SCHEMA على هذه التعيينات، ويستنتج منها معدِّلات الأنواع وأبعاد المصفوفات المناسبة. استخدم CREATE FOREIGN TABLE للتصريح بأنواع PostgreSQL بديلة. تسرد أهداف القراءة الإضافية التحويلات التي يدعمها المشغّلbinary علاوة على
التحويلات الصريحة في PostgreSQL. وتظل تلك التحويلات مسموحًا بها حتى في الخلايا الفارغة. ويجب أن
تكون القيم ضمن نطاق الأنواع الهدف. تخص هذه الأهداف عمليات القراءة فقط، أما عمليات الكتابة فتخضع
لقواعد تحويل مستقلة.
يمكن أيضًا قراءة أي عمود إلى
text أو varchar أو أي نوع string آخر. إذ تأخذ القيمة
نوع PostgreSQL المذكور أعلاه، ثم تُعرض عبر دالة الإخراج الخاصة بذلك
النوع. وعند قراءة string من ClickHouse إلى نوع نصي، يُتحقَّق من توافقه
مع ترميز قاعدة البيانات، لذا تؤدي البايتات التي لا يستطيع PostgreSQL قراءتها إلى إطلاق خطأ. صرِّح عن
عمود String أو FixedString أو Enum أو JSON بالنوع BYTEA لقراءة بايتاته كما
كتبها ClickHouse تمامًا.
يمكن للأنواع المتوافقة مع الإدخال قراءة السلاسل النصية باستخدام دالة الإدخال الخاصة بها في PostgreSQL.
ويجب أن تتطابق حقول الأنواع المركّبة وترتيبها. ولقراءة Tuple
بوصفه مصفوفة، يجب أن يكون كل حقل قابلًا للتحويل إلى نوع عنصر المصفوفة، ولا يجوز لأي حقل
أن يكون هو نفسه مصفوفة.
عند القراءة بوصفها مصفوفات، يستخدم Map صفًا واحدًا لكل زوج مفتاح-قيمة، ويستخدم Nested
صفًا واحدًا لكل سجل متداخل. ولقراءة Tuple بوصفه box، قدِّم نقطتين؛ وبوصفه
circle، قدِّم نقطة ونصف قطر؛ وبوصفه line، قدِّم ثلاثة معاملات.
وفيما يلي ملاحظات وتفاصيل إضافية.
تحويل الأنواع
مع مشغّلbinary، تستخدم الأنواع المفردة البديلة عمليات التحويل الصريحة في PostgreSQL
متى توفرت، وتُحوَّل عناصر المصفوفة إلى نوع العنصر
المُعلَن. أما التحويلات غير المدعومة والقيم الواقعة خارج النطاق فتؤدي إلى أخطاء.
مع أيٍّ من المشغّلين، يمكنك ربط أنواع Interval في ClickHouse بـ smallint أو integer
أو bigint لقراءة أعداد وحداتها وكتابتها. على سبيل المثال، تُربط القيمة 3 من نوع
IntervalDay بالعدد الصحيح 3. ويحافظ ربط
IntervalNanosecond بـ bigint على دقة النانوثانية، بينما يؤدي ربطه بـ
interval إلى اقتطاع القيمة إلى دقة الميكروثانية.
BYTEA
لا يوفر ClickHouse ما يعادل النوع BYTEA في PostgreSQL، غير أنه يتيح تخزين أي بايتات في النوع [String]. بوجه عام، ينبغي ربط سلاسل ClickHouse بالنوع [TEXT] في PostgreSQL، أما عند استخدام البيانات الثنائية فيُربط بالنوع BYTEA. مثال:SELECT الأخير:
FixedString(N) القيم القصيرة ببايتات فارغة (nul). ويُسقط عمود النص هذا الحشو في نهاية القيمة، بينما يحتفظ عمود BYTEA بكل بايت.
الأنواع المركّبة
Array
تُقابِل أنواع [Array] في ClickHouse مصفوفات PostgreSQL مباشرةً، وبدلالات مكافئة. ويكمن الاختلاف الرئيسي في أن المصفوفات متعددة الأبعاد في Postgres يجب أن تتألف من تعبيرات مصفوفات ذات أبعاد متطابقة. وتؤدي محاولة قراءة مصفوفة ClickHouse ذات أبعاد مختلفة، مثل[[1], [2,3]]،
إلى حدوث error.
يُفوَّض الوصول إلى عناصر المصفوفة عبر الفهرس إلى النظام البعيد حسب الاقتضاء، بما في ذلك الوصول عبر الفهرس
متعدد الأبعاد. أمثلة:
Map
لا يوفّر PostgreSQL أي نوع يقابل نوع [Map] في ClickHouse. ولذلك يربط pg_clickhouse أعمدة [Map] بالنوعtext[][]، بحيث يُمثَّل كل زوج مفتاح-قيمة
بمصفوفة مستقلة. ويعتمد IMPORT FOREIGN SCHEMA
هذا الربط أيضًا. كما يمكن إدراج قيم Map باستخدام INSERT على هيئة مصفوفات. إليك مثالًا:
يتطلب إدراج
Map استخدام المشغّل binary، الذي يستنتج أنواع الأعمدة
من خادم ClickHouse. أما المشغّل http فلا يفعل ذلك، ولذا يفتقر إلى
المعلومات اللازمة لتنسيق القيمة المناسبة وإدراجها.Tuple
وبالمثل، تُطابَق أعمدة [Tuple] في ClickHouse مع النوعtext[]، وتدعم عمليات INSERT
عبر المشغّل الثنائي. ويُصدر IMPORT FOREIGN SCHEMA رسالة NOTICE عند إجراء
مثل هذه المطابقة.
Nested
يقسّم ClickHouse افتراضيًا عمودNested إلى عمود Array منفصل لكل
حقل (flatten_nested=1). ويقرأ IMPORT FOREIGN SCHEMA هذه الأعمدة من
catalog system.columns الخاص بـ ClickHouse، وينشئ أعمدة مصفوفات منفصلة في PostgreSQL،
مع الحفاظ على الأسماء التي تحتوي على نقاط مثل items.a وitems.b. فمثلًا،
لنفترض الجدول الأجنبي التالي:
WHERE باستخدام إمكانات المصفوفات المعتادة،
بما في ذلك صيغة الوصول إلى عناصر المصفوفة بالفهرس:
flatten_nested=0 مصفوفةً تضم عنصرًا واحدًا
لكل صف متداخل، ويحتوي كل عنصر في المصفوفة على قيم ذلك الصف:
c2 Nested(id Int64, name String) كما يلي:
text[][] عبر أنواع Nested يفشل:
مطابقة الأنواع يدويًا
يستخدمIMPORT FOREIGN SCHEMA أنواع PostgreSQL عامة الغرض. فعلى سبيل المثال،
لنفترض وجود جدول ClickHouse يحتوي على أعمدة من الأنواع [Enum] و[Tuple] وMap و
[Nested] غير المسطّحة (flatten_nested = 0)، مثل:
key وvalue في
هذه الحالة). ويتحوّل كلٌّ من Nested وMap إلى مصفوفات من القيم المركّبة، بينما يتحوّل Tuple
إلى قيمة مركّبة واحدة:
SELECT:
WHERE --- شريطة أن تكون أسماء الحقول
متطابقة:
INSERT باستخدام هذه الأنواع المركّبة حتى الآن.
مرجع الدوال والعوامل
الدوال
توفّر هذه الدوال واجهةً للاستعلام عن قاعدة بيانات ClickHouse.clickhouse_server_version
major.minor.patch، للخادم
الخارجي المُسمّى، مع الاتصال به عند الضرورة باستخدام خيارات الخادم وتعيين
المستخدم الخاص بالمستخدم الحالي:
SELECT version()، ويخزّنه مؤقتًا طوال مدة
الاتصال.
clickhouse_query
driver الخاص بالخادم،
وبيانات الاعتماد وقاعدة البيانات وذاكرة التخزين المؤقت للاتصال.
الوسيط الأول هو اسم خادم أُنشئ باستخدام CREATE SERVER. يجب توفير
قائمة تعريف columns (AS name(col type, ...)): يحتاج PostgreSQL إلى
معرفة بنية النتيجة قبل جلب الصفوف، ويجب أن تطابق columns التي يعيدها الاستعلام. تُحوَّل القيم
من ClickHouse إلى الأنواع المعلنة بالطريقة نفسها التي يُحوَّل بها column في جدول أجنبي.
أما العبارات التي لا تعيد نتائج، مثل DDL،
فلا تتطلب تعريفًا؛ نفّذها باستخدام
clickhouse_perform بدلًا من ذلك.
لا يملك أي دور صلاحية EXECUTE افتراضيًا؛ استخدم GRANT لمنح دور
إمكانية استخدام الدالة.
clickhouse_perform
clickhouse_query شكل نتيجة ليُصرَّح عنه. وتحدّد
الخادم بالطريقة نفسها التي يستخدمها clickhouse_query، مع إعادة استخدام
driver، وبيانات الاعتماد، وقاعدة البيانات، وذاكرة التخزين المؤقت للاتصال.
وبوصفها إجراءً، يجب استدعاؤها باستخدام CALL، وليس SELECT، ولا تُرجع
صفوفًا. لا يملك أي دور صلاحية EXECUTE افتراضيًا؛ استخدم GRANT لمنح دورٍ ما
صلاحية استخدام الإجراء.
دوال Pushdown
يقوم pg_clickhouse بتمرير مجموعة فرعية من دوال PostgreSQL المضمّنة المستخدمة في الشروط (البندينHAVING وWHERE). وتتوافق هذه المجموعة الفرعية مع
مكافئاتها في ClickHouse كما يلي:
abs: absfactorial: factorialmod(int2/int4/int8/numeric): modulopow&power(float8، وليس numeric): powround: roundsin,cos,tan,atan,atan2,sinh,cosh,tanh,asinh,degrees,radians,pi: دوال الرياضيات في ClickHouse التي تحمل الاسم نفسه. لا يتم pushdown للدوالasinوacosوatanhوacosh: إذ يُصدر PG خطأً عند إدخال قيم خارج النطاق، بينما يعيد CH القيمةNaN.date_part:date_part('day'): toDayOfMonthdate_part('doy'): toDayOfYeardate_part('dow'): toDayOfWeekdate_part('year'): toYeardate_part('month'): toMonthdate_part('hour'): toHourdate_part('minute'): toMinutedate_part('second'): toSeconddate_part('quarter'): toQuarterdate_part('isoyear'): toISOYeardate_part('week'): toISOYeardate_part('epoch'): toISOYear
date_trunc:date_trunc('week'): toMondaydate_trunc('second'): toStartOfSeconddate_trunc('minute'): toStartOfMinutedate_trunc('hour'): toStartOfHourdate_trunc('day'): toStartOfDaydate_trunc('month'): toStartOfMonthdate_trunc('quarter'): toStartOfQuarterdate_trunc('year'): toStartOfYear
extract(field FROM source): نفس التعيينات كما فيdate_partdate(timestamp)&date(timestamptz): toDate (تُفكّك إلى الاسم المستعارdateفي CH)array_position: indexOf مع nullIf لتحويل0إلىNULL، واستخدام arraySlice عند وجود وسيطة ثالثة تحدد فهرس بدء البحث؛ لاحظ أنnanلا يطابق حاليًا أي قيمةarray_cat: arrayConcatarray_append: arrayPushBackarray_prepend: arrayPushFrontarray_remove: arrayRemovecardinality: arrayFlattenedLength في ClickHouse 26.9+، وإلا فـ length، التي لا تحسب إلا عناصر المصفوفة الخارجيةarray_length(array, 1):nullIf(length(array), 0)array_length&cardinality: lengtharray_to_string: arrayStringConcatstring_to_array: splitByStringsplit_part: splitByString + فهرسة المصفوفةtrim_array: arrayResizearray_fill: arrayWithConstantarray_reverse: arrayReversearray_shuffle: arrayShufflearray_sample: arrayRandomSamplearray_sort: arraySort / arrayReverseSortbtrim: trimBothltrim: trimLeftrtrim: trimRightconcat_ws: concatWithSeparatorlower(text): lowerUTF8upper(text): upperUTF8substring(text, ...)&substr(text, ...): substringUTF8substring(bytea, ...)&substr(bytea, ...): substringlength(text): lengthUTF8length(bytea)&octet_length: lengthreverse(text): reverseUTF8reverse(bytea): reversestrpos: positionUTF8regexp_like: matchregexp_match: extractGroups إذا كان التعبير النمطي يحتوي على تعبيرات فرعية بين قوسين؛ وإلا extractAll ثم تُقتطع باستخدام arraySlice.regexp_replace: replaceRegexpOne أو replaceRegexpOne عند وجود العلامةgregexp_split_to_array: splitByRegexpmd5: MD5sha224وsha256وsha384وsha512: دوال SHA المقابلة في ClickHouseencode(bytea, fmt)عندما يكونfmtثابتًا نصيًا (دون تمييز بين حالة الأحرف):encode(bytea, 'hex'): hex مُغلّفة بـ lower، لأن PostgreSQL يُنتج قيم hex بأحرف صغيرة.encode(bytea, 'base64'): base64Encode مُغلّفة بـ replaceRegexpAll لمحاكاة فاصل الأسطر بتنسيق MIME (RFC 2045) في PostgreSQL كل 76 حرفًا.encode(bytea, 'base64url')(PostgreSQL 19+): base64URLEncode، التي تطابق أبجدية URL في PostgreSQL وفق RFC 4648 من دون padding.
json_extract_path_text: صياغة العمود الفرعيjson_extract_path: toJSONString + صياغة العمود الفرعيjsonb_extract_path_text: صياغة العمود الفرعيjsonb_extract_path: toJSONString + صياغة العمود الفرعيbit_count(bytea): bitCountto_timestamp(float8): toDateTime64to_char(timestamp[tz], fmt): formatDateTime عندما يكونfmtثابتًا نصيًا وكانت كل كلمة مفتاحية فيه لها مقابل مطابق في ClickHouse. راجع to_char() ضمن ملاحظات التوافق للاطلاع على الكلمات المفتاحية المدعومة. بخلاف ذلك، تُقيَّم الدالة محليًا في PostgreSQL.statement_timestamp,transaction_timestamp, &clock_timestamp: nowInBlock64 (nowInBlock64(9, $session_timezone))CURRENT_DATE: now و toDate (toDate(now($session_timezone)))now,CURRENT_TIMESTAMP, &LOCALTIMESTAMP: now64 (now64(9, $session_timezone))CURRENT_TIMESTAMP(n)&LOCALTIMESTAMP(n): now64 (now64(n, $session_timezone))CURRENT_DATABASE: تُمرَّر كقيمة من دالة PostgreSQL.CURRENT_SCHEMA: تُمرَّر كقيمة من دالة PostgreSQL.CURRENT_CATALOG: تُمرَّر كقيمة من دالة PostgreSQL.CURRENT_USER: تُمرَّر كقيمة من دالة PostgreSQL.USER: تُمرَّر كقيمة من دالة PostgreSQL.CURRENT_ROLE: تُمرَّر كقيمة من دالة PostgreSQL.SESSION_USER: تُمرَّر كقيمة من دالة PostgreSQL.
معاملات Pushdown
- شريحة Array (
arr[L:U]): arraySlice @>(تحتوي المصفوفة على): hasAll<@(المصفوفة محتواة في): hasAll&&(تداخل المصفوفات): hasAny~(مطابقة تعبير نمطي): match!~(عدم مطابقة تعبير نمطي): match~*(عدم مطابقة تعبير نمطي دون مراعاة حالة الأحرف): match!~*(عدم مطابقة تعبير نمطي دون مراعاة حالة الأحرف): match->>(استخراج عنصر من JSON/JSONB كنص): sub-column syntax->(استخراج من JSON/JSONB): toJSONString + sub-column syntax
دلالات IN وNULL
يقيّم ClickHouse التعبير IN وفق منطق ثنائي القيم: فعندما لا يجد الفحص
تطابقاً، يعيد 0 حتى عند وجود NULL، بينما يحسب PostgreSQL
NULL. وللحفاظ على دلالات PostgreSQL، يُجري pg_clickhouse pushdown لعائلة IN
عند استخدامها مع قائمة أو مصفوفة ثابتة (IN، NOT IN، = ANY، = ALL، <> ANY، <> ALL) دون استثناء: إما الصيغة الأصلية أو منخفضة التكلفة عندما يمكنه إثبات
أن لا قيمة الفحص ولا أي عنصر في المصفوفة يمكن أن يكون NULL، أو صيغة CASE محمية
في الحالات الأخرى تتحقق من قيم NULL وقت التشغيل، وتحسب
الإجابة الدقيقة ثلاثية القيم في PostgreSQL (TRUE، FALSE، NULL) في جميع السياقات،
بما في ذلك مواضع القيم مثل قائمة SELECT أو GROUP BY.
يُجرى أيضاً pushdown لعامل التصفية NOT IN (SELECT ...) المستخدم مع columns القابلة لـNULL،
ويُعاد تحويله إلى نص مع حواجز تعويضية تحافظ على سلوك PostgreSQL: فالمجموعة
التي تحتوي على NULL تستبعد كل صف، ولا تنجح قيمة فحص NULL إلا
مع مجموعة فارغة. يُحذف كل حاجز عندما يثبت تعريف NOT NULL
عدم الحاجة إليه. وعلى خلاف صيغ المصفوفة أعلاه، لا ينطبق هذا الحاجز إلا في شرط تصفية
عادي (أو تحت NOT)؛ وما زلنا لا نُجري pushdown لـ IN (SELECT ...)
(في موضع قيمة)، ولا أجسام الاستعلامات الفرعية المجمّعة أو المجمّعة تجميعياً. يؤدي تعريف
columns بأنها NOT NULL إلى زيادة pushdown إلى أقصى حد، إذ يتيح إرسال الصيغة الأرخص غير المحمية
بدلاً من ذلك؛ ويطبّق IMPORT FOREIGN SCHEMA هذا تلقائياً على columns في ClickHouse غير Nullable.
ويتتبع الإثبات الثوابت غير NULL، وcolumns المعرّفة بـ NOT NULL،
والعمليات الحسابية الأساسية (+، -، *، و- الأحادية) عليها.
تفترض هذه القواعد الإعداد الافتراضي في ClickHouse، وهو transform_null_in = 0، الذي
يضبطه pg_clickhouse لكل استعلام عبر القيمة الافتراضية للمعلمة
pg_clickhouse.session_settings
حتى لا يتمكن ملف تعريف خادم ClickHouse من تغييره بصمت. يؤدي ضبط
transform_null_in = 1 إلى الإخلال بدلالات كل تعبير IN يُجرى له pushdown.
الدوال المخصصة
توفّر هذه الدوال المخصصة التي أنشأها pg_clickhouse دعم pushdown للاستعلامات الخارجية لبعض دوال ClickHouse التي لا يوجد لها ما يكافئها في PostgreSQL. وإذا تعذّر تطبيق pushdown على أيٍّ من هذه الدوال، فسيُرفع استثناء.Pushdown الامتدادات
يتعرّف pg_clickhouse على الدوال في بعض الامتدادات الأساسية وامتدادات الجهات الخارجية، ويُمرِّر تنفيذها إلى ما يقابلها في ClickHouse.re2
تُمرَّر جميع معاملات ودوال [امتداد re2] مباشرةً إلى ClickHouse بنسبة 1:1:@~→ matchre2match→ matchre2extract→ extractre2extractall→ extractAllre2regexpextract→ regexpExtractre2extractgroups→ extractGroupsre2replaceregexpone→ replaceRegexpOnere2replaceregexpall→ replaceRegexpAllre2countmatches→ countMatchesre2countmatchescaseinsensitive→ countMatchesCaseInsensitivere2multimatchany→ multiMatchAnyre2multimatchanyindex→ multiMatchAnyIndexre2multimatchallindices→ multiMatchAllIndices
intarray
تُنفَّذ إحدى دوال [intarray] مباشرةً في ClickHouse:idx→ indexOf
fuzzystrmatch
يمكن تمرير دالتين من [fuzzystrmatch] إلى ClickHouse:soundex: soundexlevenshtein(بوسيطتين): editDistanceUTF8
pgcyrpto
digest(text, text)وdigest(bytea, text): تُقابِلهما دالة التجزئة المناظرة في ClickHouse عندما تكون الخوارزمية قيمةً ثابتة من بينmd5أوsha1أوsha224أوsha256أوsha384أوsha512(تُطابَق دون حساسية لحالة الأحرف).
عمليات CAST ذات pushdown
يقوم pg_clickhouse بتنفيذ pushdown لعمليات CAST مثلCAST(x AS bigint) عند استخدام
أنواع بيانات متوافقة. أما مع الأنواع غير المتوافقة، فستفشل عملية الـ pushdown؛
فإذا كانت x في هذا المثال من نوع ClickHouse UInt64، فسيرفض ClickHouse
تحويل القيمة.
ولتنفيذ pushdown لعمليات CAST لأنواع البيانات غير المتوافقة، يوفّر pg_clickhouse
الدوال التالية. وهي تثير استثناءً في PostgreSQL إذا لم يُنفَّذ لها pushdown.
دوال التجميع التي تدعم pushdown
تدعم دوال التجميع التالية في PostgreSQL آلية pushdown إلى ClickHouse.- any_value
- array_agg
- avg
- bit_and
- bit_or
- bit_xor
- bool_and / every
- bool_or
- count
- corr
- covarpop
- covarsamp
- min
- max
- stddev_pop
- stddev_samp / stddev
- string_agg
- sum
- var_op
- var_samp /variance
دوال التجميع المخصصة
توفّر دوال التجميع المخصصة هذه، التي أنشأها pg_clickhouse، إمكانية pushdown للاستعلامات الخارجية لبعض دوال التجميع في ClickHouse التي لا يقابلها ما يعادلها في PostgreSQL. وإذا تعذر pushdown لأي من هذه الدوال، فسيُرفَع استثناء.Pushdown دوال التجميع المرتبة حسب المجموعة
تُطابِق دوال [دوال التجميع للمجموعات المرتبة] هذه دوال [دوال التجميع ذات المعلمات] في ClickHouse، وذلك بتمرير المعامل المباشر الخاص بها كـ parameter، وتمرير تعبيراتORDER BY الخاصة بها على أنها arguments. على سبيل المثال، query PostgreSQL هذه:
DESC وNULLS FIRST في ORDER BY
غير مدعومتين، وستؤديان إلى ظهور خطأ.
percentile_cont(double): quantilepercentile_cont(double[]): quantilespercentile_disc(double): quantileExactLowpercentile_disc(double[]): quantilesExactLow
دوال التجميع المخصصة للمجموعات المرتبة
توفر دوال [دوال التجميع للمجموعات المرتبة] المخصصة هذه، التي أنشأها pg_clickhouse، إمكانية pushdown الاستعلامات الخارجية لبعض دوال [دوال التجميع ذات المعلمات] في ClickHouse. إذا تعذر pushdown أي من هذه الدوال، فستُطلق استثناءً.quantile(double): quantilequantileExact(double): quantileExact
دوال التجميع المخصصة للمجموعات المرتبة
توفّر دوال [دوال التجميع للمجموعات المرتبة] المخصصة هذه، التي أنشأتها pg_clickhouse، ميزة pushdown الاستعلامات الخارجية لتنفيذ دوال ClickHouse [دوال التجميع ذات المعلمات]. وإذا تعذّر pushdown أي من هذه الدوال، فستُطلق استثناءً.دوال النافذة pushdown
تخضع دوال النافذة التالية في PostgreSQL لـ pushdown إلى ClickHouse باستخدام عباراتOVER (PARTITION BY ... ORDER BY ...)، بما في ذلك مواصفات الإطار
عند الاقتضاء.
- row_number
- rank
- dense_rank
- ntile
- cume_dist
- percent_rank
- lead
- lag
- first_value
- last_value
- nth_value
min/max(مع عبارةOVER)
row_number وrank وdense_rank وntile وcume_dist
وpercent_rank) عبارة الإطار الخاصة بها عند pushdown، لأن ClickHouse
لا يقبل مواصفات الإطار لهذه الدوال.
ملاحظات حول التوافق
التعبيرات النمطية
مع أن pg_clickhouse يحوّل التعبيرات النمطية إلى ما يكافئها في ClickHouse عندما تكون pg_clickhouse.pushdown_regex مضبوطة على true (وهو الإعداد الافتراضي)، ويسعى إلى ضمان حدٍّ أساسي من التوافق، فاحرص على فهم الاختلافات بينهما وكيفية تعامل pg_clickhouse معها.-
يدعم PostgreSQL [التعبيرات النمطية وفق POSIX] بينما يدعم ClickHouse
[التعبيرات النمطية وفق RE2][RE2]. انتبه إلى اختلافات السلوك: استخدم RE2
عندما يتولى ClickHouse تقييم التعبير النمطي (على سبيل المثال، في
عبارة
WHERE) واستخدم POSIX عندما يتولى Postgres تقييمه (على سبيل المثال، في عبارةSELECT). -
يقوم pg_clickhouse بتمرير [مُعدِّلات Postgres] إلى التعبير النمطي في ClickHouse عبر إضافتها في بدايته داخل
(?). على سبيل المثال:يصبح -
خيارات سطر الأوامر الوحيدة التي يدعمها كلاهما، والتي يمكن بالتالي استخدامها عند تقييمها من قِبل
ClickHouse، هي:
لا يدعم RE2 سوى هذه العلامات؛ لا تستخدم أيًا من [علامات Postgres] الأخرى.
-
يلخّص هذا الجدول تأثير العلامات المختلفة (وكذلك عدم استخدام أي علامة،
وهو ما يعادل
s) عند مطابقة الأسطر الجديدة ونهايات الأسطر. لاحظ أنه في Postgres، تمنعmوpفئات المحارف المنفية ([^xyz]) من مطابقة سطر جديد، بينما لا تفعل نظيراتها في ClickHouse ذلك. وبخلاف ذلك، فإن السلوكيات في ClickHouse وPostgres متماثلة: - أي خيارات أخرى تُمرَّر إلى دوال التعبيرات النمطية ستمنع تنفيذ الدالة على المصدر البعيد.
-
الاستثناء هو
regexp_replace()، إذ يدعم أيضًا الخيارg. وعندما يكونgمفعّلًا، يستخدم pg_clickhousereplaceRegexpAll()بدلًا منreplaceRegexpOne()ويزيل هذا الخيار قبل إضافة الخيارات الأخرى كبادئة. -
تدعم وسيطة الاستبدال في
regexp_replace()في Postgres الرمز\&للإشارة إلى المطابقة بالكامل، بينما يدعم ClickHouse الرمز\0للمطابقة بالكامل. احرص على استخدام\0عندما تُنفَّذ الدالة في ClickHouse. -
تعيد
regexp_matchفي Postgres القيمةNULLعند عدم وجود أي تطابقات، بينما تعيد التعبيرات التي يُدفَع تنفيذها إلى النظام البعيد مصفوفة فارغة. استخدمCOALESCE()لإرجاع مصفوفة فارغة بدلًا منNULLحتى تتمكن من مقارنة القيم المعادة بشكل متوافق. على سبيل المثال:
to_char()
لا يُجرى pushdown لـ PostgreSQL [to_char()] الخاص بـ timestamp وtimestamp with time zone
إلى ClickHouse [formatDateTime] إلا عندما تكون وسيطة التنسيق
ثابتًا نصيًا غير NULL، ويكون لكل رمز في PostgreSQL
مكافئ مماثل تمامًا على مستوى البايت في ClickHouse. وإذا كان التنسيق ديناميكيًا أو كان
يحتوي على أي رمز أو modifier غير مدعوم، فإن الاستدعاء يعود إلى التقييم المحلي في
PostgreSQL. ولا يُجري pg_clickhouse مطلقًا pushdown لترجمة جزئية، ولذلك يظل الناتج
متوافقًا.
أما صيغ to_char() ذات الوسيطتين المطبَّقة على numeric وinterval وأنواع
أخرى غير timestamp، فلا يُجرى لها pushdown مطلقًا؛ إذ إن ClickHouse [formatDateTime] لا
ينسّق إلا قيم التاريخ والوقت.
الرموز المترجمة
النصوص المقتبسة والقيم الحرفية
النص المحاط بـ"..." يُمرَّر كما هو حرفيًا، مع مضاعفة أي % حرفية
إلى %% لتحييد بادئة المحدِّد في ClickHouse. كذلك، فإن \" خارج علامات
الاقتباس يُمرَّر أيضًا باعتباره " حرفيًا. وداخل "..."، لا يُستخدم
backslash إلا لإلغاء المعنى الخاص لـ "؛ أما تسلسلات backslash الأخرى
فتُعامَل كنص حرفي.
المؤلفون
David E. Wheelerحقوق الطبع والنشر
حقوق الطبع والنشر (c) 2025-2026، ClickHouse [Array] https://clickhouse.com/docs/reference/data-types/array “ClickHouse Docs: Array(T)” [Map]: https://clickhouse.com/docs/sql-reference/data-types/map “ClickHouse Docs: Map” [Tuple]: https://clickhouse.com/docs/reference/data-types/tuple “ClickHouse Docs: Tuple(T1, T2, …)” [Nested]: https://clickhouse.com/docs/sql-reference/data-types/nested-data-structures/nested “ClickHouse Docs: Nested” [Enum]: https://clickhouse.com/docs/reference/data-types/enum “ClickHouse Docs: Enum” [String]: /reference/data-types/string “ClickHouse Docs: String” [TEXT]: https://www.postgresql.org/docs/current/datatype-character.html “PostgreSQL Docs: أنواع المحارف” [window functions]: https://www.postgresql.org/docs/current/functions-window.html “PostgreSQL Docs: دوال النافذة” [POSIX Regular Expressions]: https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-POSIX-REGEXP “PostgreSQL Docs: تعبيرات POSIX النمطية” [Postgres flags]: https://www.postgresql.org/docs/current/functions-matching.html#POSIX-EMBEDDED-OPTIONS-TABLE “PostgreSQL Docs: أحرف الخيارات المضمّنة ARE” [RE2]: https://github.com/google/re2/wiki/Syntax “بناء جملة RE2” [re2 extension]: https://github.com/ClickHouse/pg_re2 “pg_re2: دوال تعبيرات نمطية متوافقة مع ClickHouse باستخدام RE2” [intarray]: https://www.postgresql.org/docs/current/intarray.html “PostgreSQL Docs: intarray” [fuzzystrmatch]: https://www.postgresql.org/docs/current/fuzzystrmatch.html “PostgreSQL Docs: fuzzystrmatch” [to_char()]: https://www.postgresql.org/docs/current/functions-formatting.html “PostgreSQL Docs: دوال تنسيق أنواع البيانات”
[formatDateTime]: /reference/functions/regular-functions/date-time-functions#formatDateTime “ClickHouse Docs: formatDateTime”