注册
hint注入和持久化绑定计划
专栏/技术分享/ 文章详情 /

hint注入和持久化绑定计划

wuran 2025/08/29 14 0 0
摘要

一、 区别

1、 hint注入

Hint注入是通过系统函数为SQL语句动态添加优化器指令的技术。通过SQL注释语法(/+ ... /)向优化器传递指令,干预其生成执行计划的决策过程(如强制索引、连接顺序)。通过系统函数 sf_inject_hint 创建全局规则,将HINT指令与特定SQL绑定,无需修改原SQL文本即可干预优化器行为。规则存储在系统视图 SYSINJECTHINT 中,由数据库自动匹配应用。通过参数ENABLE_INJECT_HINT=1全局开启Hint注入。
核心特点:
1)无需修改SQL文本。
2)DDL变更导致失效,表结构变更(如删除索引)后,强制索引的HINT会报错。
3)修改规则后,SQL仍使用旧执行计划,需手动清理计划缓存。
4)支持按SQL文本绑定和按HASH_VALUE绑定。

2、持久化绑定计划

持久化绑定计划指将已生成的执行计划持久化存储至系统表(SYSPLNINFO)中,确保数据库重启后仍可加载使用,从而避免执行计划因环境变化(如迁移、升级)而失效,保障性能稳定性。数据库重启后通过参数LOAD_BINDED_PLN=1自动加载,确保计划跨会话、跨重启的稳定性。
核心特点:
1)固化现有计划:跳过优化器阶段:直接复用存储的计划,避免因统计信息更新、索引变更等导致执行计划变动。
2)持久化存储:计划存入系统表,不受重启影响。
3)表结构变更(如删列、改类型)会导致绑定计划自动失效。
4)支持按SQL文本绑定和按HASH_VALUE绑定。
5)分为内存绑定与持久化绑定
绑定状态标识:在动态视图 V$CACHEPLN 中通过 BINDED 字段区分绑定类型:
'N':未绑定
'M':内存绑定(重启失效)
'P':持久化绑定
'B':内存绑定与持久化绑定同时生效。

二、适用场景

1、hint注入

1)紧急性能问题修复:当关键SQL因优化器缺陷(如错误选择索引或连接方式)导致性能骤降时,通过Hint注入强制指定执行路径。无需重启应用或修改SQL文本,实时生效。
2)规避全局参数风险:需调整优化器参数(如OPTIMIZER_OR_NBEXP),但全局修改会影响其他业务SQL。会话级或SQL级精准控制,避免全局参数副作用。
3)解决统计信息失真问题:统计信息未及时更新或采样率不足导致计划劣化(如全表扫描替代索引扫描)。

2、持久化绑定计划

1)核心交易系统性能保障:高频交易类SQL(如支付、清算)需绝对稳定的执行计划,避免因统计信息更新、索引变更等导致计划突变引发性能抖动。计划存入系统表 SYSPLNINFO,重启后通过 LOAD_BINDED_PLN=1 自动加载,彻底规避计划漂移风险。
2)统计信息采集不及时或采样率不足时,优化器可能生成劣质计划(如全表扫描替代索引扫描)。在统计信息准确时绑定最优计划,后续统计信息更新不会触发计划重生成。
3)数据库迁移/升级场景:跨版本升级或异构迁移(如Oracle→达梦)时,需保持原执行计划一致性,避免因优化器差异导致性能回退。

三、操作步骤

1、hint注入

1)根据sql模糊匹配

可通过SYSINJECTHINT视图查看已指定的SQL语句和对应的HINT。
select * from SYSINJECTHINT ;
如需修改注入的sql信息,可先删除INJECT,再重新创建,例:
SF_DEINJECT_HINT函数可以将设置INJECT hint删除。
sf_deinject_hint('TESTJOIN',false);
添加INJECT语法:
sf_inject_hint(
sql_text => ' select * from v$sessions a ,v$session_stat b where a.sess_id=b.sessid;',
hint_text =>'use_nl(a,b)',
name =>'TESTJOIN',
description => 'this is a test join hint.',
validate => true,
fuzzy => true,    --模糊匹配
need_clear=>false    --不清空全库执行计划
);
select * from V$INJECT_HINT_INFO;--检查是否命中了hint

2)根据sql_text_id绑定

--查询sql_text_id
SELECT SQL_TEXT_ID,SQL_TEXT FROM SYS.V$SQLTEXT WHERE SQL_TEXT LIKE '%where a.sess_id=b.sessid%';  
--清除之前的hint注入
SF_DEINJECT_HINT('DAMENG_HINT_T_D_MP_SEC_MKT');
--使用sql_text_id进行hint注入
SF_INJECT_HINT('fvj4mncrsrkec','INDEX(T_D_MP_SEC_MKT,IDX_D_MP_SEC_MKT2)','DAMENG_HINT_T_D_MP_SEC_MKT','',TRUE,2);
--sql_text:待注入 HINT 规则的 SQL 语句。fuzzy 参数类型为 INT 时,值为 2 表示支持通过 sql_text_id 指定待注入的 SQL 语句,sql_text_id 字段可通过 V$SQLTEXT 视图进行查询
--validate:HINT 规则是否生效。TRUE 是;FALSE 否

2、持久化绑定计划

1)清空执行计划缓存

sp_clear_plan_cache();

2)执行sql生成新的待绑定的执行计划

select /*+use_nl(a,b)*/ * from v$sessions a ,v$session_stat b where a.sess_id=b.sessid;

3)持久化绑定

SP_SET_PLN_BINDED(983397999,'SYSDBA', 'SQL', 2);
说明: 
SP_SET_PLN_BINDED(
	sql_text    VARCHAR(32767),   -- SQL语句文本(需完整匹配)或 SQL哈希值(从 `V$CACHEPLN.HASH_VALUE`或`V$SQLTEXT.HASH_VALUE` 获取)
	schid       INTEGER,           -- 模式ID(可通过 `SELECT SCHID FROM SYSOBJECTS WHERE NAME='模式名' AND TYPE$='SCH'` 获取)
	type        VARCHAR(12),       -- 语句类型:'SQL'(查询语句)或 'PL/OBJ'(存储过程/触发器)
	binded      INTEGER            -- 绑定类型:0(解绑)、1(内存绑定)、2(持久化绑定)
);

4)查询系统中绑定执行计划持久化的信息。

select * from SYSPLNINFO;
--查询系统中绑定执行计划对应字典对象的信息。
select * from SYSPLNOBJID;
--针对sql查询是否已添加持久化绑定
select BINDED from v$cachepln;

5)移除和禁用

移除系统表 SYSPLNINFO 中 PLN_ID 为 1 的执行计划
SP_REMOVE_STORE_PLN(1);
--禁用系统表 SYSPLNINFO 中 PLN_ID 为 1 的执行计划
SP_SET_PLN_DISABLED(1,1);--解开禁用是0

6)确认持久化计划是否生效

可以通过dmp直接计划方式导出新的执行计划

--先确认sql对应的执行计划缓存号cache_item
select cache_item,sqlstr,* from v$cachepln where sqlstr like '%where a.sess_id=b.sessid%' ;
--打印内存中的缓存计划执行以下命令,打印出缓存计划到默认路径,默认路径在数据库实例目录的trace文件夹中
--假定cache_item=140036430305392
Alter session set events 'immediate trace name plndump,level 140036430305392';

7)注意

a)由于持久化绑定只保存 SQL 语句的前 1000 字节,通过执行计划哈希值以及前 1000 字节字符共同校验以查找计划,故可能存在 SQL 语句不同但哈希值相同的情况,导致查找到错误的计划。
b)内存中绑定与持久化绑定是两种不同的执行计划固化策略,其核心区别如下:
| 维度 | 内存中绑定 | 持久化绑定 |
|-------------------|----------------------------------------|-----------------------------------|
| 存储位置 | 仅保存在内存计划缓存(V$CACHEPLN) | 写入系统表 SYSPLNINFO + 内存缓存 |
| 生命周期 | 服务重启后失效 | 持久存储,重启后自动加载到内存 |
| 绑定方式 | SP_SET_PLN_BINDED(..., binded=1) | SP_SET_PLN_BINDED(..., binded=2) |
| 适用场景 | 临时调优或测试环境 | 核心业务SQL(需长期稳定) |
| 失效条件 | 计划缓存清理(SP_CLEAR_PLAN_CACHE) | 表结构变更或手动删除(SP_REMOVE_STORE_PLN) |

8)补充

select * from v$pln_history where top_sql_text like '%where a.sess_id=b.sessid%';--同一条sql,可能有多个不同的执行计划历史
select * from v$cachepln where sqlstr like '%where a.sess_id=b.sessid%';--同一个sql,hash值是一样的,说明同一时刻,只能用一个执行计划 做持久化绑定的时候,一定要注意不要绑错了计划
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服