Syntax
Arguments
Description of the arguments coincides with description of arguments in table functionss3, azureBlobStorage, HDFS and file correspondingly.
format stands for the format of data files in the Iceberg table.
For icebergS3, an optional extra_credentials parameter can be used to pass a role_arn for role-based access in ClickHouse Cloud. See Secure S3 for configuration steps.
Returned value
A table with the specified structure for reading data in the specified Iceberg table.Example
Defining a named collection
Here is an example of configuring a named collection for storing the URL and credentials:Using a data catalog
Iceberg tables can also be used with various data catalogs, such as the REST Catalog, AWS Glue Data Catalog and Unity Catalog. To use them, create a table with theIcebergS3 engine and provide the necessary settings.
For example, using REST Catalog with MinIO storage:
Schema Evolution
At the moment, with the help of CH, you can read iceberg tables, the schema of which has changed over time. We currently support reading tables where columns have been added and removed, and their order has changed. You can also change a column where a value is required to one where NULL is allowed. Additionally, we support permitted type casting for simple types, namely:- int -> long
- float -> double
- decimal(P, S) -> decimal(P’, S) where P’ > P.
Partition Pruning
ClickHouse supports partition pruning during SELECT queries for Iceberg tables, which helps optimize query performance by skipping irrelevant data files. To enable partition pruning, setuse_iceberg_partition_pruning = 1. For more information about iceberg partition pruning address https://iceberg.apache.org/spec/#partitioning
Time Travel
ClickHouse supports time travel for Iceberg tables, allowing you to query historical data with a specific timestamp or snapshot ID.Processing of tables with deleted rows
Currently, only Iceberg tables with position deletes are supported. The following deletion methods are not supported:- Equality deletes
- Deletion vectors (introduced in v3)
Basic usage
iceberg_timestamp_ms and iceberg_snapshot_id parameters in the same query.
Important considerations
- Snapshots are typically created when:
- New data is written to the table
- Some kind of data compaction is performed
- Schema changes typically don’t create snapshots - This leads to important behaviors when using time travel with tables that have undergone schema evolution.
Example scenarios
All scenarios are written in Spark because CH doesn’t support writing to Iceberg tables yet.Scenario 1: Schema Changes Without New Snapshots
Consider this sequence of operations:- At ts1 & ts2: Only the original two columns appear
- At ts3: All three columns appear, with NULL for the price of the first row
Scenario 2: Historical vs. Current Schema Differences
A time travel query at a current moment might show a different schema than the current table:ALTER TABLE doesn’t create a new snapshot but for the current table Spark takes value of schema_id from the latest metadata file, not a snapshot.
Scenario 3: Historical vs. Current Schema Differences
The second one is that while doing time travel you can’t get state of table before any data was written to it:Metadata File Resolution
When using theiceberg table function in ClickHouse, the system needs to locate the correct metadata.json file that describes the Iceberg table structure. Here’s how this resolution process works:
Candidate Search (in Priority Order)
- Direct Path Specification:
*If you set
iceberg_metadata_file_path, the system will use this exact path by combining it with the Iceberg table directory path.
- When this setting is provided, all other resolution settings are ignored.
-
Table UUID Matching:
*If
iceberg_metadata_table_uuidis specified, the system will: *Look only at.metadata.jsonfiles in themetadatadirectory *Filter for files containing atable-uuidfield matching your specified UUID (case-insensitive) -
Default Search:
*If neither of the above settings are provided, all
.metadata.jsonfiles in themetadatadirectory become candidates
Selecting the Most Recent File
After identifying candidate files using the above rules, the system determines which one is the most recent:-
If
iceberg_recent_metadata_file_by_last_updated_ms_fieldis enabled: -
The file with the largest
last-updated-msvalue is selected - Otherwise:
- The file with the highest version number is selected
-
(Version appears as
Vin filenames formatted asV.metadata.jsonorV-uuid.metadata.json)
iceberg table function in ClickHouse directly interprets files stored in S3 as Iceberg tables, which is why understanding these resolution rules is important.
Metadata cache
Iceberg table engine and table function support metadata cache storing the information of manifest files, manifest list and metadata json. The cache is stored in memory. This feature is controlled by setting use_iceberg_metadata_files_cache, which is enabled by default.
Aliases
Table functioniceberg is an alias to icebergS3 now.
Virtual Columns
_path— Path to the file. Type:LowCardinality(String)._file— Name of the file. Type:LowCardinality(String)._size— Size of the file in bytes. Type:Nullable(UInt64). If the file size is unknown, the value isNULL._time— Last modified time of the file. Type:Nullable(DateTime). If the time is unknown, the value isNULL._etag— The etag of the file. Type:LowCardinality(String). If the etag is unknown, the value isNULL.
Writes into iceberg table
Starting from version 25.7, ClickHouse supports modifications of user’s Iceberg tables. Currently, this is an experimental feature, so you first need to enable it:Creating table
To create your own empty Iceberg table, use the same commands as for reading, but specify the schema explicitly. Writes supports all data formats from iceberg specification, such as Parquet, Avro, ORC.Example
iceberg_use_version_hint setting.
If you want to compress the metadata.json file, specify the codec name in the iceberg_metadata_compression_method setting.
INSERT
After creating a new table, you can insert data using the usual ClickHouse syntax.Example
DELETE
Deleting extra rows in the merge-on-read format is also supported in ClickHouse. This query will create a new snapshot with position delete files.Example
Schema evolution
ClickHouse allows you to add, drop, modify, or rename columns with simple types (non-tuple, non-array, non-map).Example
Compaction
ClickHouse supports compaction iceberg table. Currently, it can merge position delete files into data files while updating metadata. Previous snapshot IDs and timestamps remain unchanged, so the time-travel feature can still be used with the same values. How to use it:Expire Snapshots
Iceberg tables accumulate snapshots with each INSERT, DELETE, or UPDATE operation. Over time, this can lead to a large number of snapshots and associated data files. Theexpire_snapshots command removes old snapshots and cleans up data files that are no longer referenced by any retained snapshot.
Syntax:
min-snapshots-to-keep, max-snapshot-age-ms, and per-ref overrides). When snapshot_ids is specified, the retention policy is bypassed and only the listed snapshots are considered for expiration.
Arguments:
'timestamp'(positional) orexpire_before = 'timestamp'— a datetime string (e.g.,'2024-06-01 00:00:00') interpreted in the server’s timezone. Acts as a safety fuse: snapshots whosetimestamp-msis at or after this value are protected from expiration, even if the retention policy would otherwise expire them. Can be combined withsnapshot_ids, in which case listed snapshots at or newer than the timestamp are not expired.retention_period = '<duration>'— overrides the table-levelhistory.expire.max-snapshot-age-msfor this invocation only. Snapshots older than this duration (measured from now) become candidates for expiration. The value is a duration string consisting of one or more{number}{unit}pairs concatenated together. Supported units:y(365 days),w(7 days),d(24 hours),h(60 minutes),m(60 seconds),s(1 second),ms(1 millisecond). Units can be combined, e.g.'3d','12h','1d12h30m','500ms'.retain_last = N— overrides the table-levelhistory.expire.min-snapshots-to-keepfor this invocation only. At leastNsnapshots are always retained regardless of age.snapshot_ids = [id1, id2, ...]— expires exactly the listed snapshot IDs (except snapshots referenced by current snapshot, branches, or tags). This mode bypasses the retention policy entirely and cannot be combined withretention_periodorretain_last.dry_run = 1— computes what would be expired and returns metrics without writing new metadata or deleting files.
retention_period and retain_last override only the table-level retention defaults. Per-ref (branch/tag) retention overrides configured in the Iceberg table properties (e.g., refs.<branch>.min-snapshots-to-keep) are never overridden — they always take effect as specified in the table metadata.metric_name String, metric_value Int64) containing one row per metric. The metric names follow the Iceberg spec:
The command performs the following steps:
- Evaluates the retention policy (see below) to determine which snapshots must be preserved
- If a timestamp argument was provided, additionally protects all snapshots at or newer than that timestamp
- Expires snapshots that are neither retained by the policy nor protected by the timestamp fuse
- Computes which files are exclusively associated with expired snapshots
- In normal mode: generates new metadata without the expired snapshots
- In normal mode: physically deletes unreachable manifest lists, manifest files, and data files
- In
dry_run = 1mode: skips steps 5 and 6 and only returns the calculated metrics
Snapshot Retention Policy
Theexpire_snapshots command respects the Iceberg snapshot retention policy. Retention is configured via Iceberg table properties and per-reference overrides:
Each snapshot reference (
refs in the Iceberg metadata) can override these with per-ref fields: min-snapshots-to-keep, max-snapshot-age-ms, and max-ref-age-ms.
Retention evaluation:
- For each branch (including
main): the ancestor chain is walked starting from the branch head. Snapshots are retained while either of these conditions is true:- The snapshot is one of the first
min-snapshots-to-keepin the chain - The snapshot’s age is within
max-snapshot-age-ms(i.e.,now - timestamp-ms <= max-snapshot-age-ms)
- The snapshot is one of the first
- For tags: the tagged snapshot is retained unless the tag has exceeded its
max-ref-age-ms, in which case the tag reference is removed - Non-main references whose age exceeds
max-ref-age-msare removed entirely (themainbranch is never removed) - Dangling references that point to non-existent snapshots are removed with a warning
- The current snapshot is always preserved, regardless of retention settings
ALTER TABLE EXECUTE privilege is required, which is a child of ALTER TABLE in the ClickHouse access control hierarchy. You can grant it specifically or via the parent:
- Only Iceberg format version 2 tables are supported (v1 snapshots do not guarantee
manifest-list, which is required to safely identify files for cleanup) - The current snapshot is always preserved, even if it is older than the specified timestamp
- Requires the
allow_insert_into_icebergsetting to be enabled - Requires the
allow_experimental_expire_snapshotssetting to be enabled - The catalog’s own authorization (REST catalog auth, AWS Glue IAM, etc.) is enforced independently when ClickHouse updates the metadata
Remove Orphan Files
Orphan files are files on storage that are not referenced by any snapshot in the Iceberg table metadata. They accumulate from failed writes, partial cleanup after compaction, and interrupted operations, causing unbounded storage growth. Theremove_orphan_files command identifies and removes these orphan files.
Syntax:
Examples:
metric_name and metric_value columns showing the count of deleted (or would-be-deleted in dry_run mode) files by category. File categories are classified using best-effort heuristics based on file naming conventions; files that do not match any specific pattern default to deleted_data_files_count:
Settings:
- Requires Iceberg format version 2 (or higher). Version 1 tables are rejected because they lack
manifest-listpointers in snapshots, which are needed to safely determine the reachable file set. Running the command on a v1 table returns aBAD_ARGUMENTSerror. - Requires both
allow_insert_into_icebergandallow_iceberg_remove_orphan_filessettings to be enabled - It is recommended to run
expire_snapshotsbeforeremove_orphan_filesso that files uniquely referenced by expired snapshots are cleaned up first - Use
dry_run = 1to preview orphan files before deletion - The
older_thanthreshold protects against deleting files from in-progress writes — the default 3-day threshold provides a generous safety margin