본문으로 건너뛰기
최종 수정: 에

증분 뷰 유지 관리(IVM)

증분 뷰 유지 관리(Incremental View Maintenance, IVM)는 기본 테이블의 행 수준 변경 사항을 바탕으로 비동기 구체화된 뷰를 유지 관리합니다. 일반적인 비동기 구체화된 뷰는 전체 데이터나 영향을 받은 모든 파티션을 다시 계산하지만, IVM은 두 새로 고침 사이에 기본 테이블에서 삽입, 업데이트, 삭제된 행만 계산하고 해당 변경 사항을 구체화된 뷰에 적용합니다.

실험적 기능

IVM은 Doris 5.0.0부터 사용할 수 있습니다. 실험적 기능이며 기본적으로 비활성화되어 있습니다. 사용하기 전에 FE 구성에서 changelog와 Table Stream을 활성화하세요. 사전 요구 사항을 참조하세요.

IVM을 사용하기 적합한 경우​

새로 고침 방식을 선택하기 전에 새로 고침마다 변경되는 행 수, 영향을 받는 파티션의 크기, 일관성 요구 사항을 비교하세요.

시나리오권장 사항이유
기본 테이블에서 삽입, 업데이트, 삭제가 자주 발생하며, 변경된 행이 테이블이나 파티션에서 차지하는 비율이 작음IVM 사용두 새로 고침 사이의 행 수준 변경 사항만 계산하므로 전체 파티션을 다시 계산하지 않음
변경 사항이 소수의 파티션에 집중되어 있고 해당 파티션의 재계산 비용을 감당할 수 있음PARTITIONS 사용구성이 더 간단하며 영향을 받은 파티션을 다시 계산함
최초 기준 상태 구축, 적은 데이터양 또는 IVM 기준 상태 복구COMPLETE 사용구체화된 뷰의 전체 데이터를 다시 계산함
결과가 기본 테이블과 실시간으로 트랜잭션 일관성을 유지해야 함비동기 구체화된 뷰를 사용하지 않음IVM도 비동기 작업으로 새로 고침하므로 실시간 일관성을 제공하지 않음

파티션 수준 증분 새로 고침과의 차이​

Doris는 비동기 구체화된 뷰에 네 가지 새로 고침 방식을 지원합니다. IVM은 INCREMENTAL에 해당합니다. PARTITIONS가 제공하는 파티션 수준 증분 새로 고침과 혼동하지 마세요.

새로 고침 방식계산 단위적합한 시나리오조건을 충족하지 못할 때의 동작
INCREMENTAL행 수준 변경 사항변경된 행 수가 전체 테이블이나 영향을 받은 파티션의 행 수보다 훨씬 적음기본적으로 실패하며, FALLBACK을 지정하면 폴백할 수 있음
PARTITIONS영향을 받은 구체화된 뷰의 각 파티션변경 사항이 소수의 파티션에 집중되어 있고 재계산 비용을 감당할 수 있음기본적으로 실패하며, COMPLETE로 폴백하려면 FALLBACK을 지정해야 함
COMPLETE전체 데이터적은 데이터양, 최초 기준 상태 구축 또는 IVM 기준 상태 복구항상 전체 데이터를 다시 계산함
AUTODoris가 자동 선택Doris가 사용 가능한 전략을 선택하도록 하려는 경우IVM, 파티션 새로 고침, 전체 새로 고침을 순서대로 시도하여 사용 가능한 방식을 적용함

INCREMENTAL FALLBACK은 새로 고침 시점의 실패 처리 방식만 변경합니다. 구체화된 뷰를 생성할 때 정의 SQL은 여전히 IVM 요구 사항을 충족해야 합니다. FALLBACK을 지정해도 지원되지 않는 정의가 생성 검사를 통과할 수는 없습니다.

동작 원리​

IVM은 Doris의 changelog 및 Table Stream 기능을 재사용합니다:

IVM 동작 원리: 기본 테이블의 변경 사항이 changelog를 거쳐 내부 Table Stream으로 전달됩니다. 델타 계획은 아직 소비하지 않은 변경 사항과 일관된 스냅샷을 결합해 구체화된 뷰를 업데이트하고, 같은 트랜잭션에서 소비 오프셋을 전진시킵니다

IVM을 지원하는 구체화된 뷰를 생성하면 Doris는 증분 유지 관리에 참여하는 각 기본 테이블에 대해 내부 Table Stream을 생성합니다. 내부 Stream의 이름은 __doris_ivm_stream_으로 시작합니다. 이러한 Stream을 직접 생성하거나 소비하거나 삭제할 필요는 없습니다.

새로 고침 시 Doris는 각 기본 테이블에서 아직 소비하지 않은 변경 사항으로 델타 계획을 생성합니다. 조인 쿼리에서는 소비 오프셋에 맞춘 기본 테이블의 스냅샷도 읽어, 여러 테이블의 계산이 일관된 데이터 경계를 사용하도록 합니다. 구체화된 뷰 데이터와 소비 오프셋은 같은 트랜잭션에서 커밋됩니다. 트랜잭션이 실패하면 둘 다 커밋되지 않습니다.

사전 요구 사항​

버전 및 FE 구성​

  1. Doris 5.0.0 이상을 사용하세요.

  2. 모든 FE의 fe.conf에 다음 옵션을 설정하고 FE를 재시작하세요.

    enable_feature_changelog = true
    enable_table_stream = true

두 옵션 모두 정적 구성으로, 동적으로 변경할 수 없습니다. enable_feature_changelog는 changelog와 전역 커밋 타임스탬프를 활성화하고, enable_table_stream은 Table Stream DDL과 내부 Stream 관리를 활성화합니다.

기본 테이블 요구 사항​

증분 유지 관리에 참여하는 기본 테이블은 Internal Catalog의 Doris OLAP 내부 테이블이어야 하며, 다음 요구 사항을 충족해야 합니다.

기본 테이블 모델지원 여부요구 사항 및 동작
Unique Key Merge-on-Write지원changelog와 변경 전 이미지를 활성화해야 하며, 삽입, 업데이트, 삭제를 모두 처리함
Duplicate Key지원changelog를 활성화해야 함. 추가된 변경 사항만 제공하며, 삭제 조건식으로 실행한 삭제는 기록하지 않음
Unique Key Merge-on-Read미지원대신 Merge-on-Write 사용
Aggregate Key증분 유지 관리에는 미지원excluded_trigger_tables에 포함되어 증분 새로 고침을 트리거하지 않는 테이블로만 사용할 수 있음
외부 테이블미지원IVM의 증분 기본 테이블은 Doris 내부 테이블이어야 함

업데이트와 삭제를 처리해야 하는 워크로드에는 Unique Key Merge-on-Write 테이블을 사용하고, 생성 시 다음 속성을 설정하세요.

PROPERTIES (
"enable_unique_key_merge_on_write" = "true",
"changelog.enable" = "true",
"changelog.need_historical_value" = "true"
);

Changelog는 테이블을 생성할 때만 활성화할 수 있으며, 이후에는 비활성화할 수 없습니다. 테이블 모델, 컬럼 유형, 쓰기 방식 및 DDL 제한 사항의 전체 목록은 Changelog를 참조하세요.

