
以下是关于 Oracle RAC 中 gc cr multi block request 等待事件的全面解析,涵盖其机制、触发场景、根因及系统化排查流程:
⚙️ 一、等待事件定义与核心机制
定义:当实例需要从远程节点**一次性请求多个连续的数据块(CR模式)**时产生的等待。这是全表扫描/索引快速全扫描在 RAC 环境中的关键等待事件。
关键特征:
- 批量请求:单次请求多个连续块(数量由
DB_FILE_MULTIBLOCK_READ_COUNT决定) - CR模式:请求一致性读版本(Consistent Read)
- 与物理I/O关联:常伴随
db file scattered read等待
工作流程:
- 扫描启动:实例A执行全表扫描,发现起始块不在本地缓存
- 批量请求:向主节点请求一组连续块(如块 100-115)
- 数据传输:
- 若所有块都在实例B缓存:实例B打包发送
- 若分散在多节点:主节点协调多节点发送
- 等待结束:实例A收到所有块后继续扫描
⚠️ 二、典型触发场景
| 场景类型 | 具体表现 | 关联事件 |
|---|---|---|
| 大规模全表扫描 | 报表查询、数据仓库 ETL 作业 | db file scattered read |
| 索引快速全扫描 | 大索引范围扫描 | gc current multi block request |
| 高并发扫描 | 多会话并发访问同一大表 | gc buffer busy |
| 缓存失效 | 实例重启后首次访问历史分区 | gc cr grant 2-way |
🔍 三、根本原因分类
1. 跨节点扫描问题(~45%案例)
- 非亲和性设计:表未分区或分区策略与实例访问模式不匹配
- 冗余缓存:相同数据块在多个实例缓存(
gv$bh显示重复缓存)
2. 网络传输瓶颈(~30%)
- UDP 缓冲区不足:
netstat -su显示packet receive errors - MTU 不匹配:私有网络未启用 Jumbo Frames(MTU<9000)
- 带宽饱和:千兆网络扫描 TB 级表
3. 参数配置不当(~15%)
DB_FILE_MULTIBLOCK_READ_COUNT过大(超过网络承载能力)_gc_affinity_time过短导致亲和性失效_gc_policy_minimum未启用本地缓存优化
4. 对象设计缺陷(~10%)
- 高 PCTFREE 导致块稀疏(需更多请求覆盖相同数据量)
- 链式行(Row Chaining)增加块请求数
🧩 四、详细排查流程
1. 定位问题对象与会话
- ASH 实时分析:
SELECT sql_id, object_id, current_file#, current_block#, COUNT(*) FROM gv$active_session_history WHERE event = 'gc cr multi block request' GROUP BY sql_id, object_id, current_file#, current_block# ORDER BY COUNT(*) DESC; - 对象识别:
SELECT owner, segment_name, segment_type FROM dba_extents WHERE file_id = &file_id AND &block_id BETWEEN block_id AND block_id + blocks - 1;
2. 扫描模式诊断
- 执行计划检查:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id')); -- 关注 TABLE ACCESS FULL 或 INDEX FAST FULL SCAN - 缓存分布分析:
SELECT inst_id, COUNT(*) blocks_cached FROM gv$bh WHERE objd = (SELECT data_object_id FROM dba_objects WHERE object_name = '&TABLE_NAME') GROUP BY inst_id; -- 理想状态:数据集中在访问实例
3. 网络性能验证
- UDP 错误检测(Linux):
watch -n 1 'netstat -su | grep -E "receive errors|packets dropped"' - MTU 一致性检查:
# 所有节点执行: ping -c 3 -M do -s 8972 <peer_node_IP> # MTU=9000 时测试 - 带宽压力测试:
# 使用 iperf3 测试节点间带宽 iperf3 -s # 在目标节点 iperf3 -c <target_IP> -t 30 -P 4 # 在源节点
4. 参数有效性评估
-- 关键参数检查
SELECT name, value
FROM v$parameter
WHERE name IN ('db_file_multiblock_read_count', '_gc_affinity_time', '_gc_policy_minimum');
-- 多块读实际值验证(可能被隐含参数限制)
SELECT ksppinm, ksppstvl
FROM x$ksppi x, x$ksppcv y
WHERE x.indx = y.indx
AND ksppinm LIKE '%_db_file_optimizer_read_count%';
🛠️ 五、优化解决方案
1. 减少跨节点请求
- 分区亲和性设置(12c+):
ALTER TABLE sales MODIFY PARTITION sales_q1_2023 AFFINITY 'rac1' SERVICE 'svc_rac1'; - 服务导向路由:
EXEC DBMS_SERVICE.MODIFY_SERVICE('report_svc', PREFERRED_INSTANCES => 'rac1');
2. 网络层调优
- Jumbo Frames 配置:
# Linux 永久生效 echo "MTU=9000" >> /etc/sysconfig/network-scripts/ifcfg-eth1 sysctl -w net.ipv4.ipfrag_high_thresh=41943040 - UDP 缓冲区优化:
sysctl -w net.core.rmem_max=20971520 sysctl -w net.core.wmem_max=20971520
3. 参数智能调整
-- 动态调整多块读(根据网络负载)
ALTER SYSTEM SET db_file_multiblock_read_count =
CASE WHEN TO_CHAR(SYSDATE, 'HH24') BETWEEN 22 AND 6 THEN 32 ELSE 16 END;
-- 启用缓存亲和性
ALTER SYSTEM SET "_gc_policy_minimum"=1500 SCOPE=SPFILE; -- 最小访问次数阈值
4. 对象级优化
- 块密度提升:
ALTER TABLE orders MOVE PCTFREE 5; -- 降低空闲空间 - 消除行迁移:
ALTER TABLE customers ENABLE ROW MOVEMENT; ALTER TABLE customers SHRINK SPACE CASCADE;
5. 备选架构方案
-- 使用物化视图本地化数据
CREATE MATERIALIZED VIEW sales_mv
REFRESH FAST ON DEMAND
AS SELECT * FROM sales@prod_db
WHERE region = 'EAST'; -- 区域数据本地化
-- 内存列式存储(12c+)
ALTER TABLE sales INMEMORY PRIORITY HIGH;
💎 六、典型案例
案例1:MTU 不匹配导致扫描性能骤降
现象:迁移到新机房后,全表扫描耗时从 5 分钟增至 45 分钟。
根因:新交换机 MTU=1500,而 RAC 配置 MTU=9000。
解决:
# 统一配置 MTU
switch(config)# interface GigabitEthernet0/1
switch(config-if)# mtu 9000
案例2:多块读参数引发 UDP 碎片丢失
现象:DB_FILE_MULTIBLOCK_READ_COUNT=128 时 AWR 显示 gc lost blocks 激增。
计算:128 块 * 16KB = 2MB > 默认 UDP 缓冲区(256KB)
解决:
ALTER SYSTEM SET db_file_multiblock_read_count=32; -- 512KB/请求
ALTER SYSTEM SET "_serial_direct_read"=AUTO; -- 启用直接读绕过缓存
📊 优化效果评估指标
- AWR 关键对比:
Global Cache Efficiency %> 98%Avg global cache cr block receive time< 1ms
- 网络健康指标:
netstat -su中packet receive errors = 0ifconfig中RX errors/TX errors无增长
⚠️ 终极建议:对 TB 级表优先考虑 分区本地化 + 直接路径读 组合方案,彻底避免 Cache Fusion 开销:
SELECT /*+ PARALLEL(8) FULL(t) */ * FROM big_table t PARTITION (p_current); -- 限制在亲和分区
欢迎关注我的公众号《IT小Chen》
565

被折叠的 条评论
为什么被折叠?



