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

> Este motor oferece integração somente leitura com tabelas Apache Iceberg existentes no Amazon S3, Azure, HDFS e com tabelas armazenadas localmente.

# Motor de tabela Iceberg

<Warning>
  Recomendamos usar a [Iceberg Table Function](/pt-BR/reference/functions/table-functions/iceberg) para trabalhar com dados Iceberg no ClickHouse. No momento, a Iceberg Table Function oferece funcionalidade suficiente, fornecendo uma interface parcial somente leitura para tabelas Iceberg.

  O Iceberg Table Engine está disponível, mas pode ter limitações. O ClickHouse não foi originalmente projetado para oferecer suporte a tabelas com esquemas alterados externamente, o que pode afetar a funcionalidade do Iceberg Table Engine. Como resultado, alguns recursos que funcionam com tabelas comuns podem não estar disponíveis ou podem não funcionar corretamente, especialmente ao usar o analisador antigo.

  Para garantir a melhor compatibilidade, sugerimos usar a Iceberg Table Function enquanto continuamos a aprimorar o suporte ao Iceberg Table Engine.
</Warning>

Este motor oferece integração somente leitura com tabelas Apache [Iceberg](https://iceberg.apache.org/) existentes no Amazon S3, Azure, HDFS e com tabelas armazenadas localmente.

<div id="create-table">
  ## Criar tabela
</div>

Observe que a tabela Iceberg já deve existir no armazenamento; este comando não aceita parâmetros de DDL para criar uma nova tabela.

```sql theme={null}
CREATE TABLE iceberg_table_s3
    ENGINE = IcebergS3(url,  [, NOSIGN | access_key_id, secret_access_key, [session_token]], format, [,compression], [,extra_credentials])

CREATE TABLE iceberg_table_azure
    ENGINE = IcebergAzure(connection_string|storage_account_url, container_name, blobpath, [account_name, account_key, format, compression])

CREATE TABLE iceberg_table_hdfs
    ENGINE = IcebergHDFS(path_to_table, [,format] [,compression_method])

CREATE TABLE iceberg_table_local
    ENGINE = IcebergLocal(path_to_table, [,format] [,compression_method])
```

<div id="engine-arguments">
  ## Argumentos do motor
</div>

A descrição dos argumentos coincide com a descrição dos argumentos dos motores `S3`, `AzureBlobStorage`, `HDFS` e `File`, respectivamente.
`format` indica o formato dos arquivos de dados na tabela Iceberg.

Para `IcebergS3`, é possível usar um parâmetro opcional `extra_credentials` para passar um `role_arn` para controle de acesso baseado em função no ClickHouse Cloud. Consulte [S3 seguro](/pt-BR/products/cloud/guides/data-sources/accessing-s3-data-securely) para ver as etapas de configuração.

Os parâmetros do motor podem ser especificados usando [Coleções nomeadas](/pt-BR/concepts/features/configuration/server-config/named-collections)

<div id="example">
  ### Exemplo
</div>

```sql theme={null}
CREATE TABLE iceberg_table ENGINE=IcebergS3('http://test.s3.amazonaws.com/clickhouse-bucket/test_table', 'test', 'test')
```

Usando coleções nomeadas:

```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>
        </iceberg_conf>
    </named_collections>
</clickhouse>
```

```sql theme={null}
CREATE TABLE iceberg_table ENGINE=IcebergS3(iceberg_conf, filename = 'test_table')

```

<div id="aliases">
  ## Aliases
</div>

O motor de tabela `Iceberg` detecta automaticamente o backend de armazenamento com base na configuração `disk` e encaminha para `IcebergS3`, `IcebergAzure` ou `IcebergLocal`, conforme o caso. Quando nenhum `disk` é especificado, a implementação padrão é `IcebergS3`.

<div id="data-types">
  ## Tipos de dados
</div>

A tabela a seguir mostra como os tipos de dados do Iceberg são mapeados para os tipos de dados do ClickHouse durante a inferência de esquema (para leitura).

<div id="primitive-types">
  ### Tipos primitivos
</div>

| Tipo do Iceberg    | Tipo do ClickHouse     | Observações                                                     |
| ------------------ | ---------------------- | --------------------------------------------------------------- |
| `boolean`          | `Bool`                 |                                                                 |
| `int`              | `Int32`                |                                                                 |
| `long`, `bigint`   | `Int64`                |                                                                 |
| `float`            | `Float32`              |                                                                 |
| `double`           | `Float64`              |                                                                 |
| `date`             | `Date32`               |                                                                 |
| `time`             | `Int64`                | Microssegundos desde a meia-noite                               |
| `timestamp`        | `DateTime64(6)`        | Microssegundos, sem timezone                                    |
| `timestamptz`      | `DateTime64(6, 'UTC')` | Microssegundos, timezone UTC                                    |
| `timestamp_ns`     | `DateTime64(9)`        | Nanossegundos, sem timezone (apenas no Iceberg v3 ou posterior) |
| `timestamptz_ns`   | `DateTime64(9, 'UTC')` | Nanossegundos, timezone UTC (apenas no Iceberg v3 ou posterior) |
| `string`, `binary` | `String`               |                                                                 |
| `uuid`             | `UUID`                 |                                                                 |
| `fixed(N)`         | `FixedString(N)`       |                                                                 |
| `decimal(P, S)`    | `Decimal(P, S)`        |                                                                 |

<div id="complex-types">
  ### Tipos complexos
</div>

| Tipo do Iceberg | Tipo do ClickHouse |
| --------------- | ------------------ |
| `list`          | `Array`            |
| `map`           | `Map`              |
| `struct`        | `Tuple`            |

<div id="schema-evolution">
  ## Evolução de esquema
</div>

O ClickHouse oferece suporte à leitura de tabelas Iceberg cujo esquema evoluiu ao longo do tempo. Isso inclui tabelas em que colunas foram adicionadas, removidas ou reordenadas, bem como colunas que passaram de obrigatórias para Nullable. Além disso, há suporte para as seguintes conversões de tipo:

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

No momento, não é possível alterar estruturas aninhadas nem os tipos dos elementos dentro de arrays e maps.

Para ler uma tabela cujo esquema foi alterado após sua criação com inferência dinâmica de esquema, defina allow\_dynamic\_metadata\_for\_data\_lakes = true ao criar a tabela.

<div id="partition-pruning">
  ## Poda de partições
</div>

O ClickHouse oferece suporte à poda de partições durante consultas SELECT em tabelas Iceberg, o que ajuda a otimizar o desempenho das consultas ao ignorar arquivos de dados irrelevantes. Para habilitar a poda de partições, defina `use_iceberg_partition_pruning = 1`. Para mais informações sobre a poda de partições do Iceberg, acesse [https://iceberg.apache.org/spec/#partitioning](https://iceberg.apache.org/spec/#partitioning)

<div id="time-travel">
  ## Viagem no tempo
</div>

O ClickHouse oferece suporte a viagem no tempo em tabelas Iceberg, permitindo consultar dados históricos usando um timestamp específico ou um ID de snapshot.

<div id="deleted-rows">
  ## Processamento de tabelas com linhas excluídas
</div>

O ClickHouse oferece suporte à leitura de tabelas Iceberg que usam os seguintes métodos de exclusão:

* [Exclusões por posição](https://iceberg.apache.org/spec/#position-delete-files)
* [Exclusões por igualdade](https://iceberg.apache.org/spec/#equality-delete-files) (suportadas a partir da versão 25.8+)

O método de exclusão a seguir **não é suportado**:

* [Vetores de exclusão](https://iceberg.apache.org/spec/#deletion-vectors) (introduzido na v3)

<div id="basic-usage">
  ### Uso básico
</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
```

Observação: não é possível especificar os parâmetros `iceberg_timestamp_ms` e `iceberg_snapshot_id` na mesma consulta.

<div id="important-considerations">
  ### Considerações importantes
</div>

* **Snapshots** normalmente são criados quando:
  * Novos dados são gravados na tabela
  * É realizada algum tipo de compactação de dados

* **Alterações de esquema normalmente não criam snapshots** - Isso resulta em comportamentos importantes ao usar viagem no tempo com tabelas que passaram por evolução de esquema.

<div id="example-scenarios">
  ### Cenários de exemplo
</div>

Todos os cenários estão em Spark porque o CH ainda não oferece suporte à gravação em tabelas Iceberg.

<div id="scenario-1">
  #### Cenário 1: Alterações de esquema sem novos snapshots
</div>

Considere esta sequência de operações:

```sql theme={null}
 -- Criar uma tabela com duas colunas
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example (
  order_number int, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

-- Inserir dados na tabela
  INSERT INTO spark_catalog.db.time_travel_example VALUES 
    (1, 'Mars')

  ts1 = now() // Um trecho de pseudocódigo

-- Alterar a tabela para adicionar uma nova coluna
  ALTER TABLE spark_catalog.db.time_travel_example ADD COLUMN (price double)
 
  ts2 = now()

-- Inserir dados na tabela
  INSERT INTO spark_catalog.db.time_travel_example VALUES (2, 'Venus', 100)

   ts3 = now()

-- Consultar a tabela em cada 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|
+------------+------------+-----+
```

Resultados da consulta em diferentes timestamps:

* Em ts1 & ts2: aparecem apenas as duas colunas originais
* Em ts3: aparecem as três colunas, com NULL no preço da primeira linha

<div id="scenario-2">
  #### Cenário 2: Diferenças entre o esquema histórico e o atual
</div>

Uma consulta de viagem no tempo no momento atual pode mostrar um esquema diferente do esquema atual da tabela:

```sql theme={null}
-- Criar uma tabela
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_2 (
  order_number int, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

-- Inserir dados iniciais na tabela
  INSERT INTO spark_catalog.db.time_travel_example_2 VALUES (2, 'Venus');

-- Alterar a tabela para adicionar uma nova coluna
  ALTER TABLE spark_catalog.db.time_travel_example_2 ADD COLUMN (price double);

  ts = now();

-- Consultar a tabela no momento atual usando sintaxe de timestamp

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

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

-- Consultar a tabela no momento atual
  SELECT * FROM spark_catalog.db.time_travel_example_2;
    +------------+------------+-----+
    |order_number|product_code|price|
    +------------+------------+-----+
    |           2|       Venus| NULL|
    +------------+------------+-----+
```

Isso acontece porque `ALTER TABLE` não cria um novo snapshot; para a tabela atual, o Spark obtém o valor de `schema_id` do arquivo de metadados mais recente, e não de um snapshot.

<div id="scenario-3">
  #### Cenário 3: Diferenças entre o esquema histórico e o atual
</div>

A segunda é que, ao usar a viagem no tempo, não é possível obter o estado da tabela antes de qualquer dado ter sido gravado nela:

```sql theme={null}
-- Criar uma tabela
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_3 (
  order_number int, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2');

  ts = now();

-- Consultar a tabela em um timestamp específico
  SELECT * FROM spark_catalog.db.time_travel_example_3 TIMESTAMP AS OF ts; -- Finaliza com erro: Cannot find a snapshot older than ts.
```

No ClickHouse, o comportamento é consistente com o do Spark. Você pode mentalmente substituir as consultas Select do Spark pelas consultas Select do ClickHouse, e isso funcionará da mesma forma.

<div id="metadata-file-resolution">
  ## Resolução do arquivo de metadados
</div>

Ao usar o motor de tabela `Iceberg` no ClickHouse, o sistema precisa localizar o arquivo metadata.json correto que descreve a estrutura da tabela Iceberg. Veja como esse processo de resolução funciona:

<div id="candidate-search">
  ### Busca de candidatos
</div>

1. **Especificação direta do caminho**:

* Se você definir `iceberg_metadata_file_path`, o sistema usará esse caminho exato, combinando-o com o caminho do diretório da tabela Iceberg.
* Quando essa configuração é fornecida, todas as outras configurações de resolução são ignoradas.

2. **Correspondência do UUID da tabela**:

* Se `iceberg_metadata_table_uuid` for especificado, o sistema:
  * Examinará apenas os arquivos `.metadata.json` no diretório `metadata`
  * Filtrará os arquivos que contêm um campo `table-uuid` correspondente ao UUID especificado (sem diferenciar maiúsculas de minúsculas)

3. **Busca padrão**:

* Se nenhuma das configurações acima for fornecida, todos os arquivos `.metadata.json` no diretório `metadata` passam a ser candidatos

<div id="most-recent-file">
  ### Seleção do arquivo mais recente
</div>

Depois de identificar os arquivos candidatos usando as regras acima, o sistema determina qual deles é o mais recente:

* Se `iceberg_recent_metadata_file_by_last_updated_ms_field` estiver habilitado:
  * O arquivo com o maior valor de `last-updated-ms` será selecionado

* Caso contrário:
  * O arquivo com o maior número de versão será selecionado
  * (A versão aparece como `V` em nomes de arquivo no formato `V.metadata.json` ou `V-uuid.metadata.json`)

**Observação**: Todas as configurações mencionadas (salvo indicação explícita em contrário) são configurações no nível da engine e devem ser especificadas durante a criação da tabela, como mostrado abaixo:

```sql theme={null}
CREATE TABLE example_table ENGINE = Iceberg(
    's3://bucket/path/to/iceberg_table'
) SETTINGS iceberg_metadata_table_uuid = '6f6f6407-c6a5-465f-a808-ea8900e35a38';
```

**Observação**: Embora os catálogos Iceberg normalmente façam a resolução de metadados, o mecanismo de tabela `Iceberg` do ClickHouse interpreta diretamente arquivos armazenados no S3 como tabelas Iceberg, por isso é importante entender essas regras de resolução.

<div id="data-cache">
  ## Cache de dados
</div>

O motor de tabela e a função de tabela `Iceberg` oferecem suporte a cache de dados, assim como `S3`, `AzureBlobStorage` e `HDFS`. Veja [aqui](/pt-BR/reference/engines/table-engines/integrations/s3#data-cache).

<div id="metadata-cache">
  ## Cache de metadados
</div>

O motor de tabela `Iceberg` e a função de tabela oferecem suporte a um cache de metadados que armazena informações dos arquivos de manifesto, da lista de manifestos e do JSON de metadados. O cache é armazenado em memória. Esse recurso é controlado pela configuração `use_iceberg_metadata_files_cache`, que vem habilitada por padrão.

<div id="async-metadata-prefetch">
  ## Pré-busca assíncrona de metadados
</div>

A pré-busca assíncrona de metadados pode ser habilitada na criação da tabela `Iceberg` definindo `iceberg_metadata_async_prefetch_period_ms`. Se for definido como 0 (padrão) ou se o cache de metadados não estiver habilitado, a pré-busca assíncrona será desabilitada.
Para habilitar esse recurso, deve ser informado um valor diferente de zero, em milissegundos. Esse valor representa o intervalo entre os ciclos de pré-busca.

Se estiver habilitado, o servidor executará uma operação recorrente em segundo plano para listar o catálogo remoto e detectar uma nova versão dos metadados. Em seguida, ele fará a análise desses metadados e percorrerá recursivamente o snapshot, buscando arquivos ativos de lista de manifestos e arquivos de manifesto.
Os arquivos já disponíveis no cache de metadados não serão baixados novamente. Ao final de cada ciclo de pré-busca, o snapshot de metadados mais recente estará disponível no cache de metadados.

```sql theme={null}
CREATE TABLE example_table ENGINE = Iceberg(
    's3://bucket/path/to/iceberg_table'
) SETTINGS
    iceberg_metadata_async_prefetch_period_ms = 60000;
```

Para aproveitar ao máximo a pré-busca assíncrona de metadados em operações de leitura, o parâmetro `iceberg_metadata_staleness_ms` deve ser especificado como parâmetro de consulta ou de sessão. Por padrão (0 - não especificado), no contexto de cada consulta, o servidor buscará os metadados mais recentes no catálogo remoto.
Ao especificar uma tolerância à defasagem dos metadados, o servidor pode usar a versão em cache do snapshot de metadados sem consultar o catálogo remoto. Se houver uma versão dos metadados no cache e ela tiver sido baixada dentro do intervalo de defasagem informado, ela será usada para processar a consulta.
Caso contrário, a versão mais recente será buscada no catálogo remoto.

```sql theme={null}
SELECT count() FROM icebench_table WHERE ...
SETTINGS iceberg_metadata_staleness_ms=120000
```

**Observação**: A pré-busca assíncrona de metadados é executada no `ICEBERG_SCEDULE_POOL`, um threadpool do servidor para operações em segundo plano em tabelas `Iceberg` ativas. O tamanho desse threadpool é controlado pelo parâmetro de configuração do servidor `iceberg_background_schedule_pool_size` (o padrão é 10).

**Observação**: Atualmente, espera-se que o tamanho do cache de metadados seja suficiente para armazenar integralmente o snapshot de metadados mais recente de todas as tabelas ativas, se a pré-busca assíncrona estiver habilitada.

<div id="see-also">
  ## Veja também
</div>

* [função de tabela iceberg](/pt-BR/reference/functions/table-functions/iceberg)
