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

> Materializations available and their configurations

# Materializations

export const ClickHouseSupportedBadge = () => {
  return <div className="ClickHouseSupportedBadge">
            <div className="ClickHouseSupportedIcon">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1.30762 1.39073C1.30762 1.3103 1.37465 1.22986 1.46849 1.22986H2.64824C2.72868 1.22986 2.80912 1.29689 2.80912 1.39073V14.4886C2.80912 14.5691 2.74209 14.6495 2.64824 14.6495H1.46849C1.38805 14.6495 1.30762 14.5825 1.30762 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M4.2832 1.39073C4.2832 1.3103 4.35023 1.22986 4.44408 1.22986H5.62383C5.70427 1.22986 5.7847 1.29689 5.7847 1.39073V14.4886C5.7847 14.5691 5.71767 14.6495 5.62383 14.6495H4.44408C4.36364 14.6495 4.2832 14.5825 4.2832 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M7.25977 1.39073C7.25977 1.3103 7.3268 1.22986 7.42064 1.22986H8.60039C8.68083 1.22986 8.76127 1.29689 8.76127 1.39073V14.4886C8.76127 14.5691 8.69423 14.6495 8.60039 14.6495H7.42064C7.3402 14.6495 7.25977 14.5825 7.25977 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M10.2354 1.39073C10.2354 1.3103 10.3024 1.22986 10.3962 1.22986H11.576C11.6564 1.22986 11.7369 1.29689 11.7369 1.39073V14.4886C11.7369 14.5691 11.6698 14.6495 11.576 14.6495H10.3962C10.3158 14.6495 10.2354 14.5825 10.2354 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M13.2256 6.6057C13.2256 6.52526 13.2926 6.44482 13.3865 6.44482H14.5662C14.6466 6.44482 14.7271 6.51186 14.7271 6.6057V9.27354C14.7271 9.35398 14.6601 9.43442 14.5662 9.43442H13.3865C13.306 9.43442 13.2256 9.36739 13.2256 9.27354V6.6057Z" fill="currentColor" />
                </svg>
            </div>
            ClickHouse Supported
        </div>;
};

<ClickHouseSupportedBadge />

This section covers all the materializations available in dbt-clickhouse, including experimental features.

<h2 id="general-materialization-configurations">
  General materialization configurations
</h2>

