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

> يتيح محرك PostgreSQL تنفيذ استعلامات `SELECT` و`INSERT` على البيانات المخزنة على خادم PostgreSQL بعيد.

# محرك الجدول PostgreSQL

يتيح محرك PostgreSQL تنفيذ استعلامات `SELECT` و`INSERT` على البيانات المخزنة على خادم PostgreSQL بعيد.

<Note>
  حاليًا، لا يدعم محرك الجدول PostgreSQL هذا إلا PostgreSQL بالإصدار 12 فما فوق.
</Note>

<Tip>
  اطّلع على خدمة [ClickHouse Managed Postgres](/ar/products/managed-postgres/overview) الخاصة بنا. فهي تعتمد على تخزين NVMe موجود فعليًا إلى جانب موارد الحوسبة، ما يوفّر أداءً أسرع حتى 10 مرات لأحمال العمل المقيّدة بأداء القرص مقارنةً بالبدائل التي تستخدم تخزينًا متصلًا بالشبكة مثل EBS، كما تتيح لك نسخ بيانات Postgres إلى ClickHouse باستخدام موصل Postgres CDC في ClickPipes.
</Tip>

## إنشاء جدول

```sql theme={null}
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 type1 [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 type2 [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = PostgreSQL({host:port, database, table, user, password[, schema, [, on_conflict]] | named_collection[, option=value [,..]]})
SETTINGS
    [ postgresql_connection_pool_size=16, ]
    [ postgresql_connection_pool_wait_timeout=5000, ]
    [ postgresql_connection_pool_retries=2, ]
    [ postgresql_connection_pool_auto_close_connection=false, ]
    [ postgresql_connection_attempt_timeout=2 ]
;
```

راجع وصفًا مفصلًا لاستعلام [CREATE TABLE](/ar/reference/statements/create/table).

يمكن أن تختلف بنية الجدول عن بنية جدول PostgreSQL الأصلي:

* يجب أن تكون أسماء الأعمدة مطابقة لما هي عليه في جدول PostgreSQL الأصلي، ولكن يمكنك استخدام بعض هذه الأعمدة فقط وبأي ترتيب.
* قد تختلف أنواع الأعمدة عن تلك الموجودة في جدول PostgreSQL الأصلي. يحاول ClickHouse [cast](/ar/reference/engines/database-engines/postgresql#data_types-support) القيم إلى أنواع بيانات ClickHouse.
* يحدّد الإعداد [external\_table\_functions\_use\_nulls](/ar/reference/settings/session-settings/external-table#external_table_functions_use_nulls) كيفية التعامل مع الأعمدة Nullable. القيمة الافتراضية: 1. إذا كانت القيمة 0، فلن تُنشئ دالة الجدول أعمدة Nullable، وستُدرج القيم الافتراضية بدلًا من قيم NULL. وينطبق هذا أيضًا على قيم NULL داخل المصفوفات.

**معلمات المحرك**

* `host:port` — عنوان خادم PostgreSQL.
* `database` — اسم قاعدة البيانات البعيدة.
* `table` — اسم الجدول البعيد، أو استعلام يُمرَّر إلى PostgreSQL كما هو (راجع [تمرير استعلام بدلًا من اسم جدول](#passing-a-query)).
* `user` — مستخدم PostgreSQL.
* `password` — كلمة مرور المستخدم.
* `schema` — مخطط الجدول غير الافتراضي. اختياري.
* `on_conflict` — استراتيجية حل التعارض. مثال: `ON CONFLICT DO NOTHING`. اختياري. ملاحظة: ستؤدي إضافة هذا الخيار إلى جعل الإدراج أقل كفاءة.

يُنصح باستخدام [المجموعات المسماة](/ar/concepts/features/configuration/server-config/named-collections) (المتاحة منذ الإصدار 21.11) في بيئة الإنتاج. إليك مثالًا:

```xml theme={null}
<named_collections>
    <postgres_creds>
        <host>localhost</host>
        <port>5432</port>
        <user>postgres</user>
        <password>****</password>
        <schema>schema1</schema>
    </postgres_creds>
</named_collections>
```

يمكن تجاوز بعض المعلمات باستخدام وسيطات المفتاح-القيمة:

```sql theme={null}
SELECT * FROM postgresql(postgres_creds, table='table1');
```

### TLS/SSL

تُمرَّر معلمات TLS/SSL إلى `libpq`، ويمكن ضبطها كمفاتيح في مجموعة مُسمّاة أو كوسيطات مفتاح-قيمة لاحقة: `sslmode` (`disable` أو `allow` أو `prefer` أو `require` أو `verify-ca` أو `verify-full`)، بالإضافة إلى الشهادات والمفتاح، بإحدى صيغتين. عند عدم تعيينها، تُستخدم القيم الافتراضية لـ `libpq` (`sslmode=prefer`).

* `sslrootcert` (شهادة CA، أو القيمة الخاصة `system`) و`sslcert` (شهادة العميل) و`sslkey` (المفتاح الخاص للعميل) هي مسارات لملفات محلية على الخادم. لا يمكن تحديدها إلا ضمن مجموعة مُسمّاة معرّفة في ملف تهيئة الخادم، ولا يمكن تجاوزها في استعلام، إذ يفتح الخادم الملفات بصلاحياته الخاصة.
* تقبل `sslrootcert_pem` و`sslcert_pem` و`sslkey_pem` المحتوى الحرفي للملف المقابل بدلاً من مساره. ويمكن تحديدها في أي مكان — في استعلام، أو في مجموعة مُسمّاة أُنشئت باستخدام SQL، أو كتجاوز لمجموعة مُسمّاة — وتُحجب في السجلات واستعلامات `SHOW` كما تُحجب كلمة المرور.

على سبيل المثال، لفرض اتصال مشفّر والتحقق من شهادة الخادم:

```xml theme={null}
<named_collections>
    <postgres_creds>
        <host>localhost</host>
        <port>5432</port>
        <user>postgres</user>
        <password>****</password>
        <sslmode>verify-full</sslmode>
        <sslrootcert>/etc/clickhouse-server/postgresql-ca.crt</sslrootcert>
    </postgres_creds>
</named_collections>
```

الأمر نفسه دون استخدام ملف إعدادات، مع تمرير محتوى الشهادة في الاستعلام:

```sql theme={null}
CREATE TABLE postgres_table (id UInt64, value String)
ENGINE = PostgreSQL('localhost:5432', 'database', 'table', 'user', 'password',
                    sslmode = 'verify-full', sslrootcert_pem = '-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----');
```

## الإعدادات

يمكن تهيئة مجمّع الاتصالات الذي يستخدمه محرك الجدول `PostgreSQL` (ودالة الجدول [`postgresql`](/ar/reference/functions/table-functions/postgresql)) لكل جدول على حدة باستخدام عبارة `SETTINGS`. وعند عدم تحديد إعداد معيّن، تُستخدم تلقائيًا قيمة إعداد `postgresql_*` المقابل على مستوى الاستعلام.

### `postgresql_connection_pool_size`

حجم مجمّع الاتصالات (إذا كانت جميع الاتصالات قيد الاستخدام، ينتظر الاستعلام حتى يصبح أحد الاتصالات متاحًا). يجب أن تكون القيمة غير صفرية.

القيمة الافتراضية: `16`.

### `postgresql_connection_pool_wait_timeout`

مهلة انتظار push/pop لمجمع الاتصالات، بالمللي ثانية، عندما يكون المجمع فارغًا. تعني القيمة `0` أنه يتم الحظر عند فراغ المجمع.

القيمة الافتراضية: `5000`.

### `postgresql_connection_pool_retries`

عدد مرات إعادة المحاولة لعمليتَي push/pop في مجمع الاتصالات.

القيمة الافتراضية: `2`.

### `postgresql_connection_pool_auto_close_connection`

أغلق الاتصال قبل إعادته إلى مجمّع الاتصالات.

القيمة الافتراضية: `false`.

### `postgresql_connection_attempt_timeout`

مهلة الاتصال، بالثواني، لمحاولة واحدة للاتصال بنقطة نهاية PostgreSQL. تُمرَّر القيمة كمعلمة `connect_timeout` في عنوان URL الخاص بالاتصال.

القيمة الافتراضية: `2`.

مثال:

```sql theme={null}
CREATE TABLE pg_table
(
    `float_nullable` Nullable(Float32),
    `str` String,
    `int_id` Int32
)
ENGINE = PostgreSQL('localhost:5432', 'public', 'test', 'postgres_user', 'postgres_password')
SETTINGS postgresql_connection_pool_size = 32, postgresql_connection_pool_auto_close_connection = 1;
```

## تفاصيل التنفيذ

تُنفَّذ استعلامات `SELECT` على جانب PostgreSQL بصيغة `COPY (SELECT ...) TO STDOUT` داخل معاملة PostgreSQL للقراءة فقط، مع تنفيذ `commit` بعد كل استعلام `SELECT`.

تُنفَّذ عبارات `WHERE` البسيطة مثل `=`, `!=`, `>`, `>=`, `<`, `<=`, و`IN` على خادم PostgreSQL.

تُنفَّذ جميع عمليات `JOIN`، وعمليات التجميع، والفرز، وشروط `IN [ array ]`، وقيد أخذ العينات الخاص بـ `LIMIT` في ClickHouse فقط بعد اكتمال الاستعلام إلى PostgreSQL.

## تمرير استعلام بدلًا من اسم جدول

بدلًا من اسم جدول، يمكن أن تكون الوسيطة `table` استعلام `SELECT` يُمرَّر إلى PostgreSQL كما هو. ويُستدل على بنية الجدول من نتيجة الاستعلام. ويمكن كتابة الاستعلام إما كاستعلام فرعي، أو تغليفه داخل الدالة `query`:

```sql theme={null}
CREATE TABLE pg_table ENGINE = PostgreSQL('localhost:5432', 'test', (SELECT a, b FROM t1 JOIN t2 USING (id) WHERE a > 0), 'user', 'password');
CREATE TABLE pg_table ENGINE = PostgreSQL('localhost:5432', 'test', query('SELECT a, b FROM t1 JOIN t2 USING (id) WHERE a > 0'), 'user', 'password');
```

يُعد هذا مفيدًا لدفع تنفيذ عمليات `JOIN` وعمليات التجميع أو أي معالجة أخرى إلى PostgreSQL. هذا الجدول للقراءة فقط: لا يُسمح بتنفيذ `INSERT` فيه. وتدعم دالة الجدول [`postgresql`](/ar/reference/functions/table-functions/postgresql) الصياغة نفسها.

<Note>
  تُحلَّل صيغة الاستعلام الفرعي `(SELECT ...)` بواسطة ClickHouse، ثم يُعاد تسلسلها وفق لهجة PostgreSQL ‏(وضع علامات الاقتباس لمعرّفات PostgreSQL وإفلات القيم الحرفية النصية) قبل إرسالها إلى الخادم. لذلك يجب أن تكون صالحة في ClickHouse SQL. ولتمرير صياغة خاصة بـ PostgreSQL لا يحللها ClickHouse، استخدم صيغة `query('...')`، حيث يُرسل نصها إلى PostgreSQL كما هو.

  لا يتم دفع أي `WHERE` أو `LIMIT` خارجي أو تجميع أو غير ذلك من استعلام ClickHouse المحيط إلى الاستعلام المُمرَّر — بل يُطبَّق ذلك في ClickHouse بعد جلب نتيجة الاستعلام كاملةً. ولتقييد البيانات المقروءة من PostgreSQL، ضع عامل تصفية داخل الاستعلام المُمرَّر. عند استخدام [`external_table_strict_query = 1`](/ar/reference/settings/session-settings/external-table#external_table_strict_query)، يُرفَض عامل تصفية خارجي على أعمدة الجدول مع Exception بدلًا من تطبيقه محليًا، لأنه لا يمكن دفعه إلى الاستعلام المُمرَّر. يغطي التحقق مسند `WHERE` ذي المستوى الأعلى وكل اقتران في `AND` ذي المستوى الأعلى. لا تُعد `PREWHERE` على أعمدة هذا الجدول حالةً لهذا الإعداد: إذ لا يدعم محرك الجدول هذا `PREWHERE`، ويُرفَض مثل هذا الاستعلام باستخدام `ILLEGAL_PREWHERE` بغض النظر عن الإعداد. لا يُجرى التحقق إلا حيث يمكن دفع عامل تصفية من الأساس: عندما يكون هذا الجدول هو الجدول الوحيد في الاستعلام، أو على أي من جانبي `INNER JOIN`، أو على الجانب الحافظ في عملية ربط خارجية (الجانب الأيسر من `LEFT JOIN`، والجانب الأيمن من `RIGHT JOIN`). لا يُدفع أي شيء ولا يُتحقق من أي شيء على الجانب غير الحافظ من `LEFT`/`RIGHT JOIN` أو على أي من جانبي `FULL JOIN`، لذا يُطبَّق عامل تصفية على أعمدة هذا الجدول محليًا بعد عملية الربط حتى في الوضع الصارم. حيث يُجرى التحقق، لا يُدفع المسند الذي يشير إلى جداول أخرى مرتبطة في الاستعلام المحيط ويُستثنى من التحقق، سواء أكان يشير إلى الجانب المرتبط فقط أم يخلطه مع هذا الجدول داخل تعبير واحد غير `AND` (مثلًا `OR`)؛ يحتفظ مثل هذا المسند بنقطة تقييمه المعتادة في ClickHouse (`WHERE` بعد عملية الربط، و`PREWHERE` قبلها) ولا يُرفَض.
</Note>

تُنفَّذ استعلامات `INSERT` على جانب PostgreSQL بصيغة `COPY "table_name" (field1, field2, ... fieldN) FROM STDIN` داخل معاملة PostgreSQL مع `auto-commit` بعد كل عبارة `INSERT`.

تُحوَّل أنواع `Array` في PostgreSQL إلى مصفوفات في ClickHouse.

<Note>
  انتبه: في PostgreSQL، قد تحتوي بيانات المصفوفة المُنشأة على هيئة `type_name[]` على مصفوفات متعددة الأبعاد بأعداد مختلفة من الأبعاد في صفوف مختلفة من الجدول داخل العمود نفسه. لكن في ClickHouse، لا يُسمح إلا بمصفوفات متعددة الأبعاد لها العدد نفسه من الأبعاد في جميع صفوف الجدول داخل العمود نفسه.
</Note>

يدعم عدة نسخ متماثلة يجب إدراجها باستخدام `|`. على سبيل المثال:

```sql theme={null}
CREATE TABLE test_replicas (id UInt32, name String) ENGINE = PostgreSQL(`postgres{2|3|4}:5432`, 'clickhouse', 'test_replicas', 'postgres', 'mysecretpassword');
```

يتم دعم تحديد أولوية النسخ المتماثلة لمصدر قاموس PostgreSQL. وكلما زادت القيمة في `map`، انخفضت الأولوية. أعلى أولوية هي `0`.

في المثال أدناه، تتمتع النسخة المتماثلة `example01-1` بأعلى أولوية:

```xml theme={null}
<postgresql>
    <port>5432</port>
    <user>clickhouse</user>
    <password>qwerty</password>
    <replica>
        <host>example01-1</host>
        <priority>1</priority>
    </replica>
    <replica>
        <host>example01-2</host>
        <priority>2</priority>
    </replica>
    <db>db_name</db>
    <table>table_name</table>
    <where>id=10</where>
    <invalidate_query>SQL_QUERY</invalidate_query>
</postgresql>
```

## مثال استخدام

### جدول في PostgreSQL

```text theme={null}
postgres=# CREATE TABLE "public"."test" (
"int_id" SERIAL,
"int_nullable" INT NULL DEFAULT NULL,
"float" FLOAT NOT NULL,
"str" VARCHAR(100) NOT NULL DEFAULT '',
"float_nullable" FLOAT NULL DEFAULT NULL,
PRIMARY KEY (int_id));

CREATE TABLE

postgres=# INSERT INTO test (int_id, str, "float") VALUES (1,'test',2);
INSERT 0 1

postgresql> SELECT * FROM test;
int_id | int_nullable | float | str  | float_nullable
--------+--------------+-------+------+----------------
       1 |              |     2 | test |
(1 row)
```

### إنشاء جدول في ClickHouse والاتصال بجدول PostgreSQL المُنشأ أعلاه

يستخدم هذا المثال [محرك جدول PostgreSQL](/ar/reference/engines/table-engines/integrations/postgresql) لربط جدول ClickHouse بجدول PostgreSQL واستخدام عبارتي SELECT وINSERT على قاعدة بيانات PostgreSQL:

```sql theme={null}
CREATE TABLE default.postgresql_table
(
    `float_nullable` Nullable(Float32),
    `str` String,
    `int_id` Int32
)
ENGINE = PostgreSQL('localhost:5432', 'public', 'test', 'postgres_user', 'postgres_password');
```

### إدراج البيانات الأولية من جدول PostgreSQL إلى جدول ClickHouse باستخدام استعلام SELECT

تقوم [دالة الجدول postgresql](/ar/reference/functions/table-functions/postgresql) بنسخ البيانات من PostgreSQL إلى ClickHouse، ويُستخدم ذلك غالبًا لتحسين أداء الاستعلامات على هذه البيانات عبر الاستعلام عنها أو إجراء التحليلات في ClickHouse بدلًا من PostgreSQL، كما يمكن استخدامه أيضًا لترحيل البيانات من PostgreSQL إلى ClickHouse. وبما أننا سننسخ البيانات من PostgreSQL إلى ClickHouse، فسنستخدم محرك جدول MergeTree في ClickHouse ونسميه postgresql\_copy:

```sql theme={null}
CREATE TABLE default.postgresql_copy
(
    `float_nullable` Nullable(Float32),
    `str` String,
    `int_id` Int32
)
ENGINE = MergeTree
ORDER BY (int_id);
```

```sql theme={null}
INSERT INTO default.postgresql_copy
SELECT * FROM postgresql('localhost:5432', 'public', 'test', 'postgres_user', 'postgres_password');
```

### إدراج البيانات التزايدية من جدول PostgreSQL إلى جدول ClickHouse

إذا كنت ستُجري بعد الإدراج الأولي مزامنةً مستمرة بين جدول PostgreSQL وجدول ClickHouse، فيمكنك استخدام عبارة WHERE في ClickHouse لإدراج البيانات التي أُضيفت إلى PostgreSQL فقط استنادًا إلى طابع زمني أو معرّف تسلسلي فريد.

ويتطلّب ذلك تتبّع الحد الأقصى للمعرّف أو الطابع الزمني الذي أُضيف سابقًا، كما في المثال التالي:

```sql theme={null}
SELECT max(`int_id`) AS maxIntID FROM default.postgresql_copy;
```

ثم إدراج القيم من جدول PostgreSQL التي تتجاوز الحد الأقصى

```sql theme={null}
INSERT INTO default.postgresql_copy
SELECT * FROM postgresql('localhost:5432', 'public', 'test', 'postgres_user', 'postgres_password')
WHERE int_id > (SELECT max(int_id) FROM default.postgresql_copy);
```

### استعلام البيانات من جدول ClickHouse الناتج

```sql theme={null}
SELECT * FROM postgresql_copy WHERE str IN ('test');
```

```text theme={null}
┌─float_nullable─┬─str──┬─int_id─┐
│           ᴺᵁᴸᴸ │ test │      1 │
└────────────────┴──────┴────────┘
```

### استخدام مخطط غير افتراضي

```text theme={null}
postgres=# CREATE SCHEMA "nice.schema";

postgres=# CREATE TABLE "nice.schema"."nice.table" (a integer);

postgres=# INSERT INTO "nice.schema"."nice.table" SELECT i FROM generate_series(0, 99) as t(i)
```

```sql theme={null}
CREATE TABLE pg_table_schema_with_dots (a UInt32)
        ENGINE PostgreSQL('localhost:5432', 'clickhouse', 'nice.table', 'postgrsql_user', 'password', 'nice.schema');
```

**انظر أيضًا**

* [دالة الجدول `postgresql`](/ar/reference/functions/table-functions/postgresql)
* [استخدام PostgreSQL كمصدر للقاموس](/ar/reference/statements/create/dictionary/sources/postgresql)

## محتوى مرتبط

* مدونة: [ClickHouse و PostgreSQL - ثنائي مثالي في عالم البيانات - الجزء 1](https://clickhouse.com/blog/migrating-data-between-clickhouse-postgres)
* مدونة: [ClickHouse و PostgreSQL - ثنائي مثالي في عالم البيانات - الجزء 2](https://clickhouse.com/blog/migrating-data-between-clickhouse-postgres-part-2)
