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

> يوفّر واجهة شبيهة بالجداول للقراءة فقط لجداول Apache Iceberg في Amazon S3 أو Azure أو HDFS أو المخزّنة محليًا.

# iceberg

يوفّر واجهة شبيهة بالجداول للقراءة فقط لجداول Apache [Iceberg](https://iceberg.apache.org/) في Amazon S3 أو Azure أو HDFS أو المخزّنة محليًا.

<div id="syntax">
  ## الصيغة
</div>

```sql theme={null}
icebergS3(url [, NOSIGN | access_key_id, secret_access_key, [session_token]] [,format] [,compression_method] [,extra_credentials])
icebergS3(named_collection[, option=value [,..]])

icebergAzure(connection_string|storage_account_url, container_name, blobpath, [,account_name], [,account_key] [,format] [,compression_method])
icebergAzure(named_collection[, option=value [,..]])

icebergHDFS(path_to_table, [,format] [,compression_method])
icebergHDFS(named_collection[, option=value [,..]])

icebergLocal(path_to_table, [,format] [,compression_method])
icebergLocal(named_collection[, option=value [,..]])
```

<div id="arguments">
  ## المعاملات
</div>

يتطابق وصف المعاملات مع وصفها في دوال الجداول `s3` و`azureBlobStorage` و`HDFS` و`file`، على التوالي.
يشير `format` إلى تنسيق ملفات البيانات في جدول Iceberg.

بالنسبة إلى `icebergS3`، يمكن استخدام المعامل الاختياري `extra_credentials` لتمرير `role_arn` بغرض الوصول المستند إلى الدور في ClickHouse Cloud. راجع [Secure S3](/ar/products/cloud/guides/data-sources/accessing-s3-data-securely) للاطلاع على خطوات الإعداد.

<div id="returned-value">
  ### القيمة المُعادة
</div>

جدول ذو البنية المحددة لقراءة البيانات من جدول Iceberg المحدد.

<div id="example">
  ### مثال
</div>

```sql theme={null}
SELECT * FROM icebergS3('http://test.s3.amazonaws.com/clickhouse-bucket/test_table', 'test', 'test')
```

<Warning>
  يدعم ClickHouse حاليًا قراءة الإصدارين v1 وv2 من صيغة Iceberg عبر دوال الجداول `icebergS3` و`icebergAzure` و`icebergHDFS` و`icebergLocal`، ومحركات الجداول `IcebergS3` و`icebergAzure` و`IcebergHDFS` و`IcebergLocal`.
</Warning>

<div id="defining-a-named-collection">
  ## تعريف مجموعة مسماة
</div>

فيما يلي مثال على تهيئة مجموعة مسماة لتخزين URL وبيانات الاعتماد:

```xml theme={null}
<clickhouse>
    <named_collections>
        <iceberg_conf>
            <url>http://test.s3.amazonaws.com/clickhouse-bucket/</url>
            <access_key_id>test</access_key_id>
            <secret_access_key>test</secret_access_key>
            <format>auto</format>
            <structure>auto</structure>
        </iceberg_conf>
    </named_collections>
</clickhouse>
```

```sql theme={null}
SELECT * FROM icebergS3(iceberg_conf, filename = 'test_table')
DESCRIBE icebergS3(iceberg_conf, filename = 'test_table')
```

<div id="iceberg-writes-catalogs">
  ## استخدام كتالوج بيانات
</div>

يمكن أيضًا استخدام جداول Iceberg مع كتالوجات بيانات متعددة، مثل [REST Catalog](https://iceberg.apache.org/rest-catalog-spec/)، و[AWS Glue Data Catalog](https://docs.aws.amazon.com/prescriptive-guidance/latest/serverless-etl-aws-glue/aws-glue-data-catalog.html)، و[Unity Catalog](https://www.unitycatalog.io/).

<Warning>
  عند استخدام catalog، سيحتاج معظم المستخدمين إلى استخدام محرك قاعدة البيانات `DataLakeCatalog`، إذ يربط ClickHouse بالcatalog لاكتشاف الجداول. ويمكنك استخدام محرك قاعدة البيانات هذا بدلًا من إنشاء جداول منفصلة يدويًا باستخدام محرك الجدول `IcebergS3`.
</Warning>

لاستخدام ذلك، أنشئ جدولًا باستخدام المحرك `IcebergS3` ووفّر الإعدادات اللازمة.

على سبيل المثال، عند استخدام REST Catalog مع وحدة التخزين MinIO:

```sql theme={null}
CREATE TABLE `database_name.table_name`
ENGINE = IcebergS3(
  'http://minio:9000/warehouse-rest/table_name/',
  'minio_access_key',
  'minio_secret_key'
)
```

أو باستخدام AWS Glue Data Catalog مع S3:

```sql theme={null}
CREATE TABLE `my_database.my_table`  
ENGINE = IcebergS3(
  's3://my-data-bucket/warehouse/my_database/my_table/',
  'aws_access_key',
  'aws_secret_key'
)
```

<div id="schema-evolution">
  ## تطور المخطط
</div>

في الوقت الحالي، وبمساعدة CH، يمكنك قراءة جداول Iceberg التي تغيّر مخططها بمرور الوقت. ونحن ندعم حاليًا قراءة الجداول التي أُضيفت إليها أعمدة وأُزيلت منها أعمدة، أو تغيّر ترتيب أعمدتها. ويمكنك أيضًا تحويل عمود تكون فيه القيمة إلزامية إلى عمود يُسمح فيه بالقيمة NULL. بالإضافة إلى ذلك، ندعم تحويل الأنواع المسموح به للأنواع البسيطة، وهي:  

* int -> long
* float -> double
* decimal(P, S) -> decimal(P', S) where P' > P.

حاليًا، لا يمكن تغيير البُنى المتداخلة أو أنواع العناصر داخل Array وMap.

<div id="partition-pruning">
  ## استبعاد الأقسام
</div>

يدعم ClickHouse استبعاد الأقسام أثناء استعلامات SELECT على جداول Iceberg، مما يساعد على تحسين أداء الاستعلامات عبر تخطي ملفات البيانات غير ذات الصلة. لتمكين استبعاد الأقسام، اضبط `use_iceberg_partition_pruning = 1`. لمزيد من المعلومات حول استبعاد أقسام Iceberg، راجع [https://iceberg.apache.org/spec/#partitioning](https://iceberg.apache.org/spec/#partitioning)

<div id="time-travel">
  ## السفر عبر الزمن
</div>

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

<div id="deleted-rows">
  ## معالجة الجداول ذات الصفوف المحذوفة
</div>

حاليًا، لا تُدعَم إلا جداول Iceberg التي تستخدم [الحذف حسب الموضع](https://iceberg.apache.org/spec/#position-delete-files).

أساليب الحذف التالية **غير مدعومة**:

* [الحذف بالمساواة](https://iceberg.apache.org/spec/#equality-delete-files)
* [متجهات الحذف](https://iceberg.apache.org/spec/#deletion-vectors) (أُضيفت في v3)

<div id="basic-usage">
  ### الاستخدام الأساسي
</div>

```sql theme={null}
 SELECT * FROM example_table ORDER BY 1 
 SETTINGS iceberg_timestamp_ms = 1714636800000
```

```sql theme={null}
 SELECT * FROM example_table ORDER BY 1 
 SETTINGS iceberg_snapshot_id = 3547395809148285433
```

ملاحظة: لا يمكنك تحديد المعلَمين `iceberg_timestamp_ms` و`iceberg_snapshot_id` معًا في الاستعلام نفسه.

<div id="important-considerations">
  ### اعتبارات مهمة
</div>

* **اللقطات** تُنشأ عادةً عندما:

* تُكتب بيانات جديدة إلى الجدول

* يُجرى نوعٌ ما من عمليات دمج البيانات

* **تغييرات المخطط لا تُنشئ لقطات عادةً** - يؤدي ذلك إلى سلوكيات مهمة عند استخدام السفر عبر الزمن مع الجداول التي خضعت لتطوّر المخطط.

<div id="example-scenarios">
  ### أمثلة على السيناريوهات
</div>

جميع السيناريوهات مكتوبة باستخدام Spark لأن CH لا يدعم الكتابة إلى جداول Iceberg بعد.

<div id="scenario-1">
  #### السيناريو 1: تغييرات المخطط من دون لقطات جديدة
</div>

تأمل تسلسل العمليات التالي:

```sql theme={null}
 -- Create a table with two columns
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

- - Insert data into the table
  INSERT INTO spark_catalog.db.time_travel_example VALUES 
    (1, 'Mars')

  ts1 = now() // A piece of pseudo code

- - Alter table to add a new column
  ALTER TABLE spark_catalog.db.time_travel_example ADD COLUMN (price double)
 
  ts2 = now()

- - Insert data into the table
  INSERT INTO spark_catalog.db.time_travel_example VALUES (2, 'Venus', 100)

   ts3 = now()

- - Query the table at each timestamp
  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts1;

+------------+------------+
|order_number|product_code|
+------------+------------+
|           1|        Mars|
+------------+------------+
  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts2;

+------------+------------+
|order_number|product_code|
+------------+------------+
|           1|        Mars|
+------------+------------+

  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts3;

+------------+------------+-----+
|order_number|product_code|price|
+------------+------------+-----+
|           1|        Mars| NULL|
|           2|       Venus|100.0|
+------------+------------+-----+
```

نتائج الاستعلام عند طوابع زمنية مختلفة:

* عند ts1 وts2: يظهر العمودان الأصليان فقط
* عند ts3: تظهر الأعمدة الثلاثة جميعها، وتكون قيمة السعر في الصف الأول NULL

<div id="scenario-2">
  #### السيناريو 2:  الاختلافات بين المخطط التاريخي والمخطط الحالي
</div>

قد يُظهر استعلام السفر عبر الزمن في الوقت الحالي مخططًا يختلف عن مخطط الجدول الحالي:

```sql theme={null}
-- Create a table
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_2 (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

-- Insert initial data into the table
  INSERT INTO spark_catalog.db.time_travel_example_2 VALUES (2, 'Venus');

-- Alter table to add a new column
  ALTER TABLE spark_catalog.db.time_travel_example_2 ADD COLUMN (price double);

  ts = now();

-- Query the table at a current moment but using timestamp syntax

  SELECT * FROM spark_catalog.db.time_travel_example_2 TIMESTAMP AS OF ts;

    +------------+------------+
    |order_number|product_code|
    +------------+------------+
    |           2|       Venus|
    +------------+------------+

-- Query the table at a current moment
  SELECT * FROM spark_catalog.db.time_travel_example_2;
    +------------+------------+-----+
    |order_number|product_code|price|
    +------------+------------+-----+
    |           2|       Venus| NULL|
    +------------+------------+-----+
```

يحدث هذا لأن `ALTER TABLE` لا يُنشئ snapshot جديدة، ولكن بالنسبة إلى الجدول الحالي، يأخذ Spark قيمة `schema_id` من أحدث ملف metadata، وليس من snapshot.

<div id="scenario-3">
  #### السيناريو 3: اختلافات المخطط التاريخي والحالي
</div>

والنقطة الثانية هي أنه عند استخدام السفر عبر الزمن، لا يمكنك الحصول على حالة الجدول قبل كتابة أي بيانات فيه:

```sql theme={null}
-- Create a table
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_3 (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2');

  ts = now();

-- Query the table at a specific timestamp
  SELECT * FROM spark_catalog.db.time_travel_example_3 TIMESTAMP AS OF ts; -- Finises with error: Cannot find a snapshot older than ts.
```

في ClickHouse، يكون السلوك متوافقًا مع Spark. يمكنك ببساطة اعتبار استعلامات `Select` في ClickHouse بدلًا من استعلامات `Select` في Spark، وسيعمل الأمر بالطريقة نفسها.

<div id="metadata-file-resolution">
  ## تحديد ملف البيانات الوصفية
</div>

عند استخدام الدالة الجدولية `iceberg` في ClickHouse، يحتاج النظام إلى تحديد ملف metadata.json الصحيح الذي يصف بنية جدول Iceberg. إليك كيف تتم عملية التحديد هذه:

<div id="candidate-search">
  ### البحث عن المرشحين (حسب ترتيب الأولوية)
</div>

1. **تحديد المسار مباشرةً**:
   \*إذا عيّنت `iceberg_metadata_file_path`، فسيستخدم النظام هذا المسار المحدد كما هو، من خلال دمجه مع مسار دليل جدول Iceberg.

* عند توفير هذا الإعداد، يتم تجاهل جميع إعدادات resolution الأخرى.

2. **مطابقة UUID الجدول**:
   \*إذا تم تحديد `iceberg_metadata_table_uuid`، فسيقوم النظام بما يلي:
   \*ينظر فقط إلى ملفات `.metadata.json` في دليل `metadata`
   \*يُصفّي الملفات التي تحتوي على الحقل `table-uuid` المطابق لـ UUID الذي حددته (غير حساس لحالة الأحرف)

3. **البحث الافتراضي**:
   \*إذا لم يتم توفير أيٍّ من الإعدادين أعلاه، تصبح جميع ملفات `.metadata.json` في دليل `metadata` مرشحين

<div id="most-recent-file">
  ### اختيار أحدث ملف
</div>

بعد تحديد الملفات المرشحة باستخدام القواعد المذكورة أعلاه، يحدّد النظام الملف الأحدث بينها:

* إذا كان `iceberg_recent_metadata_file_by_last_updated_ms_field` مُمكّنًا:

* يُختار الملف ذو أكبر قيمة `last-updated-ms`

* بخلاف ذلك:

* يُختار الملف ذو أعلى رقم إصدار

* (يظهر الإصدار بصيغة `V` في أسماء الملفات المنسّقة على النحو `V.metadata.json` أو `V-uuid.metadata.json`)

**ملاحظة**: جميع الإعدادات المذكورة هي إعدادات الدالة الجدولية (وليست إعدادات عامة أو على مستوى الاستعلام) ويجب تحديدها كما هو موضح أدناه:

```sql theme={null}
SELECT * FROM iceberg('s3://bucket/path/to/iceberg_table', 
    SETTINGS iceberg_metadata_table_uuid = 'a90eed4c-f74b-4e5b-b630-096fb9d09021');
```

**ملاحظة**: رغم أن كتالوجات Iceberg تتولى عادةً تحديد البيانات الوصفية، فإن دالة الجدول `iceberg` في ClickHouse تفسّر مباشرةً الملفات المخزّنة في S3 على أنها جداول Iceberg، ولذلك من المهم فهم قواعد التحديد هذه.

<div id="metadata-cache">
  ## ذاكرة التخزين المؤقت للبيانات الوصفية
</div>

يدعم محرك الجدول `Iceberg` والدالة الجدولية ذاكرة تخزين مؤقت للبيانات الوصفية تُخزّن معلومات ملفات manifest وmanifest list وملف metadata json. تُخزَّن ذاكرة التخزين المؤقت هذه في الذاكرة. ويجري التحكم في هذه الميزة عبر الإعداد `use_iceberg_metadata_files_cache`، وهي مفعّلة افتراضيًا.

<div id="aliases">
  ## الأسماء البديلة
</div>

أصبحت الدالة الجدولية `iceberg` اسمًا بديلًا لـ `icebergS3`.

<div id="virtual-columns">
  ## الأعمدة الافتراضية
</div>

* `_path` — مسار الملف. النوع: `LowCardinality(String)`.
* `_file` — اسم الملف. النوع: `LowCardinality(String)`.
* `_size` — حجم الملف بالبايت. النوع: `Nullable(UInt64)`. إذا كان حجم الملف غير معروف، فستكون القيمة `NULL`.
* `_time` — وقت آخر تعديل للملف. النوع: `Nullable(DateTime)`. إذا كان الوقت غير معروف، فستكون القيمة `NULL`.
* `_etag` — قيمة etag للملف. النوع: `LowCardinality(String)`. إذا كانت قيمة etag غير معروفة، فستكون القيمة `NULL`.

<div id="writes-into-iceberg-table">
  ## الكتابة في جدول Iceberg
</div>

بدءًا من الإصدار 25.7، يدعم ClickHouse تعديل جداول Iceberg الخاصة بالمستخدم.

حاليًا، هذه ميزة تجريبية، لذا عليك أولًا تمكينها:

```sql theme={null}
SET allow_insert_into_iceberg = 1;
```

<div id="create-iceberg-table">
  ### إنشاء جدول
</div>

لإنشاء جدول Iceberg فارغ خاص بك، استخدم الأوامر نفسها المستخدَمة للقراءة، ولكن حدِّد المخطط صراحةً.
تدعم عمليات الكتابة جميع تنسيقات البيانات وفقًا لمواصفة Iceberg، مثل Parquet وAvro وORC.

<div id="example">
  ### مثال
</div>

```sql theme={null}
CREATE TABLE iceberg_writes_example
(
    x Nullable(String),
    y Nullable(Int32)
)
ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/')
```

ملاحظة: لإنشاء ملف تلميح الإصدار، فعِّل الإعداد `iceberg_use_version_hint`.
إذا أردت ضغط ملف metadata.json، فحدِّد اسم خوارزمية الضغط في الإعداد `iceberg_metadata_compression_method`.

<div id="writes-inserts">
  ### INSERT
</div>

بعد إنشاء جدول جديد، يمكنك إدراج البيانات باستخدام صيغة ClickHouse المعتادة.

<div id="example">
  ### مثال
</div>

```sql theme={null}
INSERT INTO iceberg_writes_example VALUES ('Pavel', 777), ('Ivanov', 993);

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Pavel
y: 777

Row 2:
──────
x: Ivanov
y: 993
```

<div id="iceberg-writes-delete">
  ### DELETE
</div>

يدعم ClickHouse أيضًا حذف الصفوف الإضافية في تنسيق merge-on-read.
سينشئ هذا الاستعلام لقطة جديدة تتضمّن ملفات حذف حسب الموضع.

<div id="example">
  ### مثال
</div>

```sql theme={null}
ALTER TABLE iceberg_writes_example DELETE WHERE x != 'Ivanov';

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993
```

<div id="iceberg-writes-schema-evolution">
  ### تطوّر المخطط
</div>

يتيح ClickHouse إضافة الأعمدة ذات الأنواع البسيطة (غير tuple وغير array وغير map) أو حذفها أو تعديلها أو إعادة تسميتها.

<div id="example">
  ### مثال
</div>

```sql theme={null}
ALTER TABLE iceberg_writes_example MODIFY COLUMN y Nullable(Int64);
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

ALTER TABLE iceberg_writes_example ADD COLUMN z Nullable(Int32);
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64),                                 ↴│
   │↳    `z` Nullable(Int32)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993
z: ᴺᵁᴸᴸ

ALTER TABLE iceberg_writes_example DROP COLUMN z;
SHOW CREATE TABLE iceberg_writes_example;
   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993

ALTER TABLE iceberg_writes_example RENAME COLUMN y TO value;
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `value` Nullable(Int64)                              ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
value: 993
```

<div id="iceberg-writes-compaction">
  ### الدمج
</div>

يدعم ClickHouse دمج جداول Iceberg. حاليًا، يمكنه دمج ملفات الحذف حسب الموضع في ملفات البيانات مع تحديث البيانات الوصفية. وتبقى معرّفات اللقطات السابقة والطوابع الزمنية من دون تغيير، لذا يظل بالإمكان استخدام ميزة السفر عبر الزمن بالمعرّفات والقيم الزمنية نفسها.

كيفية استخدامه:

```sql theme={null}
SET allow_experimental_iceberg_compaction = 1

OPTIMIZE TABLE iceberg_writes_example;

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993
```

<div id="iceberg-expire-snapshots">
  ### حذف اللقطات منتهية الصلاحية
</div>

تتراكم اللقطات في جداول Iceberg مع كل عملية INSERT أو DELETE أو UPDATE. ومع مرور الوقت، قد يؤدي ذلك إلى زيادة كبيرة في عدد اللقطات وملفات البيانات المرتبطة بها. يزيل الأمر `expire_snapshots` اللقطات القديمة وينظّف ملفات البيانات التي لم تعد أي لقطة محتفَظ بها تُشير إليها.

**الصياغة:**

```sql theme={null}
ALTER TABLE iceberg_table EXECUTE expire_snapshots(
    ['timestamp']
    [, expire_before = 'timestamp']
    [, retention_period = '3d']
    [, retain_last = 100]
    [, snapshot_ids = [1, 2, 3, 4]]
    [, dry_run = 1]
);
```

بشكل افتراضي، يحدِّد [سياسة الاستبقاء](#iceberg-snapshot-retention-policy) اللقطات التي يجب الاحتفاظ بها (خصائص الجدول `min-snapshots-to-keep` و`max-snapshot-age-ms`، وعمليات التجاوز لكل مرجع). عند تحديد `snapshot_ids`، يتم تخطي سياسة الاستبقاء ولا تُؤخذ في الاعتبار لانتهاء الصلاحية إلا اللقطات المُدرجة.

**الوسيطات:**

* `'timestamp'` (موضعي) أو `expire_before = 'timestamp'` — سلسلة DateTime (مثل `'2024-06-01 00:00:00'`) تُفسَّر وفق **المنطقة الزمنية للخادم**. تعمل كآلية أمان: اللقطات التي تكون قيمة `timestamp-ms` الخاصة بها مساوية لهذه القيمة أو أحدث منها تكون محمية من انتهاء الصلاحية، حتى لو كانت سياسة الاستبقاء ستُنهي صلاحيتها بخلاف ذلك. ويمكن دمجها مع `snapshot_ids`، وفي هذه الحالة لا تنتهي صلاحية اللقطات المُدرجة التي تقع عند هذا الطابع الزمني أو بعده.
* `retention_period = '<duration>'` — يتجاوز قيمة `history.expire.max-snapshot-age-ms` على مستوى الجدول لهذا الاستدعاء فقط. تصبح اللقطات الأقدم من هذه المدة (مقاسةً من الوقت الحالي) مرشحة لانتهاء الصلاحية. وتكون القيمة سلسلة مدة تتكوّن من زوج واحد أو أكثر من `{number}{unit}` متصلة معًا. الوحدات المدعومة: `y` (365 يومًا)، `w` (7 أيام)، `d` (24 ساعة)، `h` (60 دقيقة)، `m` (60 ثانية)، `s` (ثانية واحدة)، `ms` (1 ميلي ثانية). ويمكن دمج الوحدات، مثل `'3d'` و`'12h'` و`'1d12h30m'` و`'500ms'`.
* `retain_last = N` — يتجاوز قيمة `history.expire.min-snapshots-to-keep` على مستوى الجدول لهذا الاستدعاء فقط. ويُحتفَظ دائمًا بما لا يقل عن `N` من اللقطات بغضّ النظر عن عمرها.
* `snapshot_ids = [id1, id2, ...]` — يُنهي صلاحية معرّفات اللقطات المُدرجة فقط (باستثناء اللقطات المشار إليها بواسطة اللقطة الحالية أو الفروع أو الوسوم). يتخطى هذا الوضع سياسة الاستبقاء بالكامل، ولا يمكن دمجه مع `retention_period` أو `retain_last`.
* `dry_run = 1` — يحسب ما الذي كان سينتهي صلاحيته ويُرجع المقاييس دون كتابة بيانات وصفية جديدة أو حذف ملفات.

<Note>
  يتجاوز `retention_period` و`retain_last` فقط قيم الاستبقاء الافتراضية على **مستوى الجدول**. أما عمليات تجاوز الاستبقاء لكل مرجع (فرع/وسم) المُعدّة في خصائص جدول Iceberg (مثل `refs.<branch>.min-snapshots-to-keep`) فلا يتم تجاوزها مطلقًا — بل تسري دائمًا كما هي محددة في البيانات الوصفية للجدول.
</Note>

**مثال:**

```sql theme={null}
SET allow_insert_into_iceberg = 1;

-- Create some snapshots by inserting data
INSERT INTO iceberg_table VALUES (1);
INSERT INTO iceberg_table VALUES (2);
INSERT INTO iceberg_table VALUES (3);

-- Expire using retention policy only
ALTER TABLE iceberg_table EXECUTE expire_snapshots();

-- Expire with a safety fuse: protect snapshots newer than the timestamp (positional syntax)
ALTER TABLE iceberg_table EXECUTE expire_snapshots('2025-01-01 00:00:00');

-- Same using the named argument form
ALTER TABLE iceberg_table EXECUTE expire_snapshots(expire_before = '2025-01-01 00:00:00');

-- Override retention parameters for one execution
ALTER TABLE iceberg_table EXECUTE expire_snapshots(retention_period = '3d', retain_last = 10);

-- Expire explicit snapshots
ALTER TABLE iceberg_table EXECUTE expire_snapshots(snapshot_ids = [101, 102, 103]);

-- Dry-run preview (no metadata updates, no file deletes)
ALTER TABLE iceberg_table EXECUTE expire_snapshots(retention_period = '1d', dry_run = 1);
```

**الناتج:**

يعيد الأمر جدولًا بعمودين (`metric_name String`, `metric_value Int64`) ويضم صفًا واحدًا لكل مقياس. وتتبع أسماء المقاييس [مواصفة Iceberg](https://iceberg.apache.org/docs/latest/spark-procedures/#output):

| metric\_name                          | الوصف                                          |
| ------------------------------------- | ---------------------------------------------- |
| `deleted_data_files_count`            | عدد ملفات البيانات المحذوفة                    |
| `deleted_position_delete_files_count` | عدد ملفات الحذف الموضعي المحذوفة               |
| `deleted_equality_delete_files_count` | عدد ملفات حذف المساواة المحذوفة                |
| `deleted_manifest_files_count`        | عدد ملفات البيان المحذوفة                      |
| `deleted_manifest_lists_count`        | عدد ملفات قوائم البيان المحذوفة                |
| `deleted_statistics_files_count`      | عدد ملفات الإحصاءات المحذوفة (0 دائمًا حاليًا) |
| `dry_run`                             | `1` لوضع التشغيل التجريبي، و`0` للتنفيذ العادي |

ينفّذ الأمر الخطوات التالية:

1. يقيّم سياسة الاحتفاظ (انظر أدناه) لتحديد اللقطات التي يجب الإبقاء عليها
2. إذا تم توفير وسيطة طابع زمني، فإنه يحمي أيضًا جميع اللقطات عند ذلك الطابع الزمني أو الأحدث منه
3. يُنهي صلاحية اللقطات التي لا تحتفظ بها السياسة ولا تشملها الحماية بالطابع الزمني
4. يحسب الملفات المرتبطة حصريًا باللقطات منتهية الصلاحية
5. في الوضع العادي: ينشئ بيانات وصفية جديدة من دون اللقطات منتهية الصلاحية
6. في الوضع العادي: يحذف فعليًا قوائم البيان وملفات البيان وملفات البيانات التي لم يعد من الممكن الوصول إليها
7. في وضع `dry_run = 1`: يتخطى الخطوتين 5 و6 ويُرجع فقط المقاييس المحسوبة

<div id="iceberg-snapshot-retention-policy">
  #### سياسة الاحتفاظ باللقطات
</div>

يراعي الأمر `expire_snapshots` [سياسة الاحتفاظ بلقطات Iceberg](https://iceberg.apache.org/spec/#snapshot-retention-policy). يُضبط الاحتفاظ عبر خصائص جدول Iceberg وعمليات التجاوز على مستوى كل مرجع:

| Property                               | Scope | Default                                                                      | Description                                                                    |
| -------------------------------------- | ----- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `history.expire.min-snapshots-to-keep` | Table | `iceberg_expire_default_min_snapshots_to_keep` (الافتراضي `1`)               | الحد الأدنى لعدد اللقطات التي يجب الاحتفاظ بها في سلسلة الأسلاف لكل فرع        |
| `history.expire.max-snapshot-age-ms`   | Table | `iceberg_expire_default_max_snapshot_age_ms` (الافتراضي `432000000`، 5 أيام) | الحد الأقصى لعمر اللقطات (بالملي ثانية) التي يجب الاحتفاظ بها في فرع           |
| `history.expire.max-ref-age-ms`        | Table | `iceberg_expire_default_max_ref_age_ms` (الافتراضي `∞`)                      | الحد الأقصى لعمر مرجع اللقطة (فرع أو `tag`) بالملي ثانية قبل إزالة المرجع نفسه |

يمكن لكل مرجع لقطة (`refs` في بيانات Iceberg الوصفية) تجاوز هذه القيم من خلال حقول خاصة بكل مرجع: `min-snapshots-to-keep` و`max-snapshot-age-ms` و`max-ref-age-ms`.

**تقييم الاحتفاظ:**

* **لكل فرع** (بما في ذلك `main`): يُتتبَّع تسلسل الأسلاف بدءًا من رأس الفرع. ويُحتفَظ باللقطات ما دام أحد الشرطين التاليين متحققًا:
  * أن تكون اللقطة من أول `min-snapshots-to-keep` في التسلسل
  * أن يكون عمر اللقطة ضمن `max-snapshot-age-ms` (أي `now - timestamp-ms <= max-snapshot-age-ms`)
* **بالنسبة إلى `tags`**: يُحتفَظ باللقطة المشار إليها ما لم يكن `tag` قد تجاوز `max-ref-age-ms` الخاص به، وعندها يُزال مرجع `tag`
* **المراجع غير `main`** التي يتجاوز عمرها `max-ref-age-ms` تُزال بالكامل (أما فرع `main` فلا يُزال أبدًا)
* **المراجع المعلّقة** التي تشير إلى لقطات غير موجودة تُزال مع تحذير
* **تُحفَظ اللقطة الحالية دائمًا**، بغض النظر عن إعدادات الاحتفاظ

**الامتيازات المطلوبة:**

امتياز `ALTER TABLE EXECUTE` مطلوب، وهو امتياز فرعي من `ALTER TABLE` في التسلسل الهرمي للتحكم في الوصول في ClickHouse. يمكنك منحه مباشرةً أو عبر الامتياز الأصل:

```sql theme={null}
-- Grant only EXECUTE permission
GRANT ALTER TABLE EXECUTE ON my_iceberg_table TO my_user;

-- Or grant all ALTER TABLE permissions (includes ALTER TABLE EXECUTE)
GRANT ALTER TABLE ON my_iceberg_table TO my_user;
```

<Note>
  * لا تُدعَم إلا جداول Iceberg ذات تنسيق الإصدار 2 (إذ لا تضمن لقطات v1 وجود `manifest-list`، وهو مطلوب لتحديد الملفات المراد تنظيفها بأمان)
  * تُحفَظ اللقطة الحالية دائمًا، حتى إذا كانت أقدم من الطابع الزمني المحدد
  * يتطلب تمكين الإعداد `allow_insert_into_iceberg`
  * يتطلب تمكين الإعداد `allow_experimental_expire_snapshots`
  * يُطبَّق التفويض الخاص بـ catalog نفسه (مثل مصادقة REST catalog وAWS Glue IAM وغيرها) بشكل مستقل عندما يحدّث ClickHouse البيانات الوصفية
</Note>

<div id="iceberg-remove-orphan-files">
  ### إزالة الملفات اليتيمة
</div>

الملفات اليتيمة هي ملفات موجودة في التخزين لا تشير إليها أي لقطة في البيانات الوصفية لجدول Iceberg. وتتراكم بسبب عمليات الكتابة الفاشلة، والتنظيف الجزئي بعد الدمج، والعمليات المنقطعة، مما يؤدي إلى نمو غير محدود في مساحة التخزين. يحدِّد الأمر `remove_orphan_files` هذه الملفات اليتيمة ويزيلها.

**الصيغة:**

```sql theme={null}
-- Positional form: single unnamed older_than argument
ALTER TABLE iceberg_table EXECUTE remove_orphan_files('timestamp')

-- Named form
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    older_than = 'timestamp',
    location = 'path',
    dry_run = 0|1
)

-- No arguments: use all defaults (older_than = 3 days ago)
ALTER TABLE iceberg_table EXECUTE remove_orphan_files()
```

**المعلمات:**

| المعلمة      | النوع                | الافتراضي                                                               | الوصف                                                                                                                                                                               |
| ------------ | -------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `older_than` | `String` (طابع زمني) | قبل 3 أيام (قابل للتهيئة عبر `iceberg_orphan_files_older_than_seconds`) | لا تُعدّ ملفات يتيمة محتملة إلا الملفات التي يعود وقت آخر تعديل لها إلى ما قبل هذا الطابع الزمني. هذا إجراء احترازي لتجنّب حذف الملفات الناتجة عن عمليات كتابة لا تزال قيد التنفيذ. |
| `location`   | `String`             | موقع الجدول                                                             | يقيّد الفحص بدليل فرعي محدد ضمن موقع الجدول (على سبيل المثال، `'data/'` أو `'metadata/'`).                                                                                          |
| `dry_run`    | `UInt64`             | `0`                                                                     | عند ضبطه على `1`، يحدّد الملفات اليتيمة ويُرجع ملخصًا بالنتائج دون حذف أي شيء فعليًا.                                                                                               |

**أمثلة:**

```sql theme={null}
-- Remove orphan files older than a specific timestamp
ALTER TABLE iceberg_table EXECUTE remove_orphan_files('2026-03-01 00:00:00');

-- Dry run: preview which files would be deleted
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(dry_run = 1);

-- Scan only the data directory
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    older_than = '2026-03-01 00:00:00',
    location = 'data/'
);

-- Combine positional older_than with named arguments
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    '2026-03-01 00:00:00',
    dry_run = 1
);
```

**المخرجات:**

يعيد الأمر جدولًا يحتوي على العمودين `metric_name` و`metric_value`، ويعرض عدد الملفات المحذوفة (أو التي كان سيُحذفها في وضع dry\_run) حسب الفئة. تُصنَّف فئات الملفات باستخدام أساليب استدلالية بأفضل جهد استنادًا إلى اصطلاحات تسمية الملفات؛ أما الملفات التي لا تطابق أي نمط محدد فتُدرج افتراضيًا ضمن `deleted_data_files_count`:

| metric\_name                            | metric\_value |
| --------------------------------------- | ------------- |
| deleted\_data\_files\_count             | 5             |
| deleted\_position\_delete\_files\_count | 2             |
| deleted\_equality\_delete\_files\_count | 0             |
| deleted\_manifest\_files\_count         | 3             |
| deleted\_manifest\_lists\_count         | 1             |
| deleted\_metadata\_files\_count         | 0             |
| deleted\_statistics\_files\_count       | 0             |
| skipped\_missing\_metadata\_count       | 0             |
| failed\_deletions\_count                | 0             |

**الإعدادات:**

| الإعداد                                   | النوع    | الافتراضي         | الوصف                                                       |
| ----------------------------------------- | -------- | ----------------- | ----------------------------------------------------------- |
| `allow_iceberg_remove_orphan_files`       | `Bool`   | `false`           | إعداد تحكّم لتمكين الميزة (تجريبية).                        |
| `iceberg_orphan_files_older_than_seconds` | `UInt64` | `259200` (3 أيام) | عتبة `older_than` الافتراضية بالثواني عند عدم تمرير الوسيط. |

<Note>
  * **يتطلب Iceberg format version 2 (أو أعلى).** تُرفض جداول الإصدار 1 لأنها تفتقر إلى مؤشرات `manifest-list` في لقطات، وهي مطلوبة لتحديد مجموعة الملفات القابلة للوصول بأمان. ويؤدي تشغيل الأمر على جدول v1 إلى إرجاع خطأ `BAD_ARGUMENTS`.
  * يتطلب تمكين كلٍّ من الإعدادين `allow_insert_into_iceberg` و`allow_iceberg_remove_orphan_files`
  * يُوصى بتشغيل `expire_snapshots` قبل `remove_orphan_files` حتى تُنظَّف أولًا الملفات المشار إليها بشكل فريد من خلال لقطات منتهية الصلاحية
  * استخدم `dry_run = 1` لمعاينة orphan files قبل حذفها
  * تحمي عتبة `older_than` من حذف الملفات الناتجة عن عمليات كتابة لا تزال قيد التنفيذ — وتوفّر العتبة الافتراضية البالغة 3 أيام هامش أمان مريحًا
</Note>

<div id="see-also">
  ## راجع أيضًا
</div>

* [محرك Iceberg](/ar/reference/engines/table-engines/integrations/iceberg)
* [دالة جدول العنقود الخاصة بـ Iceberg](/ar/reference/functions/table-functions/icebergCluster)