The following table shows configurations shared by some of the available materializations. For in-depth information about general dbt model configurations, see the [dbt documentation](https://docs.getdbt.com/category/general-configs):

| Option          | Description                                                                                                                                                     | Default if any |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| engine          | The table engine (type of table) to use when creating tables                                                                                                    | `MergeTree()`  |
| order\_by       | A tuple of column names or arbitrary expressions. This allows you to create a small sparse index that helps find data faster.                                   | `tuple()`      |
| partition\_by   | A partition is a logical combination of records in a table by a specified criterion. The partition key can be any expression from the table columns.            |                |
| primary\_key    | Like order\_by, a ClickHouse primary key expression.  If not specified, ClickHouse will use the order by expression as the primary key                          |                |
| settings        | A map/dictionary of "TABLE" settings to be used to DDL statements like 'CREATE TABLE' with this model                                                           |                |
| query\_settings | A map/dictionary of ClickHouse user level settings to be used with `INSERT` or `DELETE` statements in conjunction with this model                               |                |
| ttl             | A TTL expression to be used with the table.  The TTL expression is a string that can be used to specify the TTL for the table.                                  |                |
| sql\_security   | The ClickHouse user to use when executing the view's underlying query. [Accepted values](/reference/statements/create/view#sql_security): `definer`, `invoker`. |                |
| definer         | If `sql_security` was set to `definer`, you have to specify any existing user or `CURRENT_USER` in the `definer` clause.                                        |                |

<h3 id="supported-table-engines">
  Supported table engines
</h3>

| Type                   | Details                                                                       |
| ---------------------- | ----------------------------------------------------------------------------- |
| MergeTree (default)    | [docs](/reference/engines/table-engines/mergetree-family/mergetree).          |
| HDFS                   | [docs](/reference/engines/table-engines/integrations/hdfs)                    |
| MaterializedPostgreSQL | [docs](/reference/engines/table-engines/integrations/materialized-postgresql) |
| S3                     | [docs](/reference/engines/table-engines/integrations/s3)                      |
| EmbeddedRocksDB        | [docs](/reference/engines/table-engines/integrations/embedded-rocksdb)        |
| Hive                   | [docs](/reference/engines/table-engines/integrations/hive)                    |

**Note**: for materialized views, all \*MergeTree engines are supported.

<h4 id="experimental-supported-table-engines">
  Experimental supported table engines
</h4>

| Type              | Details                                                       |
| ----------------- | ------------------------------------------------------------- |
| Distributed Table | [docs](/reference/engines/table-engines/special/distributed). |
| Dictionary        | [docs](/reference/engines/table-engines/special/dictionary)   |

If you encounter issues connecting to ClickHouse from dbt with one of the above engines, please report an
issue [here](https://github.com/ClickHouse/dbt-clickhouse/issues).

<h3 id="a-note-on-model-settings">
  A note on model settings
</h3>

ClickHouse has several types/levels of "settings". In the model configuration above, two types of these are
configurable.  `settings` means the `SETTINGS`
clause used in `CREATE TABLE/VIEW` types of DDL statements, so this is generally settings that are specific to the
specific ClickHouse table engine. The new
`query_settings` is use to add a `SETTINGS` clause to the `INSERT` and `DELETE` queries used for model materialization (
including incremental materializations).
There are hundreds of ClickHouse settings, and it's not always clear which is a "table" setting and which is a "user"
setting (although the latter are generally
available in the `system.settings` table.)  In general the defaults are recommended, and any use of these properties
should be carefully researched and tested.

<h3 id="column-configuration">
  Column Configuration
</h3>

> ***NOTE:*** The column configuration options below require [model contracts](https://docs.getdbt.com/docs/collaborate/govern/model-contracts) to be enforced.

| Option | Description                                                                                                                                                                                                                            | Default if any |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| codec  | A string consisting of arguments passed to `CODEC()` in the column's DDL. For example: `codec: "Delta, ZSTD"` will be compiled as `CODEC(Delta, ZSTD)`.                                                                                |                |
| ttl    | A string consisting of a [TTL (time-to-live) expression](/concepts/features/operations/delete/ttl) that defines a TTL rule in the column's DDL. For example: `ttl: ts + INTERVAL 1 DAY` will be compiled as `TTL ts + INTERVAL 1 DAY`. |                |

<h4 id="example-of-schema-configuration">
  Example of schema configuration
</h4>

```yaml theme={null}
models:
  - name: table_column_configs
    description: 'Testing column-level configurations'
    config:
      contract:
        enforced: true
    columns:
      - name: ts
        data_type: timestamp
        codec: ZSTD
      - name: x
        data_type: UInt8
        ttl: ts + INTERVAL 1 DAY
```

<h4 id="adding-complex-types">
  Adding complex types
</h4>

dbt automatically determines the data type of each column by analyzing the SQL used to create the model. However, in some cases this process may not accurately determine the data type, leading to conflicts with the types specified in the contract `data_type` property. To address this, we recommend using the `CAST()` function in the model SQL to explicitly define the desired type. For example:

```sql theme={null}
{{
    config(
        materialized="materialized_view",
        engine="AggregatingMergeTree",
        order_by=["event_type"],
    )
}}

select
  -- event_type may be infered as a String but we may prefer LowCardinality(String):
  CAST(event_type, 'LowCardinality(String)') as event_type,
  -- countState() may be infered as `AggregateFunction(count)` but we may prefer to change the type of the argument used:
  CAST(countState(), 'AggregateFunction(count, UInt32)') as response_count, 
  -- maxSimpleState() may be infered as `SimpleAggregateFunction(max, String)` but we may prefer to also change the type of the argument used:
  CAST(maxSimpleState(event_type), 'SimpleAggregateFunction(max, LowCardinality(String))') as max_event_type
from {{ ref('user_events') }}
group by event_type
```

<h2 id="materialization-view">
  Materialization: view
</h2>

A dbt model can be created as a [ClickHouse view](/reference/functions/table-functions/view)
and configured using the following syntax:

Project File (`dbt_project.yml`):

```yaml theme={null}
models:
  <resource-path>:
    +materialized: view
```

Or config block (`models/<model_name>.sql`):

```python theme={null}
{{ config(materialized = "view") }}
```

<h2 id="materialization-table">
  Materialization: table
</h2>

A dbt model can be created as a [ClickHouse table](/reference/system-tables/tables) and
configured using the following syntax:

Project File (`dbt_project.yml`):

```yaml theme={null}
models:
  <resource-path>:
    +materialized: table
    +order_by: [ <column-name>, ... ]
    +engine: <engine-type>
    +partition_by: [ <column-name>, ... ]
```

Or config block (`models/<model_name>.sql`):

```python theme={null}
{{ config(
    materialized = "table",
    engine = "<engine-type>",
    order_by = [ "<column-name>", ... ],
    partition_by = [ "<column-name>", ... ],
      ...
    ]
) }}
```

<h3 id="data-skipping-indexes">
  Data skipping indexes
</h3>

You can add [data skipping indexes](/concepts/features/performance/skip-indexes/skipping-indexes) to `table` materializations using the `indexes` configuration:

```sql theme={null}
{{ config(
        materialized='table',
        indexes=[{
          'name': 'your_index_name',
          'definition': 'your_column TYPE minmax GRANULARITY 2'
        }]
) }}
```

<h3 id="projections">
  Projections
</h3>

You can add [projections](/concepts/features/projections/projections) to `table` and `distributed_table` materializations using the `projections` configuration. Each projection entry requires either a `query` or an `index` key (not both).

**Note**: For distributed tables, the projection is applied to the `_local` tables, not to the distributed proxy table.
**Note**: Specifying both `query` and `index` on the same projection entry raises a compile-time error.

<h4 id="query-projections">
  Query projections
</h4>

Use `query` to define a full projection query:

```sql theme={null}
{{ config(
       materialized='table',
       projections=[
           {
               'name': 'your_projection_name',
               'query': 'SELECT department, avg(age) AS avg_age GROUP BY department'
           }
       ]
) }}
```

<h4 id="index-projections">
  Index projections
</h4>

Use `index` as syntax sugar for lightweight [index projections](https://clickhouse.com/blog/clickhouse-release-25-06#index-projections) that use the `_part_offset` virtual column. Pass a single column name or a list of columns to order by:

```sql theme={null}
{{ config(
       materialized='table',
       projections=[
           {
               'name': 'proj_by_age',
               'index': 'age'
           }
       ]
) }}
```

```sql theme={null}
{{ config(
       materialized='table',
       projections=[
           {
               'name': 'proj_by_dept_age',
               'index': ['department', 'age']
           }
       ]
) }}
```

dbt-clickhouse generates version-appropriate DDL automatically:

| ClickHouse version | Generated SQL                                                   |
| ------------------ | --------------------------------------------------------------- |
| 26.1+              | `ADD PROJECTION proj_by_age INDEX age TYPE basic`               |
| 25.8 – 26.0        | `ADD PROJECTION proj_by_age (SELECT _part_offset ORDER BY age)` |

<h2 id="materialization-incremental">
  Materialization: incremental
</h2>

Table model will be reconstructed for each dbt execution. This may be infeasible and extremely costly for larger result sets or complex transformations. To address this challenge and reduce the build time, a dbt model can be created as an incremental ClickHouse table and is configured using the following syntax:

Model definition in `dbt_project.yml`:

```yaml theme={null}
models:
  <resource-path>:
    +materialized: incremental
    +order_by: [ <column-name>, ... ]
    +engine: <engine-type>
    +partition_by: [ <column-name>, ... ]
    +unique_key: [ <column-name>, ... ]
    +inserts_only: [ True|False ]
```

Or config block in `models/<model_name>.sql`:

```python theme={null}
{{ config(
    materialized = "incremental",
    engine = "<engine-type>",
    order_by = [ "<column-name>", ... ],
    partition_by = [ "<column-name>", ... ],
    unique_key = [ "<column-name>", ... ],
    inserts_only = [ True|False ],
      ...
    ]
) }}
```

<h3 id="incremental-configurations">
  Configurations
</h3>

Configurations that are specific for this materialization type are listed below:

| Option                   | Description                                                                                                                                                                                                                                                                                                            | Required?                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `unique_key`             | A tuple of column names that uniquely identify rows. For more details on uniqueness constraints, see [here](https://docs.getdbt.com/docs/build/incremental-models#defining-a-unique-key-optional).                                                                                                                     | Required. If not provided altered rows will be added twice to the incremental table. |
| `inserts_only`           | It has been deprecated in favor of the `append` incremental `strategy`, which operates in the same way. If set to True for an incremental model, incremental updates will be inserted directly to the target table without creating intermediate table. . If `inserts_only` is set, `incremental_strategy` is ignored. | Optional (default: `False`)                                                          |
| `incremental_strategy`   | The strategy to use for incremental materialization.  `delete+insert`, `append`, `insert_overwrite`, or `microbatch` are supported.  For additional details on strategies, see [here](#incremental-model-strategies)                                                                                                   | Optional (default: 'default')                                                        |
| `incremental_predicates` | Additional conditions to be applied to the incremental materialization (only applied to `delete+insert` strategy                                                                                                                                                                                                       | Optional                                                                             |

<h3 id="incremental-model-strategies">
  Incremental Model Strategies
</h3>

`dbt-clickhouse` supports three incremental model strategies.

<h4 id="default-legacy-strategy">
  The Default (Legacy) Strategy
</h4>

Historically ClickHouse has had only limited support for updates and deletes, in the form of asynchronous "mutations."
To emulate expected dbt behavior,
dbt-clickhouse by default creates a new temporary table containing all unaffected (not deleted, not changed) "old"
records, plus any new or updated records,
and then swaps or exchanges this temporary table with the existing incremental model relation. This is the only strategy
that preserves the original relation if something
goes wrong before the operation completes; however, since it involves a full copy of the original table, it can be quite
expensive and slow to execute.

<h4 id="delete-insert-strategy">
  The Delete+Insert Strategy
</h4>

The `delete+insert` strategy uses [lightweight deletes](/concepts/features/operations/delete/lightweight-delete) to remove the affected rows and then inserts the new ones. Because it doesn't copy the whole table, it performs significantly better than the "legacy" strategy. Setting `use_lw_deletes: true` in your profile makes `delete+insert` the default incremental strategy.

There are important caveats to using this strategy:

* It operates directly on the affected table without creating any intermediate or temporary tables, so if there is an
  issue during the operation, the data in the incremental model is likely to be in an invalid state.
* It requires the ClickHouse setting `allow_nondeterministic_mutations`. The adapter enables it automatically for its
  own sessions when possible. When it can't be enabled (for example, it's read-only for your dbt user), the behavior
  depends on how the strategy was chosen: models relying on the default strategy silently fall back to the legacy
  strategy, models that explicitly set `delete+insert` or `microbatch` fail at runtime, and `use_lw_deletes: true` in
  the profile fails at connection time.
* In some very rare cases, using non-deterministic `incremental_predicates` could result in a race condition for the
  updated/deleted items. To ensure consistent results, the incremental predicates should only include sub-queries on
  data that will not be modified during the incremental materialization.

<h4 id="microbatch-strategy">
  The Microbatch Strategy (Requires dbt-core >= 1.9)
</h4>

The incremental strategy `microbatch` has been a dbt-core feature since version 1.9, designed to handle large
time-series data transformations efficiently. In dbt-clickhouse, it builds on top of the existing `delete_insert`
incremental strategy by splitting the increment into predefined time-series batches based on the `event_time` and
`batch_size` model configurations.

Beyond handling large transformations, microbatch provides the ability to:

* [Reprocess failed batches](https://docs.getdbt.com/docs/build/incremental-microbatch#retry).
* Auto-detect [parallel batch execution](https://docs.getdbt.com/docs/build/parallel-batch-execution).
* Eliminate the need for complex conditional logic in [backfilling](https://docs.getdbt.com/docs/build/incremental-microbatch#backfills).

For detailed microbatch usage, refer to the [official documentation](https://docs.getdbt.com/docs/build/incremental-microbatch).

<h5 id="available-microbatch-configurations">
  Available Microbatch Configurations
</h5>

| Option              | Description                                                                                                                                                                                                                                                                                                                                | Default if any |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- |
| event\_time         | The column indicating "at what time did the row occur." Required for your microbatch model and any direct parents that should be filtered.                                                                                                                                                                                                 |                |
| begin               | The "beginning of time" for the microbatch model. This is the starting point for any initial or full-refresh builds. For example, a daily-grain microbatch model run on 2024-10-01 with begin = '2023-10-01 will process 366 batches (it's a leap year!) plus the batch for "today."                                                       |                |
| batch\_size         | The granularity of your batches. Supported values are `hour`, `day`, `month`, and `year`                                                                                                                                                                                                                                                   |                |
| lookback            | Process X batches prior to the latest bookmark to capture late-arriving records.                                                                                                                                                                                                                                                           | 1              |
| concurrent\_batches | Overrides dbt's auto detect for running batches concurrently (at the same time). Read more about [configuring concurrent batches](https://docs.getdbt.com/docs/build/incremental-microbatch#configure-concurrent_batches). Setting to true runs batches concurrently (in parallel). false runs batches sequentially (one after the other). |                |

<h4 id="append-strategy">
  The Append Strategy
</h4>

This strategy replaces the `inserts_only` setting in previous versions of dbt-clickhouse. This approach simply appends
new rows to the existing relation.
As a result duplicate rows are not eliminated, and there is no temporary or intermediate table. It is the fastest
approach if duplicates are either permitted
in the data or excluded by the incremental query WHERE clause/filter.

<h4 id="insert-overwrite-strategy">
  The insert\_overwrite Strategy (Experimental)
</h4>

> \[IMPORTANT]\
> Currently, the insert\_overwrite strategy is not fully functional with distributed materializations.

Performs the following steps:

1. Create a staging (temporary) table with the same structure as the incremental model relation:
   `CREATE TABLE <staging> AS <target>`.
2. Insert only new records (produced by `SELECT`) into the staging table.
3. Replace only new partitions (present in the staging table) into the target table.

This approach has the following advantages:

* It is faster than the default strategy because it doesn't copy the entire table.
* It is safer than other strategies because it doesn't modify the original table until the INSERT operation completes
  successfully: in case of intermediate failure, the original table is not modified.
* It implements "partitions immutability" data engineering best practice. Which simplifies incremental and parallel data
  processing, rollbacks, etc.

The strategy requires `partition_by` to be set in the model configuration. Ignores all other strategies-specific
parameters of the model config.

<h2 id="materialized-view">
  Materialization: materialized\_view
</h2>

The `materialized_view` materialization creates a ClickHouse [materialized view](/reference/statements/create/view#materialized-view) that acts as an insert trigger, automatically transforming and inserting new rows from a source table into a target table. This is one of the most powerful materializations available in dbt-clickhouse.

Due to its depth, this materialization has its own dedicated page. **[Go to the Materialized Views guide](/integrations/connectors/data-ingestion/etl-tools/dbt/materialization-materialized-view)** for the full documentation

<h2 id="materialization-dictionary">
  Materialization: dictionary (experimental)
</h2>

A dbt model can be created as a ClickHouse [dictionary](/concepts/features/dictionaries/index). On every `dbt run` the dictionary is replaced with the current model definition using `CREATE OR REPLACE DICTIONARY`.

<h3 id="dictionary-configurations">
  Configurations
</h3>

| Option                 | Description                                                                                                                                                                                                                                                 | Required       |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `fields`               | The dictionary structure, as a list of `(name, type)` pairs.                                                                                                                                                                                                | Yes            |
| `primary_key`          | The dictionary primary key. Must match the key type expected by the chosen layout (for example, a complex key for `COMPLEX_KEY_*` layouts).                                                                                                                 | Yes            |
| `layout`               | The [layout](/reference/statements/create/dictionary/layouts/overview) used to store the dictionary in memory, such as `HASHED()`, `COMPLEX_KEY_HASHED()` or `DIRECT()`.                                                                                    | Yes            |
| `source_type`          | Where the dictionary reads its data from: `clickhouse` (default, uses the model's SQL or the `table` option) or `http`.                                                                                                                                     |                |
| `lifetime`             | The [`LIFETIME`](/reference/statements/create/dictionary/lifetime) clause controlling how often the dictionary is refreshed, e.g. `MIN 0 MAX 300`. Optional since dbt-clickhouse 1.10.0 — omit it for layouts that don't use it, such as `DIRECT()`.        |                |
| `table`                | `clickhouse` source only. Read from an existing table instead of the model's SQL.                                                                                                                                                                           |                |
| `update_field`         | `clickhouse` source only. Refresh the dictionary incrementally by fetching only rows whose value in this column changed since the previous update. See [LIFETIME](/reference/statements/create/dictionary/lifetime). Available since dbt-clickhouse 1.10.0. |                |
| `update_lag`           | `clickhouse` source only. Number of seconds subtracted from the previous update time when using `update_field`, to account for late-arriving updates. Available since dbt-clickhouse 1.10.0.                                                                |                |
| `connection_overrides` | `clickhouse` source only. Overrides for the credentials used in the dictionary's `SOURCE` clause, e.g. `{'user': 'dictionary_reader'}`.                                                                                                                     |                |
| `url`, `format`        | `http` source only. The URL of the source file and its input format.                                                                                                                                                                                        | Yes for `http` |
| `range`                | The `RANGE` clause for `RANGE_HASHED()` layouts, e.g. `'min start max stop'`.                                                                                                                                                                               |                |

<h3 id="dictionary-clickhouse-source-example">
  Example with a ClickHouse source
</h3>

The model's SQL becomes the dictionary source query:

```sql theme={null}
{{ config(
       materialized='dictionary',
       fields=[
           ('id', 'UInt64'),
           ('name', 'String'),
       ],
       primary_key='id',
       layout='HASHED()',
       lifetime='MIN 0 MAX 300'
) }}

select id, name from {{ source('raw', 'people') }}
```

<h3 id="dictionary-http-source-example">
  Example with an HTTP source
</h3>

When using `source_type='http'` (or the `table` option), the model's SQL is not used as the source, but dbt still requires a body — use a `select 1` placeholder:

```sql theme={null}
{{ config(
       materialized='dictionary',
       fields=[
           ('LocationID', 'UInt16 DEFAULT 0'),
           ('Borough', 'String'),
           ('Zone', 'String'),
       ],
       primary_key='LocationID',
       layout='HASHED()',
       lifetime='MIN 0 MAX 0',
       source_type='http',
       url='https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/taxi_zone_lookup.csv',
       format='CSVWithNames'
) }}

select 1
```

See the [dictionary tests](https://github.com/ClickHouse/dbt-clickhouse/blob/main/tests/integration/adapter/dictionary/test_dictionary.py) for more examples, including range and direct dictionaries.

<h2 id="materialization-distributed-table">
  Materialization: distributed\_table (experimental)
</h2>

Distributed table created with following steps:

1. Creates temp view with sql query to get right structure
2. Create empty local tables based on view
3. Create distributed table based on local tables.
4. Data inserts into distributed table, so it is distributed across shards without duplicating.

Notes:

* dbt-clickhouse queries now automatically include the setting `insert_distributed_sync = 1` in order to ensure that
  downstream incremental
  materialization operations execute correctly. This could cause some distributed table inserts to run more slowly than
  expected.

<h3 id="distributed-table-model-example">
  Distributed table model example
</h3>

```sql theme={null}
{{
    config(
        materialized='distributed_table',
        order_by='id, created_at',
        sharding_key='cityHash64(id)',
        engine='ReplacingMergeTree'
    )
}}

select id, created_at, item
from {{ source('db', 'table') }}
```

<h3 id="distributed-table-generated-migrations">
  Generated migrations
</h3>

```sql theme={null}
CREATE TABLE db.table_local on cluster cluster (
    `id` UInt64,
    `created_at` DateTime,
    `item` String
)
    ENGINE = ReplacingMergeTree
    ORDER BY (id, created_at);

CREATE TABLE db.table on cluster cluster (
    `id` UInt64,
    `created_at` DateTime,
    `item` String
)
    ENGINE = Distributed ('cluster', 'db', 'table_local', cityHash64(id));
```

<h3 id="distributed-table-configurations">
  Configurations
</h3>

Configurations that are specific for this materialization type are listed below:

| Option        | Description                                                                                                                                                     | Default if any |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| sharding\_key | Sharding key determines the destination server when inserting into distributed engine table.  The sharding key can be random or as an output of a hash function | `rand()`)      |

<h2 id="materialization-distributed-incremental">
  materialization: distributed\_incremental (experimental)
</h2>

Incremental model based on the same idea as distributed table, the main difficulty is to process all incremental
strategies correctly.

1. *The Append Strategy* just insert data into distributed table.
2. *The Delete+Insert* Strategy creates distributed temp table to work with all data on every shard.
3. *The Default (Legacy) Strategy* creates distributed temp and intermediate tables for the same reason.

Only shard tables are replacing, because distributed table does not keep data.
The distributed table reloads only when the full\_refresh mode is enabled or the table structure may have changed.

<h3 id="distributed-incremental-model-example">
  Distributed incremental model example
</h3>

```sql theme={null}
{{
    config(
        materialized='distributed_incremental',
        engine='MergeTree',
        incremental_strategy='append',
        unique_key='id,created_at'
    )
}}

select id, created_at, item
from {{ source('db', 'table') }}
```

<h3 id="distributed-incremental-generated-migrations">
  Generated migrations
</h3>

```sql theme={null}
CREATE TABLE db.table_local on cluster cluster (
    `id` UInt64,
    `created_at` DateTime,
    `item` String
)
    ENGINE = MergeTree;

CREATE TABLE db.table on cluster cluster (
    `id` UInt64,
    `created_at` DateTime,
    `item` String
)
    ENGINE = Distributed ('cluster', 'db', 'table_local', cityHash64(id));
```

<h2 id="snapshot">
  Snapshot
</h2>

dbt snapshots allow a record to be made of changes to a mutable model over time. This in turn allows point-in-time
queries on models, where analysts can "look back in time" at the previous state of a model. This functionality is
supported by the ClickHouse connector and is configured using the following syntax:

Config block in `snapshots/<model_name>.sql`:

```python theme={null}
{{
   config(
     schema = "<schema-name>",
     unique_key = "<column-name>",
     strategy = "<strategy>",
     updated_at = "<updated-at-column-name>",
   )
}}
```

For more information on configuration, check out the [snapshot configs](https://docs.getdbt.com/docs/build/snapshots#snapshot-configs) reference page.

<h2 id="contracts-and-constraints">
  Contracts and Constraints
</h2>

Only exact column type contracts are supported. For example, a contract with a UInt32 column type will fail if the model
returns a UInt64 or other integer type.
ClickHouse also support *only* `CHECK` constraints on the entire table/model. Primary key, foreign key, unique, and
column level CHECK constraints are not supported.
(See ClickHouse documentation on primary/order by keys.)
