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

> 타임스탬프와 태그(또는 레이블)에 연결된 값 집합, 즉 시계열을 저장하는 테이블 엔진입니다.

# TimeSeries 테이블 엔진

export const PrivatePreviewBadge = () => {
  return <div className="privatePreviewBadge">
            <div className="privatePreviewIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M5.33301 6.66667V4.66667V4.66667C5.33301 3.194 6.52701 2 7.99967 2V2C9.47234 2 10.6663 3.194 10.6663 4.66667V4.66667V6.66667" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path d="M8.00033 9.33337V11.3334" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path fillRule="evenodd" clipRule="evenodd" d="M11.333 14H4.66634C3.92967 14 3.33301 13.4033 3.33301 12.6666V7.99996C3.33301 7.26329 3.92967 6.66663 4.66634 6.66663H11.333C12.0697 6.66663 12.6663 7.26329 12.6663 7.99996V12.6666C12.6663 13.4033 12.0697 14 11.333 14Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            {'비공개 프리뷰'}
        </div>;
};

<PrivatePreviewBadge />

시계열, 즉 타임스탬프와 태그(또는 레이블)에 연결된 값 집합을 저장하는 테이블 엔진입니다:

```sql theme={null}
metric_name1[tag1=value1, tag2=value2, ...] = {timestamp1: value1, timestamp2: value2, ...}
metric_name2[...] = ...
```

<Info>
  이 기능은 비공개 프리뷰 기능이며, 향후 릴리스에서 하위 호환되지 않는 방식으로 변경될 수 있습니다.
  `enable_time_series_table` 설정을 사용하여
  TimeSeries 테이블 엔진 사용을 활성화하십시오.
  `set enable_time_series_table = 1` 명령을 입력하십시오.
</Info>

<Note>
  `TimeSeries` 테이블 엔진은 ClickHouse Cloud에서 비공개 프리뷰 기능으로 제공됩니다.
  비공개 프리뷰에 참여하는 서비스에는 이미 `enable_time_series_table` 설정이
  구성되어 있습니다. 그 외의 ClickHouse Cloud 서비스에는 이 구성이
  적용되어 있지 않으며, 해당 서비스에서는 사용자가 직접 이 엔진을
  활성화할 수 없습니다.
</Note>

## 구문

```sql theme={null}
CREATE TABLE name [(columns)] ENGINE=TimeSeries
[SETTINGS var1=value1, ...]
[SAMPLES db.samples_table_name | [SAMPLES INNER COLUMNS (...)] [SAMPLES INNER ENGINE engine(arguments)]]
[RECENT SAMPLES db.recent_samples_table_name | [RECENT SAMPLES INNER COLUMNS (...)] [RECENT SAMPLES INNER ENGINE engine(arguments)]]
[TAGS db.tags_table_name | [TAGS INNER COLUMNS (...)] [TAGS INNER ENGINE engine(arguments)]]
[METRIC FAMILIES db.metric_families_table_name | [METRIC FAMILIES INNER COLUMNS (...)] [METRIC FAMILIES INNER ENGINE engine(arguments)]]
```

<Note>
  `SAMPLES` 키워드에는 `DATA`라는 별칭이 있고, `METRIC FAMILIES` 키워드에는 `METRICS`라는 별칭이 있으며, 둘 다 이전 버전과의 호환성을 위해 유지됩니다.
  4 이전 [버전](#schema-versioning)의 테이블 정의는 `METRICS`로 작성되므로, 이전 버전의 서버에서도 이를 읽을 수 있습니다.
</Note>

## 사용법

기본 설정을 그대로 사용해 시작하는 편이 더 쉽습니다 (`TimeSeries` 테이블은 컬럼 목록을 지정하지 않고도 생성할 수 있습니다):

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
```

그러면 이 테이블을 다음 프로토콜과 함께 사용할 수 있습니다(포트는 서버 구성에서 할당해야 합니다):

* [prometheus remote-write](/ko/concepts/features/interfaces/prometheus#remote-write)
* [prometheus remote-read](/ko/concepts/features/interfaces/prometheus#remote-read)

### 외부 컬럼

TimeSeries 테이블의 컬럼은 자동으로 생성됩니다. 이러한 컬럼을 외부 컬럼이라고 하며, 데이터는 저장하지 않고 SELECT/INSERT를 위한 인터페이스만 제공합니다. 실제 데이터는 [대상 테이블](#target-tables)에 저장됩니다. 다음은 외부 컬럼 목록입니다:

| Name | Type | 설명 |
| - | - | - |
| `metric_name` | `String` | 메트릭 이름 |
| `tags` | `Map(String, String)` | 시계열의 tags(labels) 맵 |
| `samples` | `Array(Tuple(DateTime64(3), Float64))`가 기본값 | 시계열에 대한 (timestamp, value) 쌍의 배열입니다. 튜플의 timestamp 및 스칼라 요소 타입은 샘플 `INNER COLUMNS` 선언에서 유추할 수 있습니다([외부 컬럼 지정](#specifying-outer-columns) 참고). 이 컬럼은 [version](#schema-versioning) 2 이하의 테이블에서는 `time_series`라는 이름을 가집니다 |
| `metric_family` | `String` | 메트릭 패밀리 이름(메트릭 메타데이터용) |
| `type` | `String` | 메트릭 유형(예: "counter", "gauge") |
| `unit` | `String` | 메트릭 단위 |
| `help` | `String` | 메트릭 설명 |

예시:

```sql theme={null}
INSERT INTO my_table (metric_name, tags, samples) VALUES
    ('cpu_usage', {'job': 'node_exporter', 'instance': 'host1:9100'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5), (toDateTime64('2024-01-01 00:01:00', 3), 0.7)])
