创建两张业务表
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 标识,> |
| 全量刷新实现 | 使用 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 变量生成序列号,快速灌入大量测试数据 |
如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得 关注不迷路 ,下次见~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3183524/ ,如需转载,请注明出处,否则将追究法律责任。