빠른 시작​

다음 예제에서는 주문을 상태별로 집계하는 IVM을 생성합니다. 첫 번째 새로 고침은 COMPLETE를 사용해 전체 기준 상태를 구축하고, 이후 새로 고침은 INCREMENTAL FALLBACK을 사용해 행 수준 변경 사항을 처리합니다.

진행 단계는 다음과 같습니다.

  1. changelog가 활성화된 Unique Key Merge-on-Write 기본 테이블을 생성합니다.
  2. REFRESH INCREMENTAL FALLBACK으로 IVM을 생성합니다.
  3. COMPLETE 새로 고침을 실행해 전체 기준 상태를 구축합니다.
  4. 기본 테이블 데이터를 변경하고 증분 새로 고침을 실행합니다.
  5. 새로 고침 작업을 조회해 결과와 폴백 사유를 확인합니다.

1단계: 기본 테이블 생성 및 초기 데이터 적재​

changelog와 변경 전 이미지가 활성화되고 업데이트와 삭제를 지원하는 기본 테이블을 생성합니다:

CREATE DATABASE IF NOT EXISTS ivm_demo;
USE ivm_demo;

CREATE TABLE orders (
order_id BIGINT,
order_status VARCHAR(16),
amount DECIMAL(10, 2)
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"enable_unique_key_merge_on_write" = "true",
"changelog.enable" = "true",
"changelog.need_historical_value" = "true"
);

INSERT INTO orders VALUES
(1, 'created', 100.00),
(2, 'created', 200.00),
(3, 'paid', 300.00);

2단계: IVM 생성​

REFRESH INCREMENTAL을 CREATE MATERIALIZED VIEW에 지정합니다. 이 예제에서는 FALLBACK도 지정하므로, 변경 사항을 안전하게 증분 계산할 수 없을 때 Doris가 파티션 새로 고침이나 전체 새로 고침으로 폴백할 수 있습니다. 각 새로 고침을 단계별로 관찰할 수 있도록 트리거는 ON MANUAL로 설정합니다. 운영 환경의 뷰는 일반적으로 예약 트리거나 커밋 시 트리거로 전환합니다. 자동 새로 고침 간격 설정을 참조하세요.

CREATE MATERIALIZED VIEW orders_by_status
BUILD DEFERRED
REFRESH INCREMENTAL FALLBACK ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES (
"replication_num" = "1"
)
AS
SELECT
order_status,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY order_status;

뷰를 생성하면 Doris가 해당 내부 Table Stream을 자동으로 생성합니다. mv_infos로 매핑을 확인할 수 있습니다.

SELECT Name, RefreshInfo, IvmBaseTableStreams
FROM mv_infos("database" = "ivm_demo")
WHERE Name = "orders_by_status";

3단계: 전체 기준 상태 구축​

첫 번째 새로 고침에는 COMPLETE를 사용해 이후 증분 유지 관리에 사용할 기준 상태를 구축합니다.

REFRESH MATERIALIZED VIEW orders_by_status COMPLETE;

새로 고침 작업은 비동기로 실행됩니다. 작업이 성공하면 구체화된 뷰를 조회합니다.

SELECT order_status, order_count, total_amount
FROM orders_by_status
ORDER BY order_status;
+--------------+-------------+--------------+
| order_status | order_count | total_amount |
+--------------+-------------+--------------+
| created | 2 | 300.00 |
| paid | 1 | 300.00 |
+--------------+-------------+--------------+

4단계: 변경 사항 쓰기 및 증분 새로 고침 실행​

다음 문은 주문 1을 업데이트하고, 주문 2를 삭제하고, 주문 4를 삽입합니다.

INSERT INTO orders VALUES (1, 'paid', 100.00);
DELETE FROM orders WHERE order_id = 2;
INSERT INTO orders VALUES (4, 'created', 400.00);

REFRESH MATERIALIZED VIEW orders_by_status INCREMENTAL FALLBACK;

새로 고침 작업이 성공하면 IVM은 위의 행 수준 변경 사항만 처리한 상태가 됩니다. 구체화된 뷰에는 이제 다음 데이터가 포함됩니다.

SELECT order_status, order_count, total_amount
FROM orders_by_status
ORDER BY order_status;
+--------------+-------------+--------------+
| order_status | order_count | total_amount |
+--------------+-------------+--------------+
| created | 1 | 400.00 |
| paid | 2 | 400.00 |
+--------------+-------------+--------------+

5단계: 새로 고침 방식 및 폴백 사유 확인​

최신 새로 고침 작업을 조회해 요청된 방식, 실제 새로 고침 범위, 폴백 사유를 확인합니다.

SELECT Status, TaskContext, RefreshMode, IvmFallbackReason, ErrorMsg
FROM tasks("type" = "mv")
WHERE MvDatabaseName = "ivm_demo"
AND MvName = "orders_by_status"
ORDER BY CreateTime DESC, TaskId DESC
LIMIT 1;
  • TaskContext는 이 작업에서 요청한 새로 고침 방식을 기록합니다. 예를 들어 INCREMENTAL입니다.
  • RefreshMode는 작업이 실제로 새로 고친 파티션 범위를 기록합니다. 값은 COMPLETE, PARTIAL 또는 NOT_REFRESH입니다.
  • IvmFallbackReason은 IVM 폴백이 발생하지 않으면 비어 있으며, 발생한 경우에는 고정된 폴백 사유를 기록합니다.
  • ErrorMsg는 엄격한 증분 새로 고침이 실패한 경우 상세 내용을 기록합니다.

지원되는 쿼리​

IVM은 구체화된 뷰를 생성할 때 정의 SQL을 검사합니다. REFRESH INCREMENTAL을 명시한 경우, 지원되지 않는 정의는 생성에 실패합니다. 이 절에서는 지원되는 관계 연산과 집계 함수를 각각 실행 가능한 예제와 함께 설명한 뒤, 지원되지 않는 쿼리 형식을 안내합니다.

예제 테이블​

이 절의 예제에서는 고객 테이블 customers, 매출 테이블 sales, 환불 테이블 refunds를 기본 테이블로 사용합니다. 모두 changelog와 변경 전 이미지가 활성화된 Unique Key Merge-on-Write 테이블입니다. ivm_demo 데이터베이스에서 실행할 수 있으며, 이 데이터베이스는 빠른 시작에서 생성했습니다:

CREATE TABLE customers (
customer_id BIGINT,
name VARCHAR(32),
city VARCHAR(16)
)
UNIQUE KEY(customer_id)
DISTRIBUTED BY HASH(customer_id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"enable_unique_key_merge_on_write" = "true",
"changelog.enable" = "true",
"changelog.need_historical_value" = "true"
);

CREATE TABLE sales (
sale_id BIGINT,
customer_id BIGINT,
channel VARCHAR(16),
amount DECIMAL(10, 2)
)
UNIQUE KEY(sale_id)
DISTRIBUTED BY HASH(sale_id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"enable_unique_key_merge_on_write" = "true",
"changelog.enable" = "true",
"changelog.need_historical_value" = "true"
);