```

삽입 시 `metric_name`은 비워 둘 수 있으며, 이는 메트릭 이름이 `tags`의 `__name__`에 지정된다는 의미입니다. 예시는 다음과 같습니다:

```sql theme={null}
INSERT INTO my_table (tags, samples) VALUES
    ({'__name__': 'cpu_usage', 'job': 'test'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5)])
```

메트릭 메타데이터를 삽입하려면 `metric_family`, `type`, `unit`, `help` 컬럼에 값을 삽입합니다:

```sql theme={null}
INSERT INTO my_table (metric_name, tags, samples, metric_family, type, unit, help) VALUES
    ('http_requests_total', {'method': 'GET'}, [(now64(), 100.0)],
     'http_requests_total', 'counter', 'requests', 'Total HTTP requests')
```

### 외부 컬럼 지정

외부 `samples` 컬럼은 `CREATE TABLE` 문에서 명시적으로 나열해 기본 `Array(Tuple(DateTime64(3), Float64))` 유형을 재정의할 수 있습니다(이전 이름인 `time_series`도 허용됩니다). ClickHouse는 튜플에서 타임스탬프와 스칼라 유형을 추출해 내부 samples table에 반영합니다:

```sql theme={null}
CREATE TABLE my_table (samples Array(Tuple(UInt32, Float32))) ENGINE=TimeSeries
```

이는 samples `INNER COLUMNS` 절에서 timestamp 및 value 컬럼의 유형을 직접 선언하는 것과 동일합니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp UInt32 CODEC(Delta, T64, ZSTD(3)), value Float32 CODEC(ALP, ZSTD(3)))
```

두 형식을 모두 같은 `CREATE TABLE` 문에서 사용하는 경우, 선언된 유형이 일치해야 합니다.

## target table

