일반 뷰
매개변수화된 뷰(Parameterized View)
Materialized View
OR REPLACE와 IF NOT EXISTS는 서로 배타적이므로 함께 사용할 수 없습니다. 둘을 함께 사용하면 구문 오류가 발생합니다.
CREATE OR REPLACE MATERIALIZED VIEW
CREATE OR REPLACE MATERIALIZED VIEW는 기존 materialized view와 해당 내부 저장 테이블(있는 경우)을 원자적으로 대체합니다. 이 작업을 수행하려면 Atomic 또는 Replicated 데이터베이스 엔진이 필요합니다.
TO절 없이: 기존 내부 테이블이 삭제되고 새 테이블이 생성됩니다.POPULATE를 지정하지 않으면 내부 테이블의 기존 데이터는 손실됩니다.TO절 사용 시: 뷰 정의만 대체되며 대상 테이블과 그 데이터에는 영향이 없습니다.REFRESH,ON CLUSTER, 그리고 모든 엔진 옵션과 호환됩니다.POPULATE는Atomic데이터베이스에서만 지원되며,Replicated데이터베이스에서는 허용되지 않습니다(아래POPULATE참고 사항 참조).CREATE VIEW및DROP VIEW권한이 필요합니다.
CREATE OR REPLACE MATERIALIZED VIEW는 Atomic 또는 Replicated 데이터베이스 엔진에서만 지원됩니다. Ordinary 데이터베이스 엔진에서는 지원되지 않습니다.TO [db].[table] 없이 materialized view를 생성할 때는 데이터를 저장할 테이블 엔진인 ENGINE을 지정해야 합니다.
TO [db].[table]과 함께 materialized view를 생성할 때는 POPULATE를 함께 사용할 수 없습니다.
materialized view는 다음과 같이 동작합니다. SELECT에 지정된 테이블에 데이터를 삽입하면, 삽입된 데이터의 일부가 이 SELECT 쿼리로 변환되고 그 결과가 뷰에 삽입됩니다.
ClickHouse의 materialized view는 대상 테이블에 삽입할 때 컬럼 순서가 아니라 column names를 사용합니다.
SELECT 쿼리 결과에 일부 컬럼 이름이 없으면, 해당 컬럼이 널 허용이 아니더라도 ClickHouse는 기본값을 사용합니다. materialized view를 사용할 때는 모든 컬럼에 alias를 추가하는 것이 안전합니다.ClickHouse의 materialized view는 삽입 트리거에 더 가깝게 구현되어 있습니다. 뷰 쿼리에 집계가 포함된 경우, 이는 새로 삽입된 데이터의 batch에만 적용됩니다. source 테이블의 기존 데이터가 변경되어도(update, delete, drop partition 등) materialized view에는 반영되지 않습니다.ClickHouse의 materialized view는 오류 발생 시 deterministic한 동작을 보장하지 않습니다. 즉, 이미 기록된 block은 대상 테이블에 유지되지만, 오류 발생 이후의 모든 block은 기록되지 않습니다.기본적으로 여러 뷰 중 하나로 push하는 데 실패하면 INSERT 쿼리도 함께 실패하며, 일부 block은 대상 테이블에 기록되지 않을 수 있습니다. 이 동작은 materialized_views_ignore_errors 설정으로 변경할 수 있습니다(INSERT 쿼리에 설정해야 합니다). materialized_views_ignore_errors=true로 설정하면 뷰로 push하는 동안 발생하는 모든 오류가 무시되고, 모든 block이 대상 테이블에 기록됩니다.또한 system.*_log 테이블에서는 기본적으로 materialized_views_ignore_errors가 true로 설정되어 있다는 점도 유의하십시오.POPULATE를 지정하면, 기존 테이블 데이터가 CREATE TABLE ... AS SELECT ...를 수행한 것처럼 생성 시 뷰에 삽입됩니다. 그렇지 않으면 쿼리에는 뷰를 생성한 후 테이블에 삽입된 데이터만 포함됩니다. 뷰를 생성하는 동안 테이블에 삽입된 데이터는 뷰에 삽입되지 않으므로, POPULATE 사용은 권장하지 않습니다.
POPULATE는 CREATE TABLE ... AS SELECT ...처럼 동작하므로 다음과 같은 제한이 있습니다.- 복제된 데이터베이스에서는 지원되지 않습니다
- ClickHouse Cloud에서는 지원되지 않습니다
INSERT ... SELECT를 사용할 수 있습니다.SELECT 쿼리에는 DISTINCT, GROUP BY, ORDER BY, LIMIT를 포함할 수 있습니다. 해당 변환은 삽입된 데이터의 각 블록에서 서로 독립적으로 수행된다는 점에 유의하십시오. 예를 들어 GROUP BY가 설정된 경우 데이터는 삽입 중에 집계되지만, 이는 삽입된 데이터의 단일 패킷 내에서만 수행됩니다. 이후에는 데이터가 추가로 집계되지 않습니다. 예외적으로 SummingMergeTree처럼 자체적으로 데이터 집계를 수행하는 ENGINE을 사용할 때는 다릅니다.
materialized view가 TO [db.]name 구문을 사용하는 경우, 뷰를 DETACH하고 대상 테이블에 ALTER를 실행한 다음, 앞서 분리한(DETACH) 뷰를 ATTACH할 수 있습니다.
materialized view는 optimize_on_insert 설정의 영향을 받는다는 점에 유의하십시오. 데이터는 뷰에 삽입되기 전에 머지됩니다.
뷰는 일반 테이블과 동일하게 표시됩니다. 예를 들어 SHOW TABLES 쿼리 결과에 나열됩니다.
뷰를 삭제하려면 DROP VIEW를 사용하십시오. DROP TABLE도 VIEW에 사용할 수 있습니다.
SQL 보안
DEFINER 및 SQL SECURITY를 사용하면 뷰의 기반 쿼리를 실행할 때 어떤 ClickHouse 사용자를 사용할지 지정할 수 있습니다.
SQL SECURITY에는 DEFINER, INVOKER, NONE의 세 가지 유효한 값이 있습니다. DEFINER 절에는 기존 사용자 또는 CURRENT_USER를 지정할 수 있습니다.
다음 표는 뷰에서 SELECT할 때 어떤 사용자에게 어떤 권한이 필요한지 설명합니다.
SQL 보안 옵션과 관계없이, 어떤 경우에도 뷰를 읽으려면 여전히 GRANT SELECT ON <view> 권한이 필요합니다.
| SQL security option | View | Materialized View |
|---|---|---|
DEFINER alice | alice는 뷰의 소스 테이블에 대한 SELECT 권한이 있어야 합니다. | alice는 뷰의 소스 테이블에 대한 SELECT 권한과 뷰의 대상 테이블에 대한 INSERT 권한이 있어야 합니다. |
INVOKER | 사용자는 뷰의 소스 테이블에 대한 SELECT 권한이 있어야 합니다. | materialized view에는 SQL SECURITY INVOKER를 지정할 수 없습니다. |
NONE | - | - |
SQL SECURITY NONE은 더 이상 권장되지 않는 옵션입니다. SQL SECURITY NONE으로 뷰를 생성할 수 있는 권한이 있는 사용자는 임의의 쿼리를 실행할 수 있습니다.
따라서 이 옵션으로 뷰를 생성하려면 GRANT ALLOW SQL SECURITY NONE TO <user> 권한이 필요합니다.DEFINER/SQL SECURITY를 지정하지 않으면 기본값이 사용됩니다:
SQL SECURITY: 일반 뷰에는INVOKER, materialized view에는DEFINER(설정으로 구성 가능)DEFINER:CURRENT_USER(설정으로 구성 가능)
DEFINER/SQL SECURITY를 지정하지 않고 뷰를 ATTACH하면, materialized view의 기본값은 SQL SECURITY NONE이고 일반 뷰의 기본값은 SQL SECURITY INVOKER입니다.
기존 뷰의 SQL 보안을 변경하려면 다음을 사용합니다:
예시
라이브 view
갱신 가능 materialized view
interval은 단순한 인터벌의 연속입니다:
APPEND를 지정하면 각 갱신 시 기존 행을 삭제하지 않고 테이블에 행을 삽입합니다. 이 삽입은 일반적인INSERT INTO ... SELECT쿼리와 마찬가지로 원자적이지 않습니다.- 그렇지 않으면 각 갱신 시 테이블의 이전 내용이 원자적으로 대체됩니다.
- 삽입 트리거가 없습니다.
SELECT에 지정된 테이블에 새 데이터가 삽입되어도 갱신 가능 materialized view로 자동 반영되지 않습니다. 대신 데이터 삽입은 주기적 또는 수동 갱신 실행 중에만 이루어집니다. SELECT쿼리에는 제한이 없습니다. 테이블 함수(예:url()), 뷰, UNION, JOIN을 모두 사용할 수 있습니다.
쿼리의
REFRESH ... SETTINGS 부분에 있는 설정은 갱신 설정(예: refresh_retries)이며, 일반 설정(예: max_threads)과는 구분됩니다. 일반 설정은 쿼리 끝에 SETTINGS를 사용해 지정할 수 있습니다.갱신 일정
RANDOMIZE FOR는 각 갱신 시각을 무작위로 조정합니다. 예:
REFRESH EVERY 1 MINUTE가 설정된 뷰의 갱신에 2분이 걸리면, 실제로는 2분마다 갱신됩니다. 이후 속도가 빨라져 10초 만에 갱신을 마치게 되면, 다시 1분마다 갱신됩니다. (즉, 누락된 갱신을 따라잡기 위해 10초마다 갱신되지는 않습니다. 그런 식의 밀린 갱신은 존재하지 않습니다.)
또한 CREATE 쿼리에서 EMPTY를 지정하지 않는 한, materialized view가 생성된 직후 즉시 갱신이 시작됩니다. EMPTY를 지정하면 첫 번째 갱신은 일정에 따라 수행됩니다.
복제된 DB에서
APPEND 모드에서는 SETTINGS all_replicas = 1을 사용해 coordination을 비활성화할 수 있습니다. 이렇게 하면 각 레플리카가 서로 독립적으로 갱신을 수행합니다. 이 경우 ReplicatedMergeTree는 필요하지 않습니다.
APPEND가 아닌 모드에서는 coordination된 갱신만 지원됩니다. coordination되지 않은 방식을 사용하려면 Atomic 데이터베이스와 CREATE ... ON CLUSTER 쿼리를 사용해 모든 레플리카에 갱신 가능 구체화 뷰를 생성하십시오.
coordination은 Keeper를 통해 수행됩니다. znode 경로는 default_replica_path 서버 설정으로 결정됩니다.
갱신 종속성
DEPENDS ON은 서로 다른 테이블의 갱신을 동기화합니다. 예를 들어, 2개의 갱신 가능 materialized view로 이루어진 체인이 있다고 가정하겠습니다.
DEPENDS ON이 없으면 두 뷰 모두 자정에 갱신을 시작하므로, 일반적으로 destination에서는 source에 있는 전날 데이터가 표시됩니다. 종속성을 추가하면:
source의 갱신이 완료된 후에만 destination의 갱신이 시작되므로, destination은 최신 데이터를 기반으로 하게 됩니다.
또는 다음과 같이 동일한 결과를 얻을 수 있습니다:
1 HOUR는 source의 갱신 주기보다 짧은 임의의 기간일 수 있습니다. 종속 테이블은 의존하는 어떤 항목보다도 더 자주 갱신되지 않습니다. 이는 실제 갱신 주기를 여러 번 지정하지 않고 갱신 가능 뷰의 연쇄를 구성하는 올바른 방법입니다.
추가 예시는 다음과 같습니다:
REFRESH EVERY 1 DAY OFFSET 10 MINUTE(destination)는REFRESH EVERY 1 DAY(source)에 종속됩니다.
source의 갱신에 10분 이상 걸리면destination은 이를 기다립니다.REFRESH EVERY 1 DAY OFFSET 1 HOUR는REFRESH EVERY 1 DAY OFFSET 23 HOUR에 종속됩니다.
해당 갱신이 서로 다른 날짜에 발생하더라도 위와 비슷합니다.X+1일의destination갱신은X일의source갱신을 기다립니다(2시간 이상 걸리는 경우).REFRESH EVERY 2 HOUR는REFRESH EVERY 1 HOUR에 종속됩니다.
2 HOUR갱신은 한 시간 걸러 한 번씩1 HOUR갱신 후에 수행됩니다. 예를 들어 자정 갱신 후, 그다음에는 오전 2시 갱신 후에 수행됩니다.REFRESH EVERY 1 MINUTE는REFRESH EVERY 2 HOUR에 종속됩니다.
destination은source가 갱신될 때마다 한 번, 즉 2시간마다 갱신됩니다. 따라서1 MINUTE는 사실상 무시됩니다.REFRESH AFTER 1 HOUR는REFRESH AFTER 1 HOUR에 종속됩니다.
현재로서는 권장되지 않습니다.
DEPENDS ON은 갱신 가능 materialized view 사이에서만 작동합니다. 일반 테이블을 DEPENDS ON 목록에 포함하면 해당 뷰는 더 이상 갱신되지 않습니다(종속 항목은 ALTER로 제거할 수 있으며, 갱신 매개변수 변경을 참조하십시오).갱신 설정
refresh_retries- 갱신 쿼리가 예외로 실패한 경우 재시도할 횟수입니다. 모든 재시도가 실패하면 다음으로 예약된 갱신 시각으로 넘어갑니다. 0은 재시도하지 않음을, -1은 무한 재시도를 의미합니다. 기본값: 2.refresh_retry_initial_backoff_ms-refresh_retries가 0이 아닐 때 첫 번째 재시도 전까지의 지연 시간입니다. 이후 각 재시도마다 지연 시간이 두 배로 증가하며, 최대refresh_retry_max_backoff_ms까지 늘어납니다. 기본값: 100 ms.refresh_retry_max_backoff_ms- 갱신 시도 사이의 지연 시간이 지수적으로 증가할 때의 상한입니다. 기본값: 60000 ms(1분).all_replicas-APPEND를 사용하는 복제된 데이터베이스에서 모든 레플리카가 각각 독립적으로 갱신할지, 아니면 예약된 각 시각마다 하나의 레플리카만 갱신할지를 제어합니다. 이 설정은 뷰를 생성한 후에는 변경할 수 없습니다. 기본값:false.prefer_dependency_replica- 뷰에DEPENDS ON이 있으면 상위 갱신을 실행한 레플리카가 종속 갱신 실행에서 우선권을 가지며, 다른 레플리카는prefer_dependency_replica_delay_ms만큼 시도를 지연합니다.SharedMergeTree와 함께 사용하면 복제 지연으로 인해 종속 갱신 체인에서 데이터가 누락되는 문제를 방지하는 데 유용합니다. 기본값:false.prefer_dependency_replica_delay_ms-prefer_dependency_replica가 활성화된 경우, 우선순위가 없는 레플리카가 종속 갱신 실행을 시도하기 전에 대기하는 시간입니다. 기본값: 2000 ms.
갱신 매개변수 변경
ALTER TABLE ... MODIFY REFRESH를 사용해 변경합니다:
EVERY 또는 AFTER)은 필수입니다. 이 구문은 항상 모든 갱신 매개변수(스케줄, RANDOMIZE FOR, DEPENDS ON, 갱신 설정)를 지정된 값으로 모두 대체합니다. 생략된 항목은 기본값으로 재설정되거나(설정), 제거됩니다(의존성, 무작위화).
-
갱신 설정만 변경하려는 경우(예:
refresh_retries)에는 기존 스케줄을 다시 지정하십시오: -
materialized view에서는
ALTER TABLE ... MODIFY SETTING refresh_retries = ...가 지원되지 않습니다. 반드시MODIFY REFRESH를 사용해야 합니다. -
APPEND를 추가하거나 제거하는 것은 지원되지 않습니다. -
all_replicas설정은 생성 후 변경할 수 없습니다.
기타 작업
system.view_refreshes 테이블에서 확인할 수 있습니다. 특히 갱신 진행 상황(실행 중인 경우), 마지막 및 다음 갱신 시각, 갱신이 실패한 경우의 예외 메시지가 포함됩니다.
갱신을 수동으로 중지, 시작, 실행 또는 취소하려면 SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW를 사용하십시오.
갱신이 완료될 때까지 기다리려면 SYSTEM WAIT VIEW를 사용하십시오. 특히 뷰를 생성한 후 초기 갱신이 완료될 때까지 기다릴 때 유용합니다.
재미있는 사실: 갱신 쿼리는 현재 갱신 중인 뷰를 읽을 수 있으며, 갱신 전 버전의 데이터를 보게 됩니다. 즉, Conway의 생명 게임을 구현할 수 있습니다: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
윈도우 뷰
이 기능은 실험 단계이며, 향후 릴리스에서 하위 호환성이 깨지는 방식으로 변경될 수 있습니다. allow_experimental_window_view 설정으로 윈도우 뷰와
WATCH 쿼리 사용을 활성화하십시오. set allow_experimental_window_view = 1 명령을 입력하십시오.WATCH 쿼리를 사용해 알림을 전송할 수 있습니다.
윈도우 뷰 생성은 MATERIALIZED VIEW 생성과 유사합니다. 윈도우 뷰는 중간 데이터를 저장하기 위한 내부 스토리지 엔진이 필요합니다. 내부 스토리지는 INNER ENGINE 절을 사용해 지정할 수 있으며, 지정하지 않으면 기본 내부 엔진으로 AggregatingMergeTree를 사용합니다.
TO [db].[table] 없이 윈도우 뷰를 생성할 때는 데이터를 저장할 테이블 엔진인 ENGINE을 반드시 지정해야 합니다.
시간 윈도우 함수
시간 속성
time_attr를 테이블 컬럼으로 설정하거나 now() 함수를 사용해 정의할 수 있습니다. 다음 쿼리는 처리 시간을 사용하는 윈도우 뷰를 생성합니다.
WATERMARK 구문을 사용해 이벤트 시간 처리를 지원합니다.
윈도우 뷰는 세 가지 워터마크 전략을 제공합니다.
STRICTLY_ASCENDING: 지금까지 관측된 최대 타임스탬프의 워터마크를 내보냅니다. 타임스탬프가 최대 타임스탬프보다 작은 행은 지연된 행으로 간주되지 않습니다.ASCENDING: 지금까지 관측된 최대 타임스탬프에서 1을 뺀 워터마크를 내보냅니다. 타임스탬프가 최대 타임스탬프와 같거나 더 작은 행은 지연된 행으로 간주되지 않습니다.BOUNDED: WATERMARK=INTERVAL. 관측된 최대 타임스탬프에서 지정된 지연 시간을 뺀 워터마크를 내보냅니다.
WATERMARK를 사용하여 윈도우 뷰를 생성하는 예시입니다.
ALLOWED_LATENESS=INTERVAL을 설정해 지연 이벤트 처리를 지원합니다. 지연 처리의 예시는 다음과 같습니다.
ALTER TABLE ... MODIFY QUERY statement를 사용하면 윈도우 뷰에 지정된 SELECT 쿼리를 수정할 수 있습니다. 새 SELECT 쿼리의 결과 데이터 구조는 TO [db.]name 절의 유무와 관계없이 원래 SELECT 쿼리와 동일해야 합니다. 중간 상태는 재사용할 수 없으므로 현재 윈도우의 데이터는 손실된다는 점에 유의하십시오.
새 윈도우 모니터링
TO 구문을 사용해 결과를 테이블로 출력할 수도 있습니다.
LIMIT를 지정할 수 있습니다. EVENTS 절을 사용하면 WATCH 쿼리의 축약형을 사용할 수 있으며, 쿼리 결과 대신 최신 쿼리 워터마크만 받습니다.
설정
window_view_clean_interval: 오래된 데이터를 정리하기 위한 윈도우 뷰 정리 간격(초)입니다. 시스템 시간 또는WATERMARK구성에 따라 아직 완전히 트리거되지 않은 윈도우는 유지되며, 그 외 데이터는 삭제됩니다.window_view_heartbeat_interval: watch 쿼리가 살아 있음을 나타내는 하트비트 간격(초)입니다.wait_for_window_view_fire_signal_timeout: 이벤트 시간 처리에서 윈도우 뷰 실행 신호를 기다리는 시간 제한입니다.
예시
data라는 로그 테이블에서 10초마다 클릭 로그의 개수를 집계해야 한다고 가정하겠습니다. 테이블 구조는 다음과 같습니다:
WATCH 쿼리를 사용해 결과를 확인합니다.
data 테이블에 삽입되면,
WATCH 쿼리는 다음과 같이 결과가 출력되어야 합니다:
TO 구문을 사용해 출력을 다른 테이블로 보낼 수도 있습니다.
*window_view*라는 이름을 사용합니다).
윈도우 뷰 사용
- 모니터링: 메트릭 로그를 시간별로 집계하고 계산한 뒤, 결과를 대상 테이블(target table)에 출력합니다. 대시보드는 대상 테이블을 소스 테이블로 사용할 수 있습니다.
- 분석: 시간 윈도우에서 데이터를 자동으로 집계하고 전처리합니다. 이는 대량의 로그를 분석할 때 유용합니다. 전처리를 통해 여러 쿼리에서 반복 계산을 없애고 쿼리 지연 시간을 줄일 수 있습니다.
임시 뷰
- 세션 수명 임시 뷰는 현재 세션이 유지되는 동안에만 존재합니다. 세션이 종료되면 자동으로 삭제됩니다.
- 데이터베이스 없음 임시 뷰에는 데이터베이스 이름을 붙여 지정할 수 없습니다. 임시 뷰는 데이터베이스 바깥(세션 네임스페이스)에 존재합니다.
-
복제되지 않음 / ON CLUSTER 없음
임시 객체는 세션에 로컬로만 존재하므로
ON CLUSTER를 사용해 생성할 수 없습니다. - 이름 해석 임시 객체(테이블 또는 뷰)와 영구 객체의 이름이 같고, 쿼리에서 데이터베이스를 지정하지 않고 해당 이름을 참조하면 임시 객체가 사용됩니다.
-
논리 객체(저장소 없음)
임시 뷰는
SELECT텍스트만 저장합니다(내부적으로View저장소를 사용). 데이터를 영구 저장하지 않으며INSERT를 받을 수 없습니다. -
Engine 절
ENGINE은 지정하지 않아도 됩니다.ENGINE = View로 지정하더라도 무시되며 동일한 논리 뷰로 처리됩니다. -
보안 / 권한
임시 뷰를 생성하려면
CREATE TEMPORARY VIEW권한이 필요하며, 이 권한은CREATE VIEW에 암묵적으로 포함됩니다. -
SHOW CREATE
임시 뷰의 DDL을 출력하려면
SHOW CREATE TEMPORARY VIEW view_name;를 사용하십시오.
구문
OR REPLACE는 임시 뷰에서는 지원되지 않습니다(임시 테이블과 일관성을 맞추기 위함입니다). 임시 뷰를 “대체”해야 하는 경우, 해당 뷰를 삭제한 후 다시 생성하십시오.
예시
지원되지 않는 항목 / 제한 사항
CREATE OR REPLACE TEMPORARY VIEW ...→ 허용되지 않음 (DROP+CREATE사용).CREATE TEMPORARY MATERIALIZED VIEW .../WINDOW VIEW→ 허용되지 않음.CREATE TEMPORARY VIEW db.view AS ...→ 허용되지 않음 (데이터베이스 지정자 사용 불가).CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ 허용되지 않음 (임시 객체는 세션 로컬임).POPULATE,REFRESH,TO [db.table], 내부 엔진, 그리고 모든 MV 전용 절 → 임시 뷰에는 적용되지 않음.
분산 쿼리 관련 참고 사항
Memory)을 참조하는 경우, 해당 데이터는 임시 테이블과 마찬가지로 분산 쿼리 실행 중 원격 서버로 전송될 수 있습니다.