是,数据倾斜很可能是导致物化视图刷新时出现 ORA-12801/ORA-00600 的原因,尤其在基表 GROUP BY 字段分布不均且启用并行时,易引发并行进程负载失衡、超时或内存溢出。
物化视图刷新时出现 ORA-12801 / ORA-00600,是不是数据倾斜导致的?
很可能是。当物化视图基表按 group by 字段(如 region_id)存在严重分布不均(例如 1% 的分区占 70% 数据),且刷新使用并行(parallel)时,oracle 并行服务器进程会按数据块或键值范围静态划分工作,容易造成某些 slave 进程负载远高于其他进程,触发超时、内存溢出或内部错误。这不是必然报错,但 ora-12801: error signaled in parallel query server 后跟 ora-00600 或长时间卡在 px server wait 等待事件,是典型信号。
如何确认物化视图刷新是否存在数据倾斜?
别只看执行计划——要查实际运行时各并行进程的处理量:
- 刷新前开启 SQL 跟踪:
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8'; - 执行刷新(如
DBMS_MVIEW.REFRESH),完成后用tkprof解析 trace 文件,关注PX Server行的rows列,差异 >5 倍即属明显倾斜 - 更轻量方法:刷新过程中查
V$PQ_TQSTAT(需有SELECT_CATALOG_ROLE):SELECT dfo_number, tq_id, server_type, num_rows, elapsed_time FROM V$PQ_TQSTAT WHERE dfo_number = (SELECT MAX(dfo_number) FROM V$PQ_TQSTAT) ORDER BY tq_id, server_type;
观察同一tq_id下不同server_type的num_rows是否悬殊
调整分布策略:用 HASH 分区替代 RANGE/ LIST,但必须配合刷新方式
物化视图本身不支持直接指定分区方式,但可通过「基表预分区 + 刷新 hint」间接控制数据分布:
- 若基表已按倾斜字段(如
user_id)做HASH分区(至少 16 个分区),刷新时加 hint 强制走分区裁剪:/*+ USE_HASH(mv) PARALLEL(mv, 8) */,比默认的RANGE分发更均衡 - 避免在
CREATE MATERIALIZED VIEW语句中写GROUP BY倾斜字段(如GROUP BY country_code),改用子查询预聚合再 join,把倾斜点前置到可调优的中间步骤 -
DBMS_MVIEW.REFRESH的method参数影响很大:用'C'(complete)时 Oracle 可能重用并行计划;用'F'(fast)时若日志缺失或物化视图定义含复杂表达式,会退化为 serial,反而掩盖问题——先确保能跑通'C'模式再调优
并行度不是越高越好:设置 parallel_degree_limit 和绑定 hint
盲目设 ALTER SESSION SET PARALLEL_DEGREE_LIMIT = CPU 常加剧争抢。真实有效的做法是:
- 查当前系统可用并行槽位:
SELECT value FROM v$parameter WHERE name = 'parallel_servers_target';,设parallel_degree_limit不超过该值的 70% - 在刷新 SQL 中显式指定并行度,而非依赖系统参数:
/*+ PARALLEL(4) */—— 4 是常见起点,再根据V$PQ_TQSTAT结果逐步试 6→8→12,每次增 2,避免跳变 - 禁用自动并行(
ALTER SESSION DISABLE PARALLEL DML;)后再执行刷新,防止 DML 阶段意外启用并行导致资源冲突
数据倾斜本质是业务分布问题,技术手段只能缓解。最易被忽略的是:物化视图日志(MLOG$)本身若未分区,其 SNAPTIME$$ 字段更新会形成热点,导致 fast refresh 卡在日志扫描阶段——这时调并行度毫无意义,得先给日志表加 HASH 分区。


