CREATE TABLE refunds (
refund_id BIGINT,
sale_id BIGINT,
amount DECIMAL(10, 2)
)
UNIQUE KEY(refund_id)
DISTRIBUTED BY HASH(refund_id) BUCKETS 1
PROPERTIES (
"replication_num" = "1",
"enable_unique_key_merge_on_write" = "true",
"changelog.enable" = "true",
"changelog.need_historical_value" = "true"
);

INSERT INTO customers VALUES
(1, 'Alice', 'Beijing'),
(2, 'Bob', 'Shanghai'),
(3, 'Carol', 'Beijing');

INSERT INTO sales VALUES
(101, 1, 'web', 120.00),
(102, 1, 'app', 80.00),
(103, 2, 'web', 200.00),
(104, NULL, 'store', 50.00);

INSERT INTO refunds VALUES
(9001, 102, 80.00),
(9002, 103, 50.00);

이 데이터에는 조인 및 집계 예제에서 사용할 두 가지 특수한 경우가 의도적으로 포함되어 있습니다. 매장 주문 104에는 고객이 없으므로 customer_id가 NULL이고, 고객 Carol에게는 아직 주문이 없습니다.

모든 예제는 같은 순서로 실행합니다. 먼저 해당 예제의 CREATE MATERIALIZED VIEW를 실행한 다음, REFRESH MATERIALIZED VIEW <mv_name> COMPLETE를 실행해 기준 상태를 구축합니다. 새로 고침 작업이 성공하면 SELECT * FROM <mv_name>을 실행해 결과를 확인합니다. 여기에 표시한 결과는 앞쪽 컬럼을 기준으로 정렬한 것입니다.

지원되는 관계 연산​

연산설명
컬럼 및 표현식일부 컬럼을 선택하거나 결정적 표현식으로 새 컬럼을 계산함
WHERE 필터조건에 따라 기본 테이블의 행을 필터링함
FROM 서브쿼리FROM 절에 별칭이 있는 서브쿼리를 사용할 수 있음. 중첩할 수 있으며 집계를 포함해서는 안 됨
상수 행SELECT에 FROM이 없고 항상 상수로 이루어진 행 하나를 반환하는 경우. 예를 들어 SELECT -1, 'unknown'. UNION ALL의 분기, 조인의 한쪽 입력 또는 전체 정의로 사용할 수 있음
GROUP BY 집계집계는 쿼리의 가장 바깥쪽 연산이어야 하며, 그 위에는 프로젝션만 올 수 있음. 그룹화 컬럼과 집계 결과에 대한 결정적 표현식을 지원함
GROUPING SETS, ROLLUP, CUBEGROUPING() 및 GROUPING_ID()와 함께 사용할 수 있으며, GROUP BY와 같은 제한이 적용됨
SELECT DISTINCT집계 함수가 없는 GROUP BY로 처리하며, GROUP BY와 같은 제한이 적용됨
INNER JOIN, CROSS JOIN다중 테이블 조인 및 셀프 조인을 지원함
LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN모든 행을 유지하는 쪽(LEFT JOIN의 왼쪽, RIGHT JOIN의 오른쪽, FULL JOIN의 양쪽)은 changelog가 없고 excluded_trigger_tables에 포함된 Duplicate Key 테이블이어서는 안 됨. 이러한 테이블의 행에는 고정된 행 식별자가 없기 때문임
중첩 외부 조인외부 조인에서 NULL로 채워질 수 있는 쪽이 조인으로 구성된 경우. 해당 쪽이 복잡할수록 증분 새로 고침 계획이 커짐
UNION ALL서로 다른 테이블, 같은 테이블 또는 상수 행을 분기로 사용할 수 있음
연쇄 IVM다른 IVM을 기본 테이블로 사용함. 기본 테이블로 사용하는 IVM에는 changelog와 변경 전 이미지를 활성화해야 함

다음 예제는 범주별로 구성되어 있습니다.

단일 테이블 쿼리​

필요한 컬럼을 선택하거나 표현식으로 새 컬럼을 계산합니다. 표현식은 결정적이어야 합니다. 즉, 같은 입력은 항상 같은 결과를 생성해야 합니다. 예를 들어 NOW()와 RAND()는 사용할 수 없습니다.

CREATE MATERIALIZED VIEW mv_sales_projection
BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES ("replication_num" = "1")
AS
SELECT sale_id, channel, amount, amount * 0.9 AS discounted_amount
FROM sales;

결과:

+---------+---------+--------+-------------------+
| sale_id | channel | amount | discounted_amount |
+---------+---------+--------+-------------------+
| 101 | web | 120.00 | 108.000 |
| 102 | app | 80.00 | 72.000 |
| 103 | web | 200.00 | 180.000 |
| 104 | store | 50.00 | 45.000 |
+---------+---------+--------+-------------------+

집계​

그룹별 집계 결과를 계산합니다. 집계 입력은 단일 테이블, 조인, UNION ALL 또는 FROM 서브쿼리일 수 있지만, 집계 자체는 쿼리의 가장 바깥쪽 연산이어야 합니다. 다음 예제는 sales와 customers를 조인한 후 도시별로 집계합니다. 주문 104에는 고객이 없으므로 집계에 포함되지 않습니다.

CREATE MATERIALIZED VIEW mv_city_sales
BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES ("replication_num" = "1")
AS
SELECT c.city, COUNT(*) AS sale_cnt, SUM(s.amount) AS total_amount
FROM sales s
INNER JOIN customers c ON s.customer_id = c.customer_id
GROUP BY c.city;

결과:

+----------+----------+--------------+
| city | sale_cnt | total_amount |
+----------+----------+--------------+
| Beijing | 2 | 200.00 |
| Shanghai | 1 | 200.00 |
+----------+----------+--------------+

집계 위의 프로젝션에서는 컬럼 이름을 바꾸거나 순서를 변경할 수 있으며, 결정적 표현식을 사용해 그룹화 컬럼과 집계 결과를 계산할 수 있습니다. 예를 들어 SUM(amount) * 100, MAX(amount) + 1, SUM(amount) / COUNT(*)는 사용한 집계 함수의 제한 사항을 충족하면 증분 새로 고침을 지원합니다. HAVING과 서브쿼리 또는 조인 입력 내부의 집계는 지원하지 않습니다. 지원되지 않는 쿼리 형식을 참조하세요.

조인​

양쪽에서 일치하는 행만 유지합니다. 주문 104에는 고객이 없으므로 결과에 포함되지 않습니다.

CREATE MATERIALIZED VIEW mv_sales_customer
BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES ("replication_num" = "1")
AS
SELECT s.sale_id, c.name, c.city, s.amount
FROM sales s
INNER JOIN customers c ON s.customer_id = c.customer_id;

결과:

+---------+-------+----------+--------+
| sale_id | name | city | amount |
+---------+-------+----------+--------+
| 101 | Alice | Beijing | 120.00 |
| 102 | Alice | Beijing | 80.00 |
| 103 | Bob | Shanghai | 200.00 |
+---------+-------+----------+--------+

