Oracle RAC中SQL调度异常和gc cr request等待的本质是执行计划与RAC架构不匹配,而非计划本身错误;根本解决需结合服务绑定、parallel_force_local参数及SQL Plan Baseline等机制实现节点级调度优化与计划稳定。
在 oracle rac 中,sql 语句被调度到非预期节点执行、出现 gc cr request 等全局缓存等待,本质不是“执行计划错”,而是执行计划与 rac 架构不匹配——尤其当并行查询被中断后残留资源未清理,或跨节点数据块争用严重时,强行固定执行计划反而会加剧问题。真正有效的优化,是让 sql 在合适节点上以合适方式执行,而非单纯“锁住计划”。
为什么 USE_NL + INDEX 提示在 RAC 下容易卡住?
你贴出的 SQL 显式用了 /*+ INDEX(MBF,IDX_MT_BIZ_FIN_DATE) USE_NL(MBF,MFF) */,这在单实例下可能高效,但在 4 节点 RAC 中极易触发 gc cr request:
-
USE_NL要求驱动表(MBF)逐行访问被驱动表(MFF),若MFF的相关数据块分散在多个节点 buffer cache 中,每次访问都需跨节点拉取 CR 块,网络延迟放大成等待 -
INDEX提示若指向的是非分区本地索引,RAC 会频繁协调索引叶块所在实例,尤其当查询条件含时间范围(如某个月份)且数据按时间分布不均时,热点块集中在某个节点,其他节点反复请求 - 并行中断后,部分实例上的临时段、PX slave 进程未完全释放,导致后续串行执行仍受残留 PX 相关 latch 或资源限制影响
用 DBMS_SQLTUNE 替代 Outline 固定计划更可靠
Outline 在 11g RAC 中已显陈旧,且依赖 use_stored_outlines 参数(12c+ 已废弃),实际中易因 category 切换失败或 session 初始化顺序问题失效。推荐用 SQL Tuning Set + SQL Plan Baseline:
- 先捕获当前卡住 SQL 的
sql_id(查v$sql或 AWR)和理想执行计划的plan_hash_value(比如在单节点上加NO_PARALLEL后跑出的稳定计划) - 用
dbms_spm.load_plans_from_cursor_cache把好计划直接绑定到该sql_id,无需修改应用,也不依赖 session 级参数 - 关键点:绑定前务必确认 baseline 的
enabled和accepted都为YES,否则优化器不会使用它 - 验证是否生效:
select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle=>'SQL_...',format=>'basic'))
强制 SQL 在指定节点执行的实操方法
RAC 不提供“把这条 SQL 永远发给 node2”的开关,但可通过服务(Service)+ 客户端连接控制实现效果:
- 创建专用服务(如
svc_monthly),用srvctl add service并指定-n node2作为首选实例,-i node2作为可用实例(避免 failover 到其它节点) - 应用连接字符串中显式指定该服务名,例如 JDBC URL 中加
service_name=svc_monthly - 配合
ALTER SYSTEM SET parallel_force_local=TRUE(仅限 11.2.0.4+),可阻止并行操作跨节点分发,这对你的月度数据转换脚本很关键 - 注意:不能靠
ALTER SESSION SET INSTANCE=node2—— 这个命令不存在;也不能靠INSTANCE_NAME连接参数,它只影响客户端解析,不改变路由逻辑
真正难处理的,是那些已经嵌在 ETL 工具或报表平台里的硬编码 SQL —— 它们连改 hint 都做不到。这时候,服务绑定 + parallel_force_local 是唯一能绕过代码改动的路径。而所有 baseline 或 profile 绑定,都必须在 SQL 文本完全一致的前提下才生效,空格、注释、大小写差异都会导致匹配失败。











