SQL优化中,有时数据库选择的执行计划并不是最优的,这时会考虑使用HINT提示来改变SQL的执行计划(比如索引扫描修改为全表扫描、嵌套循环连接修改为哈希连接)。但使用HINT提示需要修改对应的SQL语句,增加HINT子句,在应用中不是很方便,此时可以使用SF_INJECT_HINT函数来绑定SQL语句使其使用对应的HINT。
本章内容已在如下环境中测试:
操作系统:银河麒麟V10
数据库:DM8
相关关键字:DM数据库、INJECT HINT、HINT提示
一、HINT提示
如下SQL,默认两表关联使用的是哈希连接HASH JOIN:
explain select a.department_id, a.employee_name, b.department_name
from dmhr.employee a, dmhr.department b
where a.department_id = b.department_id;
使用hint改变其执行计划,修改SQL增加HINT提示 /*+use_nl(a,b) */
使其使用内嵌套循环连接:
explain select /*+use_nl(a,b) */ a.department_id, a.employee_name, b.department_name
from dmhr.employee a, dmhr.department b
where a.department_id = b.department_id;
二、INJECT HINT函数
HINT提示需要修改SQL语句, SF_INJECT_HINT函数提供无需修改 SQL 语句依然能按照指定的 HINT 运行语句的相关功能。支持SQL精确匹配和模糊匹配。
使用时的限制条件如下:
(1)INI参数ENABLE_INJECT_HINT需设置为1;
(2)SQL只能是语法正确的增删改查语句;
(3)SQL会经过系统格式化,格式化之后的SQL和指定的规则名称必须全局唯一;
(4)HINT一指定,则全局生效;
(5)系统检查SQL匹配时,必须是整条语句完全匹配,不能是语句中子查询匹配;
(6)可通过 SYSINJECTHINT 视图查看已指定的 SQL 语句和对应的 HINT。
2.1 使用前提
使用SF_INJECT_HINT函数需设置INI 参数 ENABLE_INJECT_HINT为1;
select * from v$dm_ini t where para_name = 'ENABLE_INJECT_HINT';
alter system set 'ENABLE_INJECT_HINT'=1 both;
2.2 INJECT HINT函数使用示例(精确匹配)
使用SF_INJECT_HINT函数指定SQL HINT,默认是精确匹配SQL:
sf_inject_hint(
sql_text => 'select a.department_id, a.employee_name, b.department_name from dmhr.employee a, dmhr.department b where a.department_id = b.department_id;',
hint_text =>'use_nl(a,b)',
name =>'TESTSQL',
description => 'this is a test hint',
validate => true);
这里指定SQL语句的两表关联使用nest loop join,指定后查看该sql的执行计划,可以看到执行计划显示nest loop join。
explain select a.department_id, a.employee_name, b.department_name from dmhr.employee a, dmhr.department b where a.department_id = b.department_id;
2.3 INJECT HINT函数使用示例(模糊匹配)
SF_INJECT_HINT函数精确匹配要求SQL必须严格一致。有的业务SQL较长,查询字段不同、语句中间有空格等,这时精确匹配的规则会使指定HINT无法生效。此时可以使用SF_INJECT_HINT函数的fuzzy 参数使其支持SQL模糊匹配。
例如,指定如下SQL的模糊匹配:
sf_inject_hint(
sql_text => 'from dmhr.employee a, dmhr.department b where a.department_id=b.department_id',
hint_text =>'use_nl(a,b)',
name =>'TESTJOIN',
description => 'this is a test join hint.',
validate => true,
fuzzy = true
);
查看SQL执行计划,比如查询两张表所有列信息,可以看到两表使用nest loop join。
explain select a.*, b.* from dmhr.employee a, dmhr.department b where a.department_id=b.department_id;
HINT提示支持设置INI参数,比如设置ENABLE_HASH_JOIN参数为0,也可以实现相同的功能:
sf_inject_hint(
sql_text => 'from dmhr.employee a, dmhr.department b where a.department_id=b.department_id',
hint_text =>'ENABLE_HASH_JOIN(0)',
name =>'TEST_DISABLE_HASHJOIN',
description => 'this is a test join hint.',
validate => true,
fuzzy = true
);
2.4 INJECT HINT设置查看
查询SYSINJECTHINT视图可以查看已指定的 SQL 语句和对应的 HINT:
select NAME, DESCRIPTION, VALIDATE, SQL_TEXT, HINT_TEXT, CREATOR, CRTDATE from SYSINJECTHINT;
2.5 INJECT HINT状态修改
使用SF_ALTER_HINT函数可以设置INJECT HINT无效,置为无效后,相关的sql hint将不再生效。
SF_ALTER_HINT('TESTJOIN' ,'STATUS', 'DISABLED');
2.6 INJECT HINT设置删除
SF_DEINJECT_HINT函数可以将设置INJECT hint删除。
sf_deinject_hint('TESTJOIN');
三、说明
HINT提示只能对单个sql修改设置HINT,SF_INJECT_HINT支持SQL模糊配置设置,两者都是针对SQL语句生效。
SQL语句模糊匹配时,执行的SQL语句必须与SF_INJECT_HINT规则中的SQL语句完全相同(包括SQL语句中的空格等)。指定的HINT对所有符合SQL语句均生效。
两种方法不仅可以设置SQL多表连接方法,索引提示,也可以设置INI参数提示(支持使用HINT的INI参数可通过V$HINT_INI_INFO 动态视图查询)、统计信息提示等,使SQL优化更灵活。