UNION ALL 및 연쇄 IVM​

여러 쿼리의 결과를 중복을 제거하지 않고 결합합니다. 분기는 서로 다른 테이블, 같은 테이블 또는 상수 행에서 가져올 수 있습니다. 다음 예제는 매출과 환불을 하나의 원장으로 결합하고, 환불 금액을 음수로 기록합니다.

CREATE MATERIALIZED VIEW mv_ledger
BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES ("replication_num" = "1")
AS
SELECT sale_id AS doc_id, 'sale' AS doc_type, amount
FROM sales
UNION ALL
SELECT refund_id, 'refund', -amount
FROM refunds;

결과:

+--------+----------+--------+
| doc_id | doc_type | amount |
+--------+----------+--------+
| 101 | sale | 120.00 |
| 102 | sale | 80.00 |
| 103 | sale | 200.00 |
| 104 | sale | 50.00 |
| 9001 | refund | -80.00 |
| 9002 | refund | -50.00 |
+--------+----------+--------+

지원되는 집계 함수​

IVM은 다음 집계 함수를 지원합니다. 인수에는 컬럼이나 결정적 표현식을 사용할 수 있습니다.

  • COUNT(*), COUNT(expr)
  • SUM
  • AVG
  • MIN
  • MAX
  • BITMAP_UNION
  • BITMAP_UNION_COUNT
  • ARRAY_AGG
  • COLLECT_LIST(단일 인수 형식만 지원)

다음 예제는 모두 sales 테이블을 채널별로 그룹화합니다.

COUNT(*)는 행 수를 세고, COUNT(expr)는 expr이 NULL이 아닌 행만 셉니다. 매장 주문 104의 customer_id는 NULL이므로 매장 채널의 member_sale_cnt는 0입니다.

CREATE MATERIALIZED VIEW mv_agg_count
BUILD DEFERRED REFRESH INCREMENTAL ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES ("replication_num" = "1")
AS
SELECT channel,
COUNT(*) AS sale_cnt,
COUNT(customer_id) AS member_sale_cnt
FROM sales
GROUP BY channel;

결과:

+---------+----------+-----------------+
| channel | sale_cnt | member_sale_cnt |
+---------+----------+-----------------+
| app | 1 | 1 |
| store | 1 | 0 |
| web | 2 | 2 |
+---------+----------+-----------------+

DISTINCT를 사용하는 집계 함수(예: COUNT(DISTINCT customer_id))는 지원하지 않습니다. 음수가 아닌 정수 컬럼의 정확한 고유 개수를 계산하려면 대신 BITMAP_UNION_COUNT(TO_BITMAP(customer_id))를 사용하세요. 다만 이 경우 아래 설명과 같이 삭제와 업데이트 시 전체 Bitmap을 다시 계산해야 합니다.

일부 집계 함수는 행이 삭제되면 현재 델타만으로 새 결과를 안전하게 도출할 수 없습니다. Unique Key 테이블의 업데이트는 이전 행을 삭제한 다음 새 행을 쓰므로, 업데이트에서도 다음 상황이 발생할 수 있습니다.

  • 삭제된 값이 현재 MIN 또는 MAX일 가능성이 있으면 전체 데이터를 다시 읽어야 합니다.
  • 삭제가 Bitmap 집계 결과에 영향을 주면 전체 Bitmap을 다시 계산해야 합니다.

이러한 경우 엄격한 INCREMENTAL은 실패하고, INCREMENTAL FALLBACK은 COMPLETE로 폴백합니다.

지원되지 않는 쿼리 형식​

다음 형식은 지원하지 않으며, REFRESH INCREMENTAL을 명시하면 생성에 실패합니다.

  • UNION(즉, UNION DISTINCT), INTERSECT, EXCEPT.
  • ORDER BY, LIMIT, 윈도우 함수.
  • HAVING, 그리고 FROM 서브쿼리 또는 조인 입력 내부에 작성한 집계. 집계는 쿼리의 가장 바깥쪽 연산으로만 사용할 수 있습니다. 집계 결과를 필터링하려면 구체화된 뷰를 조회할 때 필터링하세요.
  • WHERE 또는 SELECT 목록의 서브쿼리. 예를 들어 IN (SELECT ...), EXISTS (SELECT ...), 스칼라 서브쿼리입니다. IN 서브쿼리와 스칼라 서브쿼리는 Multiple columns returned by subquery are not yet supported 오류로 실패할 수 있습니다. 이 역시 IVM이 해당 서브쿼리를 지원하지 않기 때문에 발생합니다.
  • WITH 절(CTE). FROM 서브쿼리로 다시 작성하세요.
  • LATERAL VIEW.
  • 일반적인 비동기 구체화된 뷰를 기본 테이블로 사용하는 경우. 연쇄 유지 관리에서는 하위 구체화된 뷰도 IVM이어야 합니다.
  • 위 표에 나열되지 않은 모든 연산.

새로 고침 및 폴백​

생성 시 새로 고침 전략 선택​

정의생성 시 동작이후 새로 고침의 기본 동작
REFRESH INCREMENTALIVM 지원 범위를 엄격하게 검사하며, 지원되지 않으면 생성에 실패함IVM만 시도하며, IVM이 실패하면 작업이 실패함
REFRESH INCREMENTAL FALLBACK엄격한 모드와 동일하며, IVM 검사를 통과해야 함IVM을 먼저 시도한 후 사유에 따라 폴백함
REFRESH AUTO정의가 IVM을 지원하는지 확인하고, 지원하지 않으면 일반적인 비동기 구체화된 뷰를 생성함IVM을 지원하는 뷰에서는 IVM, 파티션 새로 고침, 전체 새로 고침을 순서대로 시도함
REFRESH PARTITIONS [FALLBACK]구체화된 뷰에 PARTITION BY가 정의되어 있어야 함변경된 파티션을 다시 계산하며, FALLBACK을 지정하면 전체 새로 고침으로 폴백할 수 있음
REFRESH COMPLETEIVM 메타데이터를 생성하지 않음항상 전체 새로 고침을 수행함

자동 새로 고침 간격 설정​

IVM은 비동기 구체화된 뷰의 트리거 방식을 재사용하며, 별도의 트리거 구문은 없습니다. 트리거는 ON 절에 지정하며, 이 절은 REFRESH INCREMENTAL [FALLBACK] 뒤에 옵니다.

트리거구문설명
수동ON MANUAL기본값. REFRESH MATERIALIZED VIEW를 실행할 때만 새로 고침함
예약ON SCHEDULE EVERY <interval> <unit> [STARTS '<start_time>']고정 간격으로 증분 새로 고침을 자동 실행함
커밋 시ON COMMIT기본 테이블의 데이터 적재 트랜잭션이 커밋된 후 증분 새로 고침을 자동 실행함