`TimeSeries` 테이블은 자체 데이터를 갖지 않으며, 모든 데이터는 target table에 저장됩니다.
이는 [materialized view](/ko/reference/statements/create/view#materialized-view)의 동작 방식과 비슷하지만,
materialized view는 target table이 하나인 반면
`TimeSeries` 테이블에는 [samples](#samples-table), [tags](#tags-table), [메트릭 패밀리](#metric-families-table)라는 세 개의 필수 target table이 있고,
기본적으로 활성화되어 있는 선택적 [최근 샘플](#recent-samples-table) target table이 있습니다
([recent\_samples\_ttl\_seconds](#settings) 설정 참조).

target table은 `CREATE TABLE` 쿼리에서 명시적으로 지정할 수도 있고
`TimeSeries` 테이블 엔진이 내부 target table을 자동으로 생성할 수도 있습니다.

`TimeSeries` 테이블에 삽입된 행은 변환되고 블록으로 분할된 후, 이 target table들에 삽입됩니다.

target table은 다음과 같습니다:

### Samples table

*samples* 테이블에는 특정 식별자에 연결된 시계열이 포함됩니다.

*samples* 테이블에는 다음 컬럼이 있어야 합니다:

| 이름 | 필수? | 기본 타입 | 가능한 타입 | 설명 |
| - | - | - | - | - |
| `id` | \[x] | `Tuple(UInt64, LowCardinality(UUID))` | 모든 타입 | 메트릭 이름과 태그 조합을 식별합니다 |
| `timestamp` | \[x] | `DateTime64(3)` | `DateTime64(X)` | 시점 |
| `value` | \[x] | `Float64` | `Float32` 또는 `Float64` | `timestamp`에 연결된 값 |

엔진이 자체적으로 생성하는 컬럼에는 시계열 압축 코덱이 적용됩니다:
`timestamp CODEC(Delta, T64, ZSTD(3))` 및 `value CODEC(ALP, ZSTD(3))`입니다. 거의 단조로운 타임스탬프는 일반 코덱으로는 거의
압축되지 않으며, 그렇지 않으면 samples 테이블의 디스크상 크기에서 큰 비중을 차지할 수 있습니다.
엔진은 내부 samples 테이블과 최근 샘플 테이블에 대해 `enable_alp_codec` 설정 없이도 `ALP`를 활성화합니다.
[컬럼 타입 조정](#adjusting-column-types)도 참조하십시오.

### 최근 샘플 테이블

*최근 샘플* 테이블은 선택 사항이며 기본적으로 활성화되어 있습니다([recent\_samples\_ttl\_seconds](#settings) 설정 참조. 이 값을 0으로 설정하면 테이블이 비활성화됩니다). 이 테이블에는 해당 설정에서 정의한 TTL보다 최신인 샘플의 복사본이 포함되며, [samples](#samples-table) 테이블과 동일한 컬럼을 가져야 합니다.
생성된 `timestamp` 컬럼은 `CODEC(Delta, T64, ZSTD(3))`을 사용하고,
생성된 `value` 컬럼은 `CODEC(ALP, ZSTD(3))`을 사용합니다.

삽입되는 모든 샘플은 samples 테이블과 최근 샘플 테이블 모두에 기록됩니다.
시간 범위가 TTL 윈도우 내에 있는 쿼리는 최근 샘플 테이블이 훨씬 작으므로 기본 samples 테이블 대신 최근 샘플 테이블에서 읽습니다(쿼리 수준 설정 `time_series_prefer_recent_samples_table`으로 이 동작을 비활성화할 수 있습니다).

내부 최근 샘플 테이블의 TTL은 항상 [recent\_samples\_ttl\_seconds](#settings) 설정을 기반으로 결정됩니다.

### Tags 테이블

*tags* 테이블에는 메트릭 이름과 태그의 각 조합별로 계산된 식별자가 포함됩니다.

*tags* 테이블에는 다음 컬럼이 있어야 합니다:

| Name | Mandatory? | 기본 타입 | 가능한 타입 | 설명 |
| - | - | - | - | - |
| `id` | \[x] | `Tuple(UInt64, LowCardinality(UUID))` | any (must match the type of `id` in the [samples](#samples-table) table) | `id`는 메트릭 이름과 태그의 조합을 식별합니다. DEFAULT 표현식은 이러한 식별자를 계산하는 방법을 지정합니다 |
| `metric_name` | \[x] | `LowCardinality(String)` | `String` or `LowCardinality(String)` | 메트릭 이름 |
| `<tag_value_column>` | \[ ] | `String` | `String` or `LowCardinality(String)` or `LowCardinality(Nullable(String))` | 특정 태그의 값입니다. 태그 이름과 해당 컬럼 이름은 [tags\_to\_columns](#settings) 설정에서 지정합니다 |
| `tags` | \[x] | `Map(LowCardinality(String), String)` | `Map(String, String)` or `Map(LowCardinality(String), String)` or `Map(LowCardinality(String), LowCardinality(String))` | 메트릭 이름을 담는 태그 `__name__`와 [tags\_to\_columns](#settings) 설정에 나열된 이름의 태그를 포함한 모든 태그의 맵입니다. 이전 버전의 ClickHouse에서 생성된 테이블은 이 컬럼에 전용 컬럼이 없는 태그만 저장했으며 메트릭 이름은 저장하지 않았습니다. 읽기 시 두 경우를 모두 처리합니다 |
| `min_time` | \[ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` or `Nullable(DateTime64(X))` | 해당 `id`를 가진 시계열의 최소 타임스탬프입니다. [store\_min\_time\_and\_max\_time](#settings)가 `true`이면 이 컬럼이 생성됩니다 |
| `max_time` | \[ ] | `Nullable(DateTime64(3))` | `DateTime64(X)` or `Nullable(DateTime64(X))` | 해당 `id`를 가진 시계열의 최대 타임스탬프입니다. [store\_min\_time\_and\_max\_time](#settings)가 `true`이면 이 컬럼이 생성됩니다 |

[version](#schema-versioning) 5 이상에서 `MergeTree` 엔진 계열을 사용하는 새 내부 tags 테이블에는 `tags`에 대한 역텍스트 인덱스가 있습니다:
`INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs')`. 키와 값을 함께 조회하여 PromQL의
`{job="api"}`와 같은 정확한 레이블 일치를 가속합니다. 빈 문자열과의 비교도
누락된 레이블과 일치하며 이 인덱스를 사용하지 않습니다.

`TAGS INNER COLUMNS`에 명시적으로 선언된 인덱스는 기본 인덱스를 대체합니다. 기존 테이블과 외부
tags 테이블은 기존 인덱스를 유지합니다. 이 기능을 활성화하려면 해당 tags target table에 인덱스를 추가하고 구체화하십시오.

### 메트릭 패밀리 테이블

*metric families* 테이블에는 수집 중인 메트릭 패밀리, 해당 메트릭 패밀리의 타입, 그리고 설명에 대한 정보가 포함됩니다.
메트릭 패밀리는 동일한 이름(`__name__` 태그)과 동일한 타입을 가진 메트릭 그룹입니다. 예를 들어 histogram은 여러 메트릭으로 구성된 메트릭 패밀리입니다.

*metric families* 테이블에는 다음 컬럼이 있어야 합니다:

| Name | Mandatory? | Default type | Possible types | Description |
| - | - | - | - | - |
| `metric_family_name` | \[x] | `String` | `String` or `LowCardinality(String)` | 메트릭 패밀리의 이름 |
| `type` | \[x] | `LowCardinality(String)` | `String` or `LowCardinality(String)` | 메트릭 패밀리의 타입으로, "counter", "gauge", "summary", "stateset", "histogram", "gaugehistogram" 중 하나입니다 |
| `unit` | \[x] | `LowCardinality(String)` | `String` or `LowCardinality(String)` | 메트릭에 사용되는 단위 |
| `help` | \[x] | `String` | `String` or `LowCardinality(String)` | 메트릭 설명 |

## 생성

`TimeSeries` 테이블 엔진을 사용하여 테이블을 생성하는 방법은 여러 가지가 있습니다.
가장 간단한 SQL 문은

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
```

실제로 다음 테이블이 생성됩니다(`SHOW CREATE TABLE my_table`을 실행하여 확인할 수 있습니다):

```sql theme={null}
CREATE TABLE my_table
(
    `metric_name` String,
    `tags` Map(String, String),
    `samples` Array(Tuple(DateTime64(3), Float64)),
    `metric_family` String,
    `type` String,
    `unit` String,
    `help` String
)
ENGINE = TimeSeries
SETTINGS version = 5, recent_samples_ttl_seconds = 345600
SAMPLES INNER COLUMNS
(
    `id` Tuple(UInt64, LowCardinality(UUID)),
    `timestamp` DateTime64(3) CODEC(Delta, T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
SAMPLES INNER ENGINE = MergeTree ORDER BY (id, timestamp) SETTINGS index_granularity = 32768
RECENT SAMPLES INNER COLUMNS
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(Delta, T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
RECENT SAMPLES INNER ENGINE = MergeTree PARTITION BY toStartOfInterval(toDateTime(timestamp), toIntervalHour(5)) ORDER BY (id, timestamp) TTL toDateTime(timestamp) + toIntervalSecond(345600) SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1
TAGS INNER COLUMNS
(
    `id` Tuple(UInt64, LowCardinality(UUID)) DEFAULT tuple(sipHash64(metric_name), toLowCardinality(reinterpretAsUUID(sipHash128(tags)))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3))),
    INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs') GRANULARITY 100000000
)
TAGS INNER ENGINE = AggregatingMergeTree PRIMARY KEY metric_name ORDER BY (metric_name, id) SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
METRIC FAMILIES INNER COLUMNS
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
METRIC FAMILIES INNER ENGINE = ReplacingMergeTree ORDER BY metric_family_name
```

따라서 컬럼은 자동으로 생성되며, `INNER COLUMNS` 절에 자체 컬럼 정의가 저장된 4개의 내부 대상 테이블도 생성됩니다. `recent_samples_ttl_seconds` 설정은 기본값과 함께 `SETTINGS` 절에 기록됩니다. 이 설정은 최근 샘플 테이블의 TTL을 정의하므로, 실제 값은 생성 시점에 고정됩니다.
또한 최신 스키마 버전이 `version` 설정에 고정됩니다([스키마 버전 관리](#schema-versioning) 참조).

내부 대상 테이블의 이름은 `.inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
`.inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, `.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,
`.inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
이며 각 대상 테이블에는 고유한 열 집합이 있습니다:

```sql theme={null}
CREATE TABLE default.`.inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, LowCardinality(UUID)),
    `timestamp` DateTime64(3) CODEC(Delta(8), T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
ENGINE = MergeTree
ORDER BY (id, timestamp)
SETTINGS index_granularity = 32768
```

```sql theme={null}
CREATE TABLE default.`.inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(Delta(8), T64, ZSTD(3)),
    `value` Float64 CODEC(ALP, ZSTD(3))
)
ENGINE = MergeTree
PARTITION BY toStartOfInterval(toDateTime(timestamp), toIntervalHour(5))
ORDER BY (id, timestamp)
TTL toDateTime(timestamp) + toIntervalSecond(345600)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1
```

```sql theme={null}
CREATE TABLE default.`.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, LowCardinality(UUID)) DEFAULT tuple(sipHash64(metric_name), toLowCardinality(reinterpretAsUUID(sipHash128(tags)))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3))),
    INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs') GRANULARITY 100000000
)
ENGINE = AggregatingMergeTree
PRIMARY KEY metric_name
ORDER BY (metric_name, id)
SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
```

```sql theme={null}
CREATE TABLE default.`.inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
ENGINE = ReplacingMergeTree
ORDER BY metric_family_name
SETTINGS index_granularity = 8192
```

## 기존 테이블을 AS로 사용해 테이블 생성

문 `CREATE TABLE new_table AS existing_table`은 `existing_table`과 동일하게 구성된 `TimeSeries` 테이블을 생성합니다.
`existing_table`은 `TimeSeries` 테이블이어야 합니다. `existing_table`의 외부 대상은 복사되지 않으므로 문에서
해당 대상을 직접 선언해야 합니다.

이 문은 `existing_table`에서 다음 항목을 복사합니다.

* `version`을 제외한 `SETTINGS` 절: 새 테이블에는 항상 최신 버전이 적용됩니다. 문에 직접 작성한 설정은 이름을 기준으로 복사된 설정과
  병합되므로, 직접 작성한 설정이 복사된 설정에 우선하며 `name = DEFAULT`는 복사된 설정을 기본값으로 재설정합니다.
* 각 내부 테이블의 `INNER COLUMNS` 및 `INNER ENGINE` 절. 사용자 정의 컬럼(예: 추가 컬럼, 코덱 또는 DEFAULT 표현식이 있는 컬럼)과
  사용자 정의 엔진 부분(예: 인수가 있는 엔진, 사용자 정의 정렬 키 또는 엔진 설정)은 유지됩니다. 나머지 컬럼과 엔진 부분은 새 테이블의 설정에 맞게 조정되므로,
  예를 들어 문에 작성한 `tags_to_columns`, `aggregate_min_time_and_max_time` 또는 `tags_index_granularity`가 적용됩니다.

`id`, 타임스탬프 및 값 컬럼의 타입과 내부 엔진의 복제 유형(`MergeTree`,
`ReplicatedMergeTree` 또는 `SharedMergeTree`)도 문에서 직접 선언하지 않는 한 `existing_table`에서 가져옵니다.
외부 컬럼 목록은 다시 생성되며 복사되지 않습니다.

이전 버전의 ClickHouse에서 생성한 테이블도 `existing_table`로 사용할 수 있습니다. 새 테이블에는 현재
구조(예: 현재 `id` 타입 및 기본 식별자 표현식)가 적용됩니다.

## 컬럼 유형 조정

`INNER COLUMNS` 절을 사용하면 내부 대상 테이블의 컬럼 유형을 조정할 수 있습니다. 예를 들어, 타임스탬프를 마이크로초 단위로 저장하고 값을 `Float32`로 저장하려면 다음을 사용합니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6) CODEC(Delta, T64, ZSTD(3)), value Float32 CODEC(ALP, ZSTD(3)))
```

내부 컬럼을 코덱 없이 지정하면 기본 코덱이 사용됩니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6), value Float32)
```

## `id` 컬럼

`id` 컬럼에는 식별자가 들어 있으며, 각 식별자는 메트릭 이름과 태그의 조합을 기준으로 계산됩니다.
식별자를 생성하는 데 사용되는 유형과 `DEFAULT` 표현식은 `TAGS INNER COLUMNS` 절을 통해 사용자 지정할 수 있습니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
TAGS INNER COLUMNS (id UInt64 DEFAULT sipHash64(tags))
```

`id` 컬럼은 비교 가능한 널 허용이 아닌 모든 타입일 수 있습니다. samples 및 tags 내부 테이블에 선언된 `id` 타입은 서로 일치해야 합니다.

`id` 컬럼에 `DEFAULT` 표현식이 지정되지 않고 `id_generator` 설정도 지정되지 않은 경우, `id` 타입이 `UUID`, `UInt64`, `UInt128`, `FixedString(16)`, `LowCardinality`로 래핑된 동일한 타입 또는 이들 타입 두 개로 이루어진 튜플인 경우에만 ClickHouse가 `id` 타입에 따라 `DEFAULT` 표현식을 자동으로 선택합니다. 이러한 튜플에서는 자동으로 선택된 표현식이 첫 번째 구성 요소에서 메트릭 이름의 해시를 계산하고, 두 번째 구성 요소에서 모든 태그의 해시를 계산합니다.

`Tuple(UInt64, LowCardinality(UUID))`와 같은 `LowCardinality` 식별자 타입은 식별자가 딕셔너리 인코딩된 상태로 유지합니다. samples 테이블은 모든 행에 전체 식별자를 반복해 저장하는 대신 블록별로 작은 딕셔너리와 딕셔너리 인덱스를 저장하므로 쿼리가 읽는 데이터 양이 줄어듭니다.

`id_generator` 설정을 사용하면 `INNER COLUMNS` 절을 사용하지 않고도 동일하게 사용자 지정할 수 있습니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SETTINGS id_generator = 'sipHash64(tags)'
```

이 설정이 지정되면, 컬럼의 `DEFAULT`에 다른 표현식이 있더라도 `id`를 생성하는 데 이 설정이 사용됩니다.

`id` 컬럼의 타입은 `INNER COLUMNS` 절 대신 `id_type` 설정으로 지정할 수도 있습니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SETTINGS id_type = 'UInt64', id_generator = 'sipHash64(tags)'
```

`id_generator` 설정이 지정되면 `CREATE` 시점에 `id_type` 설정이 자동으로 기록되므로,
정의에는 해당 표현식이 작성된 대상 타입이 그대로 유지됩니다.

## `tags` 컬럼

`tags` 컬럼에는 메트릭 이름이 포함된 `__name__` 태그를 비롯하여 시계열의 모든 태그가 포함됩니다.

`tags_to_columns` 설정을 사용하면 특정 태그를 `tags` 컬럼 내부의 맵에 저장하는 것 외에도 별도의 컬럼에 저장하도록
지정할 수 있습니다:

```sql theme={null}
CREATE TABLE my_table
ENGINE = TimeSeries
SETTINGS tags_to_columns = {'instance': 'instance', 'job': 'job'}
```

이 SQL 문은 내부 [tags](#tags-table) 대상 테이블에 `instance` 및 `job` 컬럼을 추가합니다.
`instance` 및 `job` 태그의 값은 해당 컬럼과 `tags` 컬럼 모두에 저장됩니다.

<Note>
  이전 버전의 ClickHouse에서 생성된 테이블의 `tags` 컬럼에는 전용 컬럼에 저장되지 않는 태그만 포함되며 메트릭 이름은 포함되지 않습니다. `all_tags` 컬럼은 삽입 시
  메트릭 이름을 제외한 모든 태그로 채워지는 일시적 컬럼입니다.
</Note>

## 내부 대상 테이블의 테이블 엔진

기본적으로 내부 대상 테이블에는 다음 테이블 엔진이 사용됩니다.

* [samples](#samples-table) 테이블은 [MergeTree](/ko/reference/engines/table-engines/mergetree-family/mergetree)를 사용합니다;
* [최근 샘플](#recent-samples-table) 테이블은 5시간 버킷으로 파티션된 [MergeTree](/ko/reference/engines/table-engines/mergetree-family/mergetree)를 사용하며([recent\_samples\_partition\_by](#settings) 설정 참조), [recent\_samples\_ttl\_seconds](#settings) 설정에서 파생된 `TTL`과 활성화된 `ttl_only_drop_parts`를 사용하므로 만료된 파트 전체가 삭제됩니다;
* [tags](#tags-table) 테이블은 [AggregatingMergeTree](/ko/reference/engines/table-engines/mergetree-family/aggregatingmergetree)를 사용합니다. 이 테이블에는 동일한 데이터가 여러 번 삽입되는 경우가 많으므로
  중복을 제거할 방법이 필요하고, `min_time` 및 `max_time` 컬럼에 대해 집계를 수행해야 하기 때문입니다;
* [메트릭 패밀리](#metric-families-table) 테이블은 [ReplacingMergeTree](/ko/reference/engines/table-engines/mergetree-family/replacingmergetree)를 사용합니다. 이 테이블에도 동일한 데이터가 여러 번 삽입되는 경우가 많으므로
  중복을 제거할 방법이 필요하기 때문입니다.

생성된 내부 테이블의 엔진 계열은 `default_table_engine` 쿼리 수준 설정을 따릅니다.
`default_table_engine = ReplicatedMergeTree` 또는 `SharedMergeTree`를 사용하면 내부 테이블은 해당
`Replicated` 또는 `Shared` 엔진을 사용합니다. `default_table_engine = None`(또는 다른 값)을 사용하면 내부 테이블의 엔진을
명시적으로 지정해야 합니다.

모든 내부 테이블은 동일한 복제 유형을 사용해야 합니다. 하나가 복제되었거나 공유된 경우, 다른 내부
테이블도 복제되거나 공유되어야 합니다. 그렇지 않으면 레플리카 간에 내용이 달라집니다. 예를 들어,
`SAMPLES INNER ENGINE = ReplicatedMergeTree(...)`를 선언하려면 다른 내부 엔진도 복제되어야 합니다.
명시적으로 선언하거나 `default_table_engine = ReplicatedMergeTree`로 생성해야 합니다.

다음과 같이 지정하면 내부 대상 테이블에 다른 테이블 엔진을 사용할 수도 있습니다:

```sql theme={null}
CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES ENGINE=ReplicatedMergeTree
RECENT SAMPLES ENGINE=ReplicatedMergeTree
TAGS ENGINE=ReplicatedAggregatingMergeTree
METRIC FAMILIES ENGINE=ReplicatedReplacingMergeTree
```

[tags](#tags-table) 테이블은 태그 컬럼(및 `tags` 맵)을 정렬 키(sorting key) 밖에 유지하는데,
이는 `AggregatingMergeTree`에서 기본적으로 허용하지 않습니다([`allow_dimensions_outside_sorting_key`](/ko/reference/engines/table-engines/mergetree-family/aggregatingmergetree) 참조).
여기서 이것이 안전한 이유는 해당 컬럼들이 정렬 키의 일부인 `id`에 함수적으로 종속되어 있으므로, 백그라운드 머지로 함께 축약되는 모든
행이 동일한 값을 공유하기 때문입니다. 위와 같이 내부 tags 테이블이 생성되거나 해당 엔진이 인라인으로 지정되면 `TimeSeries`는 여기에
`allow_dimensions_outside_sorting_key = 1`을 자동으로 설정합니다. 수동으로 생성한 [외부](#external-target-tables) 집계 tags 테이블은 직접 설정해야 합니다.

## 외부 대상 테이블

수동으로 생성한 테이블을 `TimeSeries` 테이블에서 사용하게 할 수 있습니다:

```sql theme={null}
CREATE TABLE samples_for_my_table
(
    `id` UUID,
    `timestamp` DateTime64(3),
    `value` Float64
)
ENGINE = MergeTree
ORDER BY (id, timestamp);

CREATE TABLE tags_for_my_table ...

CREATE TABLE metric_families_for_my_table ...

CREATE TABLE my_table ENGINE=TimeSeries SAMPLES samples_for_my_table TAGS tags_for_my_table METRIC FAMILIES metric_families_for_my_table;
```

외부 테이블은 [최근 샘플](#recent-samples-table) 대상(`RECENT SAMPLES my_recent_samples_table` 절)으로도 사용할 수 있습니다.
이러한 테이블은 외부 Samples 테이블과 동일한 컬럼을 가져야 하며, 최소
[recent\_samples\_ttl\_seconds](#settings)초 동안 데이터를 보존해야 합니다. 이는 사용자의 책임입니다.

외부 테이블의 컬럼 타입(`id`, `timestamp`, `value`, 그리고 [`tags_to_columns`](#settings)에 나열된 `<tag_value_column>`들)은 `TimeSeries` 테이블이 내부적으로 생성하는 타입과 일치해야 합니다(타입 제약 조건은 [Samples table](#samples-table), [Tags 테이블](#tags-table), [메트릭 패밀리 테이블](#metric-families-table)을 참조하십시오). 타입 불일치는 `CREATE` 시점에 보고됩니다.

외부 Tags 테이블의 `id` 컬럼 타입과 식별자를 생성하는 표현식은 `CREATE` 시점에 [`id_type`](#settings) 및 [`id_generator`](#settings) 설정에 기록됩니다([version](#schema-versioning) 2부터). 따라서 `TimeSeries` 테이블의 정의가 이를 유지합니다. 예를 들어 `CREATE TABLE ... AS my_table`은 외부 대상 테이블을 읽지 않고 `my_table`의 정의에서 `id` 타입을 읽습니다. `id_generator` 설정이 지정되지 않은 경우, 외부 테이블의 `id` 컬럼에 선언된 `DEFAULT`(있는 경우)로 설정되며, 없으면 `id` 타입에서 파생된 정규 생성기로 설정됩니다. 기록된 표현식은 이후 외부 테이블의 `DEFAULT`가 변경되더라도 `id` 생성에 사용됩니다 — 자세한 내용은 [The `id` column](#id-column)을 참조하십시오.

## 설정 변경

`CREATE` 이후에는 다음 2개의 설정을 변경할 수 있습니다:

* `id_generator`
* `filter_by_min_time_and_max_time`

```sql theme={null}
ALTER TABLE my_table MODIFY SETTING id_generator = 'sipHash64(tags)';
ALTER TABLE my_table MODIFY SETTING filter_by_min_time_and_max_time = 0;
ALTER TABLE my_table RESET SETTING filter_by_min_time_and_max_time;
```

`id_generator`는 데이터가 이미 Tags 테이블에 있는 상태에서 변경하면 동일한 메트릭+태그 조합에 대해 서로 다른 ID가 생성될 수 있습니다. 기존 행은 이전 ID를 유지하고, 새 행은 새 생성기를 사용합니다.

다른 설정은 `ALTER ... MODIFY SETTING`으로 변경할 수 없습니다. 대부분은 `CREATE` 시점에 내부 테이블의 스키마에 반영되며, `version` 설정은 `CREATE` 시점에 자동으로 고정되어 스키마 자체를 식별합니다([스키마 버전 관리](#schema-versioning) 참조).

## 설정

다음은 `TimeSeries` 테이블을 정의할 때 지정할 수 있는 설정 목록입니다.

| 이름 | 유형 | 기본값 | 설명 |
| - | - | - | - |
| `id_type` | 데이터 타입 | `id` 컬럼에 따라 다름 | 대상 테이블의 `id` 컬럼 유형입니다. 일반적으로 이 유형은 내부 테이블의 `INNER COLUMNS` 절이나 [외부](#external-target-tables) tags 테이블에서 선언됩니다. 그 외의 방식으로 정의에 유형이 유지되지 않는 경우, 즉 tags 대상이 외부 테이블이거나 `id_generator` 설정이 지정된 경우에는 `CREATE` 시점에 이 설정이 자동으로 기록됩니다. 이 설정은 `TAGS INNER COLUMNS (id <type>)` 대신 명시적으로 지정할 수도 있습니다. `version`이 2 이상이어야 합니다 |
| `id_generator` | 표현식 | `id` 유형에 따라 다름 | 태그로부터 시계열의 식별자(지문)를 계산하는 표현식입니다. 설정하지 않으면 `id` 컬럼의 기본 표현식이 사용됩니다. `id` 컬럼의 기본 표현식도 설정되지 않은 경우 표현식이 자동으로 선택됩니다. 외부 tags 테이블에서는 `version`이 2 이상이면 이 설정이 `CREATE` 시 자동으로 기록됩니다([외부 대상 테이블](#external-target-tables) 참조) |
| `tags_to_columns` | 맵 | {} | [tags](#tags-table) 테이블에서 어떤 태그를 별도의 컬럼으로 저장할지 지정하는 맵입니다. 구문: `{'tag1': 'column1', 'tag2' : column2, ...}` |
| `use_all_tags_column_to_generate_id` | Bool | false | 더 이상 사용되지 않는 설정이며 아무 작업도 수행하지 않습니다 |
| `store_min_time_and_max_time` | Bool | true | true로 설정하면 테이블은 각 시계열에 대해 `min_time` 및 `max_time`을 저장합니다 |
| `aggregate_min_time_and_max_time` | Bool | true | 내부 대상 `tags` 테이블을 생성할 때, 이 플래그를 사용하면 `min_time` 컬럼의 유형으로 단순한 `Nullable(DateTime64(3))` 대신 `SimpleAggregateFunction(min, Nullable(DateTime64(3)))`를 사용합니다. `max_time` 컬럼도 동일합니다 |
| `filter_by_min_time_and_max_time` | Bool | true | true로 설정하면 테이블은 시계열을 필터링할 때 `min_time` 및 `max_time` 컬럼을 사용합니다 |
| `samples_index_granularity` | UInt64 | 32768 | 내부 [samples](#samples-table) 테이블의 `index_granularity`를 설정합니다. 명시적으로 설정하면 엔진 선언의 `index_granularity`를 재정의합니다. 외부 samples 테이블 및 MergeTree가 아닌 엔진에서는 무시됩니다 |
| `recent_samples_ttl_seconds` | UInt64 | 345600 | 추가 `최근 샘플` 대상 테이블의 보존 기간입니다. 삽입되는 모든 샘플은 이 테이블에도 기록됩니다. 내부 최근 샘플 테이블에는 항상 이 설정에서 파생된 `TTL toDateTime(timestamp) + toIntervalSecond(recent_samples_ttl_seconds)`이 적용됩니다(엔진 선언의 TTL을 재정의함). 외부 최근 샘플 테이블은 최소한 이 설정값만큼의 초 동안 데이터를 보존해야 합니다. 시간 범위가 TTL 윈도우에 포함되는 쿼리는 기본 samples 테이블보다 최근 샘플 테이블을 우선합니다(쿼리 수준 설정 `time_series_prefer_recent_samples_table` 참조). 기본값은 4일이며, 유효 값은 CREATE 시 테이블 정의에 고정됩니다. 최근 샘플 테이블을 비활성화하려면 0으로 설정하십시오 |
| `recent_samples_partition_by` | 표현식 | `toStartOfInterval(toDateTime(timestamp), toIntervalHour(5))` | 내부 `recent samples` 테이블의 파티션 키입니다. 예: `toStartOfHour(timestamp)`. 명시적으로 설정하면 엔진 선언의 파티션 키를 재정의하며, 둘 다 설정되지 않은 경우 5시간마다 하나의 파티션이 사용됩니다. 외부 최근 샘플 테이블에서는 무시됩니다. `recent_samples_ttl_seconds`가 0이 아니어야 합니다 |
| `recent_samples_index_granularity` | UInt64 | 8192 | 내부 `recent samples` 테이블의 `index_granularity`를 설정합니다. 명시적으로 설정하면 엔진 선언의 `index_granularity`를 재정의합니다. 외부 최근 샘플 테이블 및 MergeTree가 아닌 엔진에서는 무시됩니다. `recent_samples_ttl_seconds`가 0이 아니어야 합니다 |
| `tags_index_granularity` | UInt64 | 8192 | 내부 [tags](#tags-table) 테이블의 `index_granularity`를 설정합니다. 명시적으로 설정하면 엔진 선언의 `index_granularity`를 재정의합니다. 외부 tags 테이블 및 MergeTree가 아닌 엔진에서는 무시됩니다 |
| `version` | UInt64 | 5 | 테이블의 버전입니다. 대상 테이블의 집합과 그 구조를 식별합니다. 버전은 테이블이 생성될 때 자동으로 고정되며 이후에는 변경할 수 없습니다. 일반적으로 `CREATE TABLE` 쿼리에서는 생략해야 합니다([스키마 버전 관리](#schema-versioning) 참조) |

## 스키마 버전 관리

`TimeSeries` 테이블 엔진과 PromQL 실행 계층은 활발히 개발이 진행 중입니다.
대상 테이블의 집합과 그 구조는 ClickHouse 버전에 따라 달라질 수 있습니다.
이러한 변경을 감지할 수 있도록, 모든 `TimeSeries` 테이블은 자신의 버전을 [version](#settings) 설정에 저장합니다.
버전은 테이블이 생성될 때 `CREATE` 쿼리에 자동으로 고정되며(그 값은 서버가 알고 있는 최신 버전, 현재는 5입니다),
테이블 메타데이터에 유지되고 `ALTER`로 변경할 수 없습니다. 이 설정이 도입되기 전에 생성된 테이블은 버전 0으로 간주됩니다.
일반적으로 이 설정은 `CREATE TABLE` 쿼리에서 생략하면 되며, 그러면 테이블은 최신 버전을 갖게 됩니다.
서버가 해당 버전을 지원한다면 `version`을 명시적으로 지정할 수도 있습니다. 이 경우 테이블은 해당 버전의 방식대로 정의됩니다([버전 이력](#version-history) 참고).
`CREATE TABLE ... AS other_table`은 다른 테이블의 버전을 복사하지 않습니다. [기존 테이블을 AS로 사용하여 테이블 생성](#create-as)을 참고하십시오.

서버는 일정 범위의 버전을 지원하며, 최소 버전은 `SELECT`로 읽는 경우, `INSERT` 또는 Prometheus remote-write 프로토콜로 쓰는 경우,
PromQL을 평가하는 경우([prometheusQuery](/ko/reference/functions/table-functions/prometheusQuery),
[prometheusQueryRange](/ko/reference/functions/table-functions/prometheusQueryRange),
[timeSeriesSelector](/ko/reference/functions/table-functions/timeSeriesSelector) 테이블 함수,
`promql` 방언, Prometheus HTTP 쿼리 API)에 따라 각각 다를 수 있습니다:

* `TimeSeries` 테이블의 버전이 PromQL을 사용하기에 너무 오래된 경우, 해당 테이블에 대한 PromQL 쿼리는 거부됩니다. 이때 발생하는 예외는 테이블을 다시 생성하도록 안내합니다.
  즉, 새 `TimeSeries` 테이블을 생성하고 `INSERT ... SELECT` 쿼리로 데이터를 복사한 뒤, 기존 테이블을 새 테이블으로 대체하십시오.
* 버전이 쓰기를 지원하기에 너무 오래된 경우, `INSERT` 쿼리와 Prometheus remote-write 프로토콜은 거부되지만 `SELECT` 쿼리는 계속 동작합니다.
* 버전이 서버에서 아예 지원되지 않을 정도로 오래된 경우, 해당 테이블에 대한 모든 쿼리(`SHOW CREATE TABLE`, `DETACH`, `DROP` 제외)가 거부됩니다.

### 버전 이력

| 버전 | 변경 사항 |
| - | - |
| 0 | `version` 설정이 도입되기 전에 생성된 테이블로, "prealpha" 테이블(대상 테이블의 컬럼을 [외부 컬럼(outer columns)](#outer-columns)으로 선언한 테이블)과 [최근 샘플](#recent-samples-table) 테이블이 없는 테이블을 포함합니다 |
| 1 | `version` 설정이 도입되었습니다 |
| 2 | [`id_type`](#settings) 설정이 도입되었습니다. 외부 Tags 테이블을 사용하는 테이블은 `id` 컬럼의 유형을 `id_type`에, 식별자를 생성하는 표현식을 [`id_generator`](#settings)에 기록하므로, 테이블 정의가 외부 테이블에 의존하지 않습니다. `id_generator`가 설정된 경우에도 `id_type`이 기록됩니다([`id` 컬럼](#id-column) 참조) |
| 3 | 외부 컬럼 `time_series`의 이름이 `samples`로 변경되었습니다([외부 컬럼](#outer-columns) 참조). 이전 버전의 테이블은 기존 컬럼 이름을 유지하며, [prometheusQuery](/ko/reference/functions/table-functions/prometheusQuery) 및 [prometheusQueryRange](/ko/reference/functions/table-functions/prometheusQueryRange) 테이블 함수는 해당 테이블이 사용하는 이름으로 컬럼을 반환합니다. 저장된 데이터는 변경되지 않았습니다 |
| 4 | `metrics` target table의 이름이 `메트릭 패밀리`로 변경되었습니다. 내부 테이블 이름이 `.inner_id.metrics.<uuid>` 대신 `.inner_id.metricfamilies.<uuid>`가 되고, 정의는 `METRICS` 대신 `METRIC FAMILIES` keyword로 작성됩니다. 저장된 데이터는 변경되지 않았습니다 |
| 5 | `MergeTree` 엔진 계열을 사용하는 새 내부 Tags 테이블에는 기본적으로 `tags` 맵에 `keyValuePairs` 텍스트 인덱스가 생성됩니다([Tags 테이블](#tags-table) 참조) |

# 함수

다음은 `TimeSeries` 테이블을 인수로 지원하는 함수 목록입니다.

* [timeSeriesSamples](/ko/reference/functions/table-functions/timeSeriesSamples)
* [timeSeriesTags](/ko/reference/functions/table-functions/timeSeriesTags)
* [timeSeriesMetricFamilies](/ko/reference/functions/table-functions/timeSeriesMetricFamilies)
