联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
创建两张业务表 orders(订单表)和 items(商品维度表),构成经典的订单-商品关联模型:
-- 订单表(50000+ 行)
CREATE TABLE orders (
order_id BIGINT PRIMARY KEY,
item_id BIGINT NOT NULL,
price DECIMAL(10,2),
amount DECIMAL(12,2),
order_date DATE,
region VARCHAR(50)
);
-- 商品维度表(3 行)
CREATE TABLE items (
item_id BIGINT PRIMARY KEY,
item_name VARCHAR(200),
category VARCHAR(100),
price DECIMAL(10,2)
);
为两张基表分别创建 MLOG,关键参数:
WITH PRIMARY KEY, ROWID, SEQUENCE (...) — 记录主键、行ID、序列号及指定列的变更INCLUDING NEW VALUES — 支持增量刷新时记录新值CREATE MATERIALIZED VIEW LOG ON orders
WITH PRIMARY KEY, ROWID, SEQUENCE (item_id, amount, order_date, region)
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON items
WITH PRIMARY KEY, ROWID, SEQUENCE (item_name, category, price)
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW mv_orders_items
REFRESH FAST ON DEMAND
START WITH NOW() NEXT NOW() + INTERVAL 1 MINUTE
AS
SELECT
o.order_id, o.item_id, o.order_date, o.region,
i.item_name, i.category, i.price, o.amount,
COUNT(*) AS cnt
FROM orders o
JOIN items i ON o.item_id = i.item_id
GROUP BY o.order_id, o.item_id, o.order_date, o.region,
i.item_name, i.category, i.price, o.amount;
关键语法解读:
REFRESH FAST — 增量刷新(仅应用 MLOG 中的变更)ON DEMAND — 按需刷新(由调度 JOB 触发,非自动提交时刷新)START WITH NOW() NEXT NOW() + INTERVAL 1 MINUTE — 立即开始,每分钟调度一次SELECT mview_name, owner, rewrite_enabled, refresh_mode, refresh_method,
last_refresh_type, last_refresh_date, staleness
FROM oceanbase.dba_mviews
WHERE mview_name = 'MV_ORDERS_ITEMS';
输出结果:
| 字段 | 值 | 含义 |
|---|---|---|
| mview_name | mv_orders_items | 物化视图名 |
| owner | jhd_test | 所属租户 |
| rewrite_enabled | N | 未启用查询重写 |
| refresh_mode | DEMAND | 按需刷新模式 |
| refresh_method | FAST | 增量刷新方式 |
| last_refresh_type | FAST | 最后一次刷新类型为增量 |
| last_refresh_date | 2026-07-10 11:23:50 | 最后刷新时间 |
| staleness | NULL | 无过期标记(数据是新鲜的) |
SELECT run_owner, mviews, refresh_id, method, num_mvs,
start_time, end_time, elapsed_time, parallelism,
number_of_failures, complete_stats_available
FROM oceanbase.dba_mvref_run_stats
WHERE mviews LIKE '%MV_ORDERS_ITEMS%'
ORDER BY start_time DESC;
输出结果(6 次连续自动刷新记录):
| refresh_id | method | parallelism | elapsed_time | start_time | failures | stats_ok |
|---|---|---|---|---|---|---|
| 749639 | NULL | 4 | 0 | 11:26:50 | 0 | Y |
| 749383 | NULL | 4 | 0 | 11:25:50 | 0 | Y |
| 749191 | NULL | 4 | 0 | 11:24:50 | 0 | Y |
| 748997 | NULL | 4 | 0 | 11:23:50 | 0 | Y |
| 748808 | NULL | 4 | 0 | 11:22:50 | 0 | Y |
| 748620 | NULL | 4 | 0 | 11:21:51 | 0 | Y |
关键发现:
SELECT mview_owner, mview_name, dep_owner, dep_name, dep_type
FROM oceanbase.dba_mview_deps
WHERE mview_name = 'mv_orders_items';
| mview_name | dep_name | dep_type |
|---|---|---|
| mv_orders_items | items | TABLE |
| mv_orders_items | orders | TABLE |
SELECT svr_ip, svr_port, table_name, job_type, session_id,
parallel, job_start_time, read_snapshot
FROM oceanbase.dba_mview_running_jobs
WHERE table_name = 'mv_orders_items';
-- Empty set(当前无正在运行的刷新任务)
SELECT owner, job_name, job_type, job_action,
repeat_interval, next_run_date, last_start_date,
state, enabled
FROM oceanbase.dba_scheduler_jobs
WHERE job_action LIKE '%mv_orders_items%';
| 字段 | 值 |
|---|---|
| job_name | MVIEW_REFRESH$J_1125899907591046 |
| job_type | PLSQL_BLOCK |
| job_action | DBMS_MVIEW.refresh('jhd_test.mv_orders_items',nested=>FALSE) |
| repeat_interval | NOW() + INTERVAL 1 MINUTE |
| state | SCHEDULED |
| enabled | 1 |
关键发现:
MVIEW_REFRESH$J_
nested=>FALSE 表示不级联刷新依赖的物化视图-- 查看默认值
SHOW VARIABLES LIKE "mview_refresh_dop";
-- 默认值 = 4
-- 设置当前会话并行度
SET mview_refresh_dop = 16;
-- 手动刷新
CALL dbms_mview.refresh('mv_orders_items', 'f'); -- 增量
CALL dbms_mview.refresh('mv_orders_items', 'c'); -- 全量
验证结果(从 dba_mvref_run_stats 提取):
| method | parallelism | elapsed_time | 说明 |
|---|---|---|---|
| c | 16 | 2 | 全量刷新,并行度 16 生效 |
| f | 16 | 0 | 增量刷新,并行度 16 生效 |
| NULL | 4 | 0 | 自动调度刷新,仍用默认并行度 4 |
结论: mview_refresh_dop 仅对手动调用 DBMS_MVIEW.REFRESH 生效,不影响自动调度任务。
CALL dbms_mview.refresh('mv_orders_items', 'f', refresh_parallel => 16);
CALL dbms_mview.refresh('mv_orders_items', 'c', refresh_parallel => 16);
验证结果:
| method | parallelism | elapsed_time |
|---|---|---|
| c | 16 | 1 |
| f | 16 | 0 |
结论: 显式指定参数优先级最高,效果与方法 1 一致。
ALTER MATERIALIZED VIEW mv_orders_items PARALLEL 16;
CALL dbms_mview.refresh('mv_orders_items', 'f');
CALL dbms_mview.refresh('mv_orders_items', 'c');
验证结果(关键对比数据):
| method | parallelism | 触发方式 | 说明 |
|---|---|---|---|
| f | 4 | 手动 CALL | MV 的 PARALLEL 属性未生效,仍用默认 4 |
| NULL | 16 | 自动调度 | 自动任务使用了 MV 的 PARALLEL 16 |
| c | 4 | 手动 CALL | MV 的 PARALLEL 属性未生效 |
重要结论:
ALTER MATERIALIZED VIEW ... PARALLEL N 设置的并行度只对自动调度任务生效并行度优先级总结:
| 优先级 | 控制方式 | 手动刷新 | 自动调度 |
|---|---|---|---|
| 最高 | refresh_parallel => N | 生效 | — |
| 中 | SET mview_refresh_dop = N | 生效 | — |
| 低 | ALTER MV ... PARALLEL N | 不生效 | 生效 |
| 默认 | mview_refresh_dop(默认 4) | 生效 | 生效 |
-- 维度表:3 行
INSERT INTO items VALUES (1, '笔记本电脑', '电子产品', 5999.00);
INSERT INTO items VALUES (2, '办公桌', '家具', 1500.00);
INSERT INTO items VALUES (3, '咖啡机', '家电', 899.00);
COMMIT;
-- 订单表:50000 行(利用 information_schema.tables 笛卡尔积生成序列号)
INSERT INTO orders
SELECT seq, MOD(seq, 3) + 1, ROUND(RAND() * 5000, 2),
DATE_ADD('2026-06-01', INTERVAL MOD(seq, 30) DAY),
CASE MOD(seq, 3) WHEN 0 THEN 'SH' WHEN 1 THEN 'BJ' ELSE 'GZ' END
FROM (
SELECT @rownum := @rownum + 1 AS seq
FROM information_schema.tables a, information_schema.tables b,
(SELECT @rownum := 0) r
LIMIT 50000
) t;
SELECT refresh_id, mv_name, tbl_owner, tbl_name,
num_rows_ins, num_rows_upd, num_rows_del, num_rows
FROM oceanbase.dba_mvref_change_stats
WHERE mv_name = 'mv_orders_items'
ORDER BY refresh_id DESC LIMIT 30;
关键输出(数据灌入后的刷新记录):
| refresh_id | tbl_name | num_rows_ins | num_rows_upd | num_rows_del | num_rows |
|---|---|---|---|---|---|
| 792325 | orders | 50000 | 0 | 0 | 0 |
| 792325 | items | 3 | 0 | 0 | 0 |
| 792129 | orders | 0 | 0 | 0 | 0 |
| 792129 | items | 0 | 0 | 0 | 0 |
关键发现:
SELECT r.refresh_id, r.run_owner, r.mviews, r.method,
r.start_time, r.end_time, r.elapsed_time, r.parallelism,
c.tbl_name, c.num_rows_ins, c.num_rows_upd,
c.num_rows_del, c.num_rows
FROM oceanbase.dba_mvref_run_stats r
LEFT JOIN oceanbase.dba_mvref_change_stats c
ON r.refresh_id = c.refresh_id
WHERE r.mviews LIKE '%MV_ORDERS_ITEMS%'
ORDER BY r.start_time DESC LIMIT 30;
此查询将刷新运行统计与基表数据变化量关联,可一次性看到:某次刷新的耗时、并行度、以及各基表的 INSERT/UPDATE/DELETE 行数。
ALTER TABLE orders MODIFY amount DECIMAL(12,2);
-- ERROR 1235 (0A000): modify column to table with materialized view log is not supported
原因: 基表存在 MLOG,OceanBase 不允许直接修改有 MLOG 依赖的表的列定义。
CALL DBMS_SCHEDULER.DISABLE('MVIEW_REFRESH$J_xxx');
DROP MATERIALIZED VIEW LOG ON orders; / DROP MATERIALIZED VIEW LOG ON items;
ALTER TABLE orders MODIFY amount DECIMAL(14,2);
CREATE MATERIALIZED VIEW LOG ON orders WITH PRIMARY KEY, ROWID, SEQUENCE (...) INCLUDING NEW VALUES;
CALL DBMS_MVIEW.REFRESH('mv_orders_items', 'C');(MLOG 重建后丢失增量记录,必须全量刷新)CALL DBMS_SCHEDULER.ENABLE('MVIEW_REFRESH$J_xxx');
SHOW PARAMETERS LIKE 'enable_mlog_auto_maintenance';
| 字段 | 值 |
|---|---|
| name | enable_mlog_auto_maintenance |
| value | True |
| default_value | False |
| scope | TENANT |
| edit_level | DYNAMIC_EFFECTIVE |
| info | Switch of MLOG automated maintenance |
关键发现: 开启 enable_mlog_auto_maintenance = True 后,创建增量刷新物化视图时不需要手动创建 MLOG,系统会自动管理 MLOG 的创建和维护。
-- 直接创建物化视图(不手动建 MLOG)
CREATE MATERIALIZED VIEW mv_orders_items
REFRESH FAST ON DEMAND
START WITH NOW() NEXT NOW() + INTERVAL 1 MINUTE
ENABLE QUERY REWRITE
AS SELECT ... FROM orders o JOIN items i ON ...;
-- 成功创建,无需预先 CREATE MATERIALIZED VIEW LOG
对比:
CREATE MATERIALIZED VIEW mv_orders_items_rt
REFRESH FAST ON DEMAND
ENABLE ON QUERY COMPUTATION -- 关键:启用实时查询计算
AS SELECT ... FROM orders o JOIN items i ON ...;
SELECT mview_name, refresh_method, rewrite_enabled,
on_query_computation, refresh_dop, staleness
FROM oceanbase.dba_mviews
WHERE mview_name IN ('mv_orders_items', 'mv_orders_items_rt');
| 字段 | mv_orders_items(普通) | mv_orders_items_rt(实时) |
|---|---|---|
| refresh_method | FAST | FAST |
| rewrite_enabled | N | N |
| on_query_computation | N | Y |
| refresh_dop | 16 | 0 |
| staleness | NULL | NULL |
关键差异:
-- 灌入数据后查看 MLOG
SELECT COUNT(*) FROM mlog$_orders; -- 50000 行
SELECT COUNT(*) FROM mlog$_items; -- 3 行
-- 手动触发增量刷新
CALL DBMS_MVIEW.REFRESH('mv_orders_items', 'F'); -- 1.595s
-- 立即查看 MLOG(刷新后)
SELECT COUNT(*) FROM mlog$_orders; -- 仍然 50000 行!
SELECT COUNT(*) FROM mlog$_items; -- 仍然 3 行!
关键发现: 增量刷新完成后,MLOG 数据没有立即被清理。
-- 过一段时间后再查
SELECT COUNT(*) FROM mlog$_orders; -- 0 行(已清理)
SELECT COUNT(*) FROM mlog$_items; -- 0 行(已清理)
结论: MLOG 的清理是异步延迟的,不在刷新事务内同步完成。刷新完成后,系统会在后台异步清理已消费的 MLOG 记录。
SELECT mv_owner, refresh_id, mv_name, tbl_name,
num_rows_ins, num_rows_upd, num_rows_del, num_rows
FROM oceanbase.dba_mvref_change_stats
WHERE mv_name = 'mv_orders_items'
ORDER BY refresh_id DESC;
关键记录对比:
| refresh_id | tbl_name | num_rows_ins | num_rows | 说明 |
|---|---|---|---|---|
| 298329 | orders | 0 | 50000 | MLOG 未清理时刷新,ins=0 但 num_rows=50000 |
| 298329 | items | 0 | 3 | 同上 |
| 297814 | orders | 50000 | 50000 | MLOG 有数据时刷新,ins=50000 |
| 297814 | items | 3 | 3 | 同上 |
| 297564 | orders | 0 | 0 | 无变更的空刷新 |
分析:
CALL DBMS_MVIEW.REFRESH('mv_orders_items', 'C');
SELECT last_trace_id();
-- YB42C0A8055F-0006559633DE7958-0-0
[17:15:53.583] mview complete refresh success(arg={
tenant_id:1014, table_id:500044, parallelism:4,
last_refresh_scn:1783761310230412000,
target_data_sync_scn:1783761352019617000,
use_direct_load_for_complete_refresh:true,
direct_dep_cnt:2,
select_sql:"select ... from (orders as of snapshot ... join items as of snapshot ...)"
}, res={task_id:305871, trace_id:YB42C0A8055F-0006559633DE7958-0-0})
[17:15:53.583] mview refresh finish(ret=0, ret="OB_SUCCESS", param_={
tenant_id:1014, mview_id:500044, refresh_id:305861,
refresh_method:1, retry_id:0, parallel:0,
target_data_sync_scn:1783761352019617000
})
日志字段解读:
| 字段 | 值 | 含义 |
|---|---|---|
| tenant_id | 1014 | 租户 ID |
| table_id / mview_id | 500044 | 物化视图内部 ID |
| parallelism | 4 | 使用的并行度 |
| last_refresh_scn | 1783761310230412000 | 上次刷新的 SCN |
| target_data_sync_scn | 1783761352019617000 | 本次数据同步到的 SCN |
| use_direct_load_for_complete_refresh | true | 全量刷新使用了旁路导入(direct load) |
| direct_dep_cnt | 2 | 直接依赖的基表数量(orders + items) |
| refresh_method | 1 | 1 = COMPLETE(全量) |
| ret | OB_SUCCESS | 刷新成功 |
关键发现:
SELECT * FROM oceanbase.DBA_MVREF_STATS WHERE refresh_id=305861;
| 字段 | 值 |
|---|---|
| REFRESH_METHOD | COMPLETE |
| START_TIME | 2026-07-11 17:15:52 |
| END_TIME | 2026-07-11 17:15:54 |
| ELAPSED_TIME | 1520386(微秒,约 1.52 秒) |
| LOG_SETUP_TIME | 0 |
| LOG_PURGE_TIME | NULL |
| RESULT | 0(成功) |
| SVR_IP | 192.168.5.95 |
| 维度 | 知识点 |
|---|---|
| MLOG 作用 | 记录基表数据变更(INSERT/UPDATE/DELETE),是增量刷新(FAST)的数据来源 |
| MLOG 清理机制 | 增量刷新后 MLOG 不会立即清理,系统异步延迟清理已消费的 MLOG 记录 |
| 并行度控制 | 三级优先级:refresh_parallel 参数 > mview_refresh_dop 变量 > MV PARALLEL 属性;其中 MV PARALLEL 仅对自动调度生效 |
| DDL 变更限制 | 有 MLOG 的基表不能直接修改列定义,需按"停调度 → 删MLOG → 改列 → 建MLOG → 全量刷新 → 恢复调度"流程处理 |
| enable_mlog_auto_maintenance | 开启后无需手动创建 MLOG,系统自动管理,简化了增量刷新 MV 的创建流程 |
| 实时物化视图 | ENABLE ON QUERY COMPUTATION 标识,on_query_computation=Y,refresh_dop=0(系统管理),查询时实时计算增量 |
| 全量刷新实现 | 使用 as of snapshot 读一致性快照 + direct load(旁路导入)提升性能 |
| 诊断视图体系 | dba_mviews(基本信息)、dba_mvref_run_stats(刷新统计)、dba_mvref_change_stats(数据变化量)、dba_mview_deps(依赖)、dba_mview_running_jobs(运行中任务)、dba_scheduler_jobs(调度JOB) |
| observer.log 诊断 | 通过 trace_id 串联刷新链路;关注 use_direct_load、parallelism、target_data_sync_scn 等关键字段 |
| 数据灌入技巧 | 利用 information_schema.tables 笛卡尔积 + @rownum 变量生成序列号,快速灌入大量测试数据 |