예약 간격의 규칙은 다음과 같습니다.

  • <interval>은 양의 정수여야 하며, <unit>에는 MINUTE, HOUR, DAY 또는 WEEK를 사용할 수 있습니다.
  • 최소 새로 고침 간격은 EVERY 1 MINUTE입니다. SECOND를 지정하면 interval time unit can not be second 오류로 실패합니다. FE 옵션 enable_job_schedule_second_for_test를 사용하면 초 단위 간격을 허용할 수 있지만, 테스트 전용이므로 운영 환경에서는 활성화해서는 안 됩니다.
  • STARTS는 첫 예약 실행 시각을 'yyyy-MM-dd HH:mm:ss' 형식으로 설정하며, 현재 시각보다 이후여야 합니다. 이를 지정하지 않으면 구체화된 뷰를 생성한 시점에서 한 간격이 지난 후 첫 번째 새로 고침이 실행됩니다. 이후 실행 시각은 이전 작업의 완료 시점과 관계없이 첫 예약 시각에 간격의 정수 배를 더한 시각으로 고정됩니다.

다음 예제는 5분마다 증분 새로 고침을 실행하고, 변경 사항을 증분 계산할 수 없을 때 폴백을 허용합니다.

CREATE MATERIALIZED VIEW orders_by_status
BUILD IMMEDIATE
REFRESH INCREMENTAL FALLBACK ON SCHEDULE EVERY 5 MINUTE
DISTRIBUTED BY RANDOM BUCKETS 1
PROPERTIES (
"replication_num" = "1"
)
AS
SELECT
order_status,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY order_status;

예약 작업과 커밋 시 작업은 구체화된 뷰를 생성할 때 정의한 새로 고침 전략으로 실행됩니다. INCREMENTAL은 IVM만 시도하고, INCREMENTAL FALLBACK은 IVM을 먼저 시도한 후 사유에 따라 폴백하며, AUTO는 IVM, 파티션 새로 고침, 전체 새로 고침을 순서대로 시도합니다. 자동으로 트리거된 작업에는 다음 동작도 적용됩니다.

  • 첫 번째 자동 새로 고침은 기준 상태를 자체적으로 구축합니다. 구체화된 뷰의 새로 고침이 한 번도 성공하지 않았다면(예를 들어 BUILD DEFERRED로 생성한 후 아직 새로 고침하지 않은 경우), 첫 번째 예약 작업이나 커밋 시 작업이 자동으로 COMPLETE를 실행해 전체 기준 상태를 구축합니다. 수동으로 COMPLETE를 실행할 필요는 없습니다. 이후 작업부터 증분 새로 고침을 수행합니다.
  • 하나의 구체화된 뷰에 대한 새로 고침 작업은 순차적으로 실행되며, 초과 트리거는 건너뜁니다. 자동으로 트리거된 작업은 실행 중인 작업 하나와 대기 중인 작업 하나까지만 유지합니다. 간격이 단일 새로 고침 소요 시간보다 짧거나, ON COMMIT에서 기본 테이블의 커밋이 매우 자주 발생하면 새 트리거를 건너뛰고 FE 메트릭 async_materialized_view_task_skip_num이 증가합니다. 대기 중인 작업은 누적된 변경 사항을 한 번에 모두 소비하므로 변경 사항이 누락되지는 않지만, 실제 새로 고침 지연 시간은 설정한 간격보다 길어집니다. 정상 부하에서 단일 증분 새로 고침이 한 간격 내에 완료될 수 있도록 간격을 선택하세요.
  • ON COMMIT은 증분 유지 관리에 참여하는 기본 테이블에서만 트리거됩니다. excluded_trigger_tables에 포함된 테이블의 커밋은 새로 고침을 트리거하지 않습니다. excluded_trigger_tables를 참조하세요.

트리거를 변경할 때는 ON 절만 지정하고 INCREMENTAL을 다시 쓰지 마세요. IVM의 새로 고침 방식은 ALTER로 변경할 수 없으므로 ALTER MATERIALIZED VIEW ... REFRESH INCREMENTAL ...은 거부됩니다. 트리거만 변경하는 것은 허용되며, Doris는 새 트리거로 예약 작업을 다시 생성합니다.

ALTER MATERIALIZED VIEW orders_by_status REFRESH ON SCHEDULE EVERY 1 MINUTE;
ALTER MATERIALIZED VIEW orders_by_status REFRESH ON COMMIT;
ALTER MATERIALIZED VIEW orders_by_status REFRESH ON MANUAL;

수동으로 새로 고침 방식 재정의​

IVM을 생성한 후 필요에 따라 다음 중 하나를 실행할 수 있습니다.

REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL;
REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL FALLBACK;
REFRESH MATERIALIZED VIEW <mv_name> PARTITIONS;
REFRESH MATERIALIZED VIEW <mv_name> PARTITIONS FALLBACK;
REFRESH MATERIALIZED VIEW <mv_name> COMPLETE;

IVM에서는 새로 고칠 파티션의 이름을 지정하는 기존 PARTITION (<partition_name>) 또는 PARTITIONS (<partition_name>, ...) 구문을 사용할 수 없습니다. PARTITIONS 키워드로 Doris가 새로 고침이 필요한 파티션을 계산하도록 하거나, COMPLETE로 전체 데이터를 새로 고치세요.

폴백 순서​

요청에서 폴백을 허용하면 Doris는 기본적으로 다음 순서로 시도합니다.

IVM -> PARTITIONS -> COMPLETE

일부 실패는 기존 IVM 기준 상태를 더 이상 안전하게 사용할 수 없음을 의미합니다. 이 경우 Doris는 파티션 새로 고침을 건너뛰고 곧바로 COMPLETE를 실행합니다. 일반적인 사유는 다음과 같습니다.

IvmFallbackReason의미복구 방법
STREAM_UNSUPPORTED내부 Stream이 없거나 더 이상 사용할 수 없음전체 새로 고침 수행. 내부 Stream도 다시 구축하고 소비 오프셋을 다시 정렬함
MIN_MAX_BOUNDARY_HIT삭제로 인해 현재 MIN 또는 MAX가 변경될 수 있음집계 결과 전체를 다시 계산함
BITMAP_AGG_DELETE삭제가 Bitmap 집계에 영향을 줌전체 Bitmap을 다시 계산함
PLAN_SIGNATURE_MISMATCH현재 쿼리 계획이 영구 저장된 IVM 레이아웃과 일치하지 않음전체 새로 고침을 수행하고 새 기준 상태를 구축함
INCOMPLETE_REFRESH_SNAPSHOT폴백 체인에서 사용할 전체 새로 고침 스냅샷이 아직 없음전체 새로 고침으로 기준 상태를 구축함

엄격한 INCREMENTAL은 폴백하지 않습니다. 작업이 실패하면 구체화된 뷰는 새로 고침 이전의 데이터를 유지하고, 내부 Stream의 소비 오프셋도 전진하지 않습니다. 오류를 해결한 후 증분 새로 고침을 다시 실행하거나, COMPLETE를 실행해 기준 상태를 다시 구축할 수 있습니다.

첫 번째 새로 고침 및 기준 상태 재구축​

증분 새로 고침은 기준 상태 이후의 변경 사항만 처리할 수 있습니다. 기준 상태는 구체화된 뷰를 가장 최근에 전체 계산한 결과와 그에 맞춰 정렬된 내부 Stream 소비 오프셋으로 구성됩니다. Doris는 구체화된 뷰의 파티션별로 기준 상태의 유효성을 추적합니다. 기준 상태가 유효하지 않은 파티션은 전체를 다시 구축하고, 나머지 파티션은 계속 증분 새로 고침합니다.

첫 번째 새로 고침

구체화된 뷰의 새로 고침이 성공하기 전에는 어떤 파티션에도 기준 상태가 없습니다. 요청한 새로 고침 방식에 관계없이 첫 번째 새로 고침은 전체 데이터를 계산합니다.

새로 고침 요청첫 번째 새로 고침의 동작
COMPLETE전체 데이터를 완전히 새로 고침함
INCREMENTAL모든 파티션을 먼저 다시 구축한 후 델타를 처리함
INCREMENTAL FALLBACK, AUTO곧바로 COMPLETE를 실행함
예약 또는 커밋 시 트리거COMPLETE를 실행함. 자동 새로 고침 간격 설정 참조

이 작업들의 RefreshMode는 모두 COMPLETE이고, IvmFallbackReason은 비어 있습니다. 따라서 IVM을 생성한 후 별도로 COMPLETE를 실행할 필요는 없습니다. 빠른 시작에서 COMPLETE를 명시적으로 실행하는 것은 기준 상태 구축 단계를 더 명확하게 보여주기 위한 것입니다.

일부 파티션의 기준 상태 무효화

다음 기본 테이블 연산은 메타데이터만 변경하고 changelog에 변경 레코드를 기록하지 않으므로, 증분 새로 고침은 변경 사항만으로 어떤 행이 삭제되거나 교체되었는지 알 수 없습니다. 이러한 기본 테이블 파티션을 읽는 구체화된 뷰의 파티션은 다시 구축해야 합니다:

  • TRUNCATE TABLE. 일부 파티션만 비우는 경우도 포함
  • ALTER TABLE ... DROP PARTITION
  • RECOVER PARTITION
  • 기본값인 엄격한 범위 일치를 사용하는 ALTER TABLE ... REPLACE PARTITION

구체화된 뷰가 기본 테이블의 파티션 컬럼을 기준으로 파티션화되어 있으면 Doris는 영향을 받은 구체화된 뷰의 파티션만 표시합니다. 다음 새로 고침에서는 엄격한 INCREMENTAL을 포함해 이러한 파티션을 먼저 다시 구축한 후, 나머지 파티션을 증분 새로 고침합니다. IvmRebuiltPartitions 컬럼은 tasks("type"="mv")에서 해당 새로 고침이 추가로 다시 구축한 파티션 수를 기록합니다. 기본 테이블의 파티션이 삭제되면 해당 구체화된 뷰의 파티션도 파티션 동기화 중에 삭제되므로 다시 구축할 필요가 없습니다.

구체화된 뷰가 파티션화되어 있지 않거나 Doris가 영향을 받은 구체화된 뷰의 파티션을 확인할 수 없으면, 아래 설명과 같이 전체 구체화된 뷰의 기준 상태가 무효화됩니다. excluded_trigger_tables에 포함된 기본 테이블에서 이러한 연산을 수행해도 기준 상태는 무효화되지 않습니다.

전체 구체화된 뷰의 기준 상태 무효화

다음 상황에서는 전체 구체화된 뷰의 기준 상태가 무효화되고 SCHEMA_CHANGE 상태가 됩니다. 이 상태는 State 및 SchemaChangeDetail 컬럼을 통해 mv_infos에서 확인할 수 있습니다.

  • 기본 테이블에서 DROP COLUMN, MODIFY COLUMN, RENAME COLUMN, RENAME(테이블 이름 변경) 또는 REPLACE WITH TABLE을 실행한 경우. ADD COLUMN은 기준 상태를 무효화하지 않습니다. changelog가 있는 테이블에서는 MODIFY COLUMN과 RENAME COLUMN을 허용하지 않습니다. changelog DDL 제한 사항을 참조하세요.
  • 기본 테이블에서 엄격한 범위 일치 없이 REPLACE PARTITION을 실행하거나, 이전 목록의 파티션 연산을 특정 구체화된 뷰의 파티션에 대응시킬 수 없는 경우.
  • 속성 변경으로 구체화된 뷰의 유지 관리 범위가 넓어진 경우. 예를 들어 excluded_trigger_tables에서 기본 테이블을 제거하거나, ivm_partition_window_limit을 늘리거나 제거하거나, partition_sync_limit의 범위를 넓히는 경우입니다.

구체화된 뷰가 SCHEMA_CHANGE 상태이면 다음 INCREMENTAL, INCREMENTAL FALLBACK, AUTO, COMPLETE 또는 PARTITIONS FALLBACK 새로 고침은 전체 구체화된 뷰를 다시 구축하며, 성공하면 상태가 NORMAL로 돌아갑니다. PARTITIONS 새로 고침에 FALLBACK이 없으면 실패하고, 대신 COMPLETE, AUTO 또는 PARTITIONS FALLBACK을 사용하라는 메시지가 표시됩니다.

기본 테이블이 변경된 후 정의 SQL을 더 이상 분석할 수 없다면, 예를 들어 구체화된 뷰에서 사용하는 컬럼이 삭제되었다면 모든 새로 고침이 실패하므로 구체화된 뷰를 삭제하고 다시 생성해야 합니다.

내부 Stream 사용 불가

내부 Stream이 없거나 더 이상 사용할 수 없으면 INCREMENTAL FALLBACK과 AUTO는 곧바로 COMPLETE를 실행하며, IvmFallbackReason은 STREAM_UNSUPPORTED가 됩니다. COMPLETE 새로 고침은 내부 Stream을 다시 구축하고 소비 오프셋을 다시 정렬합니다. 엄격한 INCREMENTAL 새로 고침은 실패하므로 COMPLETE 또는 AUTO를 한 번 실행해야 합니다.

델타 계획 미리 보기 및 설명​

EXPLAIN으로 새로 고침 계획 확인​

다음 명령은 계획만 생성합니다. 구체화된 뷰 데이터, 내부 Stream 오프셋 또는 IVM 메타데이터는 변경하지 않습니다.

EXPLAIN REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL;

기본적으로 계획에는 현재 소비하지 않은 데이터가 있는 Stream만 포함됩니다. 델타 계획의 전체 구조를 확인하려면 다음을 사용하세요.

EXPLAIN REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL WITH ALL STREAMS;

WITH ALL STREAMS는 이미 완전히 소비한 Stream도 계획에 포함하므로, 다중 테이블 조인의 전체 증분 구조를 확인하는 데 유용합니다. 영구 저장된 상태는 변경하지 않습니다.

전체 새로 고침 계획도 확인할 수 있습니다.

EXPLAIN REFRESH MATERIALIZED VIEW <mv_name> COMPLETE;

DRY RUN으로 기록할 행 확인​

WITH DRY RUN은 다음 증분 새로 고침의 델타 쿼리를 실행하고 결과를 클라이언트에 반환합니다. 구체화된 뷰에 쓰거나 Stream 오프셋을 전진시키지는 않습니다.

REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL WITH DRY RUN;
REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL WITH DRY RUN LIMIT 100;
REFRESH MATERIALIZED VIEW <mv_name> INCREMENTAL WITH DRY RUN LIMIT 100 OFFSET 200;

결과에는 새로 고침이 실제로 기록할 행이 포함되므로, 비즈니스 컬럼 외에 IVM, Sequence, Delete Sign 컬럼과 같은 내부 컬럼도 포함됩니다. 기본 테이블 데이터가 변경되지 않는 한 반복 실행해도 같은 결과를 반환합니다.

DRY RUN은 IVM의 INCREMENTAL 새로 고침만 지원합니다. COMPLETE, EXPLAIN 또는 파티션 새로 고침과 함께 사용할 수 없습니다.

내부 Table Stream​

IVM은 내부 Table Stream의 전체 수명 주기를 자동으로 관리합니다.

  • IVM을 생성하면 증분 유지 관리에 참여하는 각 기본 테이블에 대해 내부 Stream이 생성됩니다.
  • excluded_trigger_tables를 수정하면 새 기본 테이블 집합에 따라 내부 Stream이 추가되거나 제거됩니다.
  • IVM을 삭제하면 해당 구체화된 뷰가 소유한 내부 Stream도 정리됩니다.
  • 새로 고침 중에는 기본 테이블 파티션별로 소비 오프셋을 기록하고 전진시킵니다.

mv_infos로 기본 테이블과 내부 Stream 간의 매핑을 직접 확인할 수 있습니다.

SELECT Name, IvmBaseTableStreams
FROM mv_infos("database" = "<database_name>")
WHERE Name = "<mv_name>";

Stream 상태와 파티션의 미처리 데이터양은 information_schema.table_streams 및 information_schema.table_stream_consumption에서도 확인할 수 있습니다.

내부 Stream을 수동으로 관리하지 마세요

내부 Stream은 __doris_ivm_stream_으로 시작하며 IVM 전용입니다. INSERT INTO ... SELECT로 소비하거나 수동으로 삭제하거나 다시 생성하지 마세요. Doris는 일반적인 INSERT INTO를 통한 내부 Stream 소비를 거부합니다.

Table Stream의 오프셋, 스냅샷 및 동시성 의미 체계는 Table Stream 기초 및 Table Stream 고급을 참조하세요.

IVM 속성​

먼저 행 식별자, 파티션 윈도우 및 트리거 관계를 기준으로 속성을 선택한 다음, 아래 절에서 세부 영향을 검토하세요.

속성기본값수정 가능 여부효과
ivm_use_full_keysfalse불가원본 행의 식별 키를 구체화된 뷰의 Unique Key에 추가해 해시 충돌 위험을 줄임
ivm_partition_window_limit무제한가능지정한 기본 테이블에서 파티션 값 순으로 마지막 N개 파티션만 유지 관리함
excluded_trigger_tables없음가능내부 Stream을 생성하지 않으며 자체적으로 증분 새로 고침을 트리거하지 않는 기본 테이블

ivm_use_full_keys​

ivm_use_full_keys는 구체화된 뷰의 Unique Key에 원본 행의 식별 키도 포함할지 제어합니다.

항목설명
유형Boolean
기본값false
수정 가능 여부불가. IVM 생성 시에만 설정할 수 있음
효과복합 행 식별자를 해싱할 때 해시 충돌 위험을 줄임
비용구체화된 뷰의 키 너비와 스토리지 오버헤드가 증가함
PROPERTIES (
"ivm_use_full_keys" = "true"
)

쿼리에 다중 테이블 조인, UNION ALL 또는 연쇄 IVM이 포함되고, 해당 워크로드에서 행 식별자의 해시 충돌을 피하는 것이 더 중요하다면 이 속성을 활성화하세요. 활성화하기 전에 원본 키의 유형과 전체 길이가 Doris Unique Key 제한을 충족하는지 확인하세요.

ivm_partition_window_limit​

ivm_partition_window_limit은 각 IVM 새로 고침의 대상을 지정한 기본 테이블에서 파티션 값 순으로 마지막 N개 파티션으로 제한합니다. 형식은 <table_name>:<partition_count>이며, 여러 테이블은 쉼표로 구분합니다.

PROPERTIES (
"ivm_partition_window_limit" = "orders:7,users:1"
)

이 속성은 IVM 증분 새로 고침이 읽는 파티션만 제한합니다. 구체화된 뷰의 파티션 보존 정책은 아닙니다. COMPLETE는 여전히 전체 기본 테이블을 읽고 전체 결과를 구축합니다. 윈도우에서 제외된 오래된 파티션의 변경 사항은 이후 IVM 결과에 반영되지 않습니다. 따라서 이 설정은 정보 손실이 발생하는 설정이며, 최근 파티션만 필요하다는 요구가 명확한 워크로드에만 적합합니다.

이 속성은 ALTER MATERIALIZED VIEW ... SET으로 수정할 수 있습니다. 윈도우를 넓히거나 제한을 제거하면 이전에 무시한 변경 사항을 기존 오프셋에서 복구할 수 없으므로, 구체화된 뷰의 기준 상태가 무효화되고 다음 새로 고침에서 전체 구체화된 뷰를 다시 구축합니다. 첫 번째 새로 고침 및 기준 상태 재구축을 참조하세요.

excluded_trigger_tables​

excluded_trigger_tables에 포함된 기본 테이블에는 내부 Stream이 생성되지 않으며, 해당 테이블 자체의 변경으로는 증분 새로 고침을 트리거하지 않습니다. 다른 기본 테이블의 변경으로 새로 고침이 트리거되면 Doris는 계산 중에 이러한 테이블의 현재 데이터도 읽습니다.

거의 변경되지 않는 차원 테이블이나, 다른 기본 테이블이 새로 고침을 트리거할 때까지 변경 사항 반영을 기다려도 되는 테이블만 제외하세요. 자주 변경되는 테이블을 제외하면 해당 테이블만 변경된 후에는 구체화된 뷰의 결과가 최신 상태를 반영하지 못합니다.

리소스 및 파티션 속성​

  • workload_group: 새로 고침 작업에서 사용하는 Workload Group으로, CPU 및 메모리 리소스를 제한합니다.
  • partition_sync_limit, partition_sync_time_unit: 구체화된 뷰가 보존하고 동기화하는 파티션 범위를 제어합니다. 이는 ivm_partition_window_limit의 증분 읽기 윈도우와 다릅니다.
  • refresh_partition_num: 파티션 새로 고침 및 폴백 중에 단일 INSERT가 처리하는 파티션 수를 제어합니다. IVM 델타의 행 수는 제어하지 않습니다.

구체화된 뷰의 전체 속성은 CREATE ASYNC MATERIALIZED VIEW를 참조하세요.

제한 사항 및 참고 사항​

  • IVM은 구체화된 뷰를 생성할 때만 활성화할 수 있습니다. ALTER MATERIALIZED VIEW로 일반 구체화된 뷰를 IVM으로 전환하거나 IVM의 기본 새로 고침 방식을 다른 방식으로 변경할 수 없습니다. 전환하려면 구체화된 뷰를 다시 생성하세요.
  • changelog를 활성화하면 쓰기 및 스토리지 오버헤드가 추가됩니다. Unique Key MoW 테이블은 각 업데이트 이전의 값도 읽고 저장해야 합니다. IVM이 꼭 필요한 기본 테이블에만 활성화하고, 운영 환경에 적용하기 전에 실제와 유사한 워크로드로 데이터 적재 처리량을 평가하세요.
  • IVM도 비동기 작업을 통해 새로 고침하므로 기본 테이블의 트랜잭션과 실시간 일관성을 제공하지 않습니다. 새로 고침 지연 시간은 트리거 방식, 대기 시간, 델타 계획 실행 시간에 따라 달라집니다. 최소 예약 간격은 1분입니다. 자동 새로 고침 간격 설정을 참조하세요.
  • 복잡한 중첩 외부 조인은 델타 계획을 크게 만듭니다. 특히 NULL 생성 측의 복잡한 하위 트리에서 두드러집니다. 계획 수립이나 새로 고침 비용이 지나치게 커지면 조인을 단순화하거나 복잡한 하위 트리를 먼저 하위 IVM으로 구체화하세요.
  • MIN, MAX 및 Bitmap 집계는 일부 삭제 시나리오에서 전체 재계산이 필요합니다. 운영 환경에서는 INCREMENTAL FALLBACK 또는 AUTO를 사용하고 IvmFallbackReason을 모니터링하세요.
  • changelog의 테이블 모델, 컬럼 유형, 스키마 변경 및 삭제 제한은 IVM에도 그대로 적용됩니다. changelog의 지원 범위 및 제한 사항을 참조하세요.

자주 묻는 질문​

생성에 실패하거나, 새로 고침이 폴백하거나, 데이터가 업데이트되지 않으면 아래 표에서 원인을 찾아보세요.

문제진단 및 처리 방법
CREATE MATERIALIZED VIEW ... REFRESH INCREMENTAL이 실패함FE에서 enable_feature_changelog와 enable_table_stream이 활성화되어 있는지, 기본 테이블이 테이블 모델 및 changelog 요구 사항을 충족하는지, 정의 SQL이 IVM 지원 범위에 속하는지 확인하세요
엄격한 증분 새로 고침 작업의 RefreshMode가 COMPLETE이거나 IvmRebuiltPartitions가 0보다 큼첫 번째 새로 고침 또는 무효화된 기준 상태를 자동으로 다시 구축하는 동작이며 오류가 아닙니다. 발생 조건은 첫 번째 새로 고침 및 기준 상태 재구축을 참조하세요
PARTITIONS 새로 고침에 FALLBACK이 없으면 The refresh baseline of MV ... was invalidated 오류로 실패함전체 구체화된 뷰의 기준 상태가 무효화되었습니다. 대신 COMPLETE, AUTO 또는 PARTITIONS FALLBACK으로 새로 고치세요
ON SCHEDULE EVERY 30 SECOND가 interval time unit can not be second 오류로 실패함최소 예약 간격은 EVERY 1 MINUTE이며, 단위는 MINUTE, HOUR, DAY 또는 WEEK만 사용할 수 있습니다. 더 짧은 지연 시간이 필요하면 ON COMMIT을 사용하세요. 자동 새로 고침 간격 설정을 참조하세요
예약 새로 고침의 실제 지연 시간이 설정한 간격보다 김하나의 구체화된 뷰에 대한 작업은 순차적으로 실행되며, 단일 새로 고침이 간격보다 오래 걸리면 초과 트리거를 건너뜁니다. tasks("type"="mv")에서 작업 소요 시간과 FE 메트릭 async_materialized_view_task_skip_num을 확인한 다음, 간격을 늘리거나 정의를 단순화하거나 workload_group으로 새로 고침에 더 많은 리소스를 할당하세요
새로 고침 작업이 COMPLETE로 폴백함IvmFallbackReason을 tasks("type"="mv")에서 조회하고, 폴백 순서의 사유에 따라 처리하세요
제외된 기본 테이블만 변경된 후 뷰가 업데이트되지 않음excluded_trigger_tables에 포함된 테이블은 자체적으로 새로 고침을 트리거하지 않습니다. 다른 기본 테이블이 트리거하는 새로 고침을 기다리거나 COMPLETE 새로 고침을 실행하세요. 해당 테이블을 excluded_trigger_tables에서 제거하면 다음 새로 고침에서 전체 구체화된 뷰를 다시 구축합니다
내부 Stream을 수동으로 소비하거나 초기화할 수 있나요아니요. 내부 Stream은 IVM 전용이며, Doris가 수명 주기와 소비 오프셋을 관리합니다

모범 사례​

  1. 먼저 변경된 행 수와 파티션 크기를 비교하세요. 변경 사항이 파티션에서 차지하는 비율이 작으면 IVM을 우선 고려하세요. 변경 사항이 파티션 대부분을 차지하면 PARTITIONS가 더 간단할 수 있습니다.
  2. 운영 환경에서는 안전한 폴백을 활성화하세요. INCREMENTAL FALLBACK 또는 AUTO를 사용해 삭제나 기준 상태 문제로 새로 고침이 장시간 계속 실패하는 상황을 방지하세요.
  3. 새로 고침 소요 시간을 기준으로 트리거와 간격을 선택하세요. 최소 예약 간격은 1분이며, 정상 부하에서 단일 증분 새로 고침의 소요 시간보다 간격이 길어야 합니다. 더 짧은 지연 시간이 필요하고 기본 테이블의 커밋이 지나치게 잦지 않다면 ON COMMIT을 사용하세요.
  4. 기준 상태를 먼저 확인하세요. 첫 번째 새로 고침은 전체 데이터를 계산합니다. 증분 새로 고침으로 이를 유지 관리하기 전에 결과를 검증하세요.
  5. 업데이트 및 삭제 워크로드에는 Unique Key MoW를 사용하세요. Duplicate Key 테이블은 추가만 발생하는 데이터에만 적합합니다.
  6. 새로 고침 작업의 리소스를 격리하세요. workload_group을 사용해 복잡한 델타 계획이 온라인 쿼리와 리소스를 두고 경쟁하지 않도록 하세요.
  7. 작업과 Stream의 미처리 데이터양을 모니터링하세요. tasks("type"="mv"), mv_infos, information_schema.table_stream_consumption을 함께 살펴보세요.
  8. 폴백 사유를 정기적으로 검토하세요. 간헐적인 폴백은 정확성을 보호하지만, 지속적인 폴백은 쿼리 구조, changelog 연속성 또는 기준 상태를 점검해야 한다는 신호입니다.

예제 환경 정리​

DROP MATERIALIZED VIEW orders_by_status;
DROP TABLE orders;
DROP DATABASE ivm_demo;

IVM을 삭제하면 Doris가 해당 내부 Table Stream도 정리합니다. 별도로 DROP STREAM을 실행할 필요는 없습니다.

관련 문서​