Oracle物化视图FAST REFRESH默认锁整分区表,因物化视图日志缺失分区键信息,无法定位变更分区;需同时满足日志含分区键列且MV定义显式引用该列,才能实现分区粒度加锁。
物化视图刷新时为什么锁分区表整表?
oracle 默认对分区表的物化视图执行 fast refresh 时,并不自动按分区粒度加锁,而是对基表(即分区表)整体申请 tm 锁(dml 队列锁),哪怕只刷新一个分区的数据。这是因为在传统物化视图日志(mlog$)中,变更记录不带分区键信息,oracle 无法判断哪些变更属于哪个分区,只能保守地锁全表。
常见现象包括:ORA-00054: resource busy and acquire with NOWAIT specified、应用批量 DML 被阻塞、v$lock 中看到大量 TM 锁处于 ROW EXCLUSIVE 或 SHARE 模式。
- 确认是否真为物化视图刷新导致:查
v$session的sql_id是否指向DBMS_MVIEW.REFRESH或内部刷新 SQL - 检查物化视图日志:运行
SELECT * FROM USER_MVIEW_LOGS WHERE MASTER = 'YOUR_PARTITIONED_TABLE';,若ROWID列存在但无分区键列,说明日志未覆盖分区裁剪依据 - 避免在业务高峰执行
COMPLETE REFRESH—— 它会隐式锁全表并重写整个 MV,比 FAST 更激进
如何让 FAST REFRESH 只锁变更涉及的分区?
核心是让 Oracle 在刷新时能“定位到分区”,这需要两个条件同时满足:物化视图日志包含分区键列 + 物化视图定义中显式引用该列用于分区裁剪。
假设分区表 Sales 按 sale_date 范围分区,且该列可作为刷新边界依据:
- 重建物化视图日志,显式加入分区键列:
CREATE MATERIALIZED VIEW LOG ON Sales ADD (sale_date) WITH ROWID, SEQUENCE (sale_date, amount, prod_id) INCLUDING NEW VALUES;
- 创建物化视图时,确保
sale_date出现在 SELECT 列表且未被函数包裹(如不能写TRUNC(sale_date)):CREATE MATERIALIZED VIEW mv_sales_daily BUILD IMMEDIATE REFRESH FAST ON DEMAND AS SELECT sale_date, prod_id, SUM(amount) amt FROM Sales GROUP BY sale_date, prod_id; - 刷新时指定分区范围(需配合 DBMS_MVIEW.REFRESH 接口):
EXEC DBMS_MVIEW.REFRESH('mv_sales_daily', METHOD => 'F', ROLLBACK_SEG => NULL, PUSH_DEFERRED_RPC => TRUE, REFRESH_AFTER_ERRORS => FALSE, PURGE_OPTION => 1, PARALLELISM => 0, HEAP_SIZE => 0, ATOMIC_REFRESH => FALSE);注意:仅当 MV 定义含分区键且日志同步后,Oracle 内部才会启用分区感知刷新逻辑
ATOMIC_REFRESH=FALSE 真的能减少锁吗?
能,但有前提和副作用。ATOMIC_REFRESH => FALSE 表示刷新时不走事务原子性保障,而是先 truncate MV 再 insert,跳过 MV 表上的 TM 锁升级过程。它对锁的缓解效果明显,但仅适用于允许短暂空窗期(MV 查询返回空或旧数据)的场景。
- 必须搭配
ON COMMIT或ON DEMAND刷新模式,ON STATEMENT不支持该参数 - truncate 操作本身仍需对 MV 表加
EXCLUSIVE锁,但持续时间极短(毫秒级),远低于全量 insert 的行锁累积时间 - 风险点:如果刷新中途失败,MV 处于空状态;且无法回滚,需人工干预恢复
- 验证是否生效:刷新期间查
v$locked_object,应看不到 MV 表的锁,而只有基表上针对变更分区的细粒度锁
还有哪些容易被忽略的并发瓶颈?
分区表物化视图高并发下的真实瓶颈,常不在锁本身,而在底层资源争用。
-
MLOG$表热点:所有分区的 DML 都写入同一张日志表,易成 I/O 和 buffer busy waits 源头。解决方案是为MLOG$表手动分区(如按SNAPTIME$$范围),并确保其索引也分区 - 物化视图日志序列号(
SEQUENCE$$)争用:高并发 DML 下,MLOG$的隐式 sequence 更新可能引发 enq: TX row lock contention。可考虑关闭日志的SEQUENCE(改用ROWID+ 时间戳组合判断变更顺序),但需接受部分极端时序下刷新遗漏风险 - 并行刷新反效果:对单个 MV 设置
PARALLELISM > 1,可能加剧基表分区间锁竞争(如多个并行进程试图刷新同一分区),建议优先保证单分区刷新快,再通过调度错峰调用不同分区的刷新任务
真正压测时,别只盯着锁等待事件,enq: TX - index contention、buffer busy waits、log file sync 往往才是分区 MV 并发卡点所在。


















