在Oracle中可以使用outline、SQL PROFILE等手段去在无需修改SQL语句的情况下,来保证SQL执行计划在不同硬件环境下相同,从而保证SQL语句在不同环境的执行效率。那么,在达梦数据库中则可以使用SF_INJECT_HINT系统函数达到类似的效果。
SF_INJECT_HINT系统函数的功能是对指定SQL增加HINT。可通过SYSINJECTHINT视图查看已指定的SQL语句和对应的HINT;
使用方法如下:
SF_INJECT_HINT(SQL_TEXT,HINT_TEXT,NAME,DESCRIPTION,VALIDATA,FUZZY);
参数说明如下:
SQL_TEXT:要指定HINT的SQL语句;
HINT_TEXT:要为SQL指定的HINT;多个hint使用空格隔开;
NAME:可以指定名称,或者设为NULL让系统自动创建名称;
DESCRIPTION:对规则的详细描述,可为NULL;
VALIDATA:规则是否生效,可为NULL,则为默认值TRUE;
FUZZY:SQL的匹配规则为精准匹配或模糊匹配。值为TRUE或NULL时,模糊匹配;值为FALSE或缺省时,精准匹配;
需要注意:
FUZZY参数在老的版本中是不支持的(DM V8 1-1-190附近的版本才开始支持)
使用时的限制条件如下:
(1)INI参数ENABLE_INJECT_HINT需设置为1;
(2)SQL只能是语法正确的增删改查语句;
(3)SQL会经过系统格式化,格式化之后的SQL和指定的规则名称必须全局唯一;
(4)HINT一指定,则全局生效;
(5)系统检查SQL匹配时,必须是整条语句完全匹配,不能是语句中子查询匹配;
使用场景:
通过SF_INJECT_HINT函数为SQL指定HINT的方式,适合在SQL执行计划较差或者走错(比如走了索引但回表代价高于全表扫描、表连接错误等情况)且调整SQL语句代价比较大的情况下使用。
(1)设置INI参数ENABLE_INJECT_HINT为1
ENABLE_INJECT_HINT参数表示是否启用SQL指定HINT的功能,0:不启用;1:启用,默认0。动态,会话级参数,修改后无需重启数据库生效。
SP_SET_PARA_VALUE(1,'ENABLE_INJECT_HINT',1);
(2)会话级开启MONITOR_SQL_EXEC,方便使用ET查看SQL执行计划各个操作消耗的时间
sf_set_session_para_value('MONITOR_SQL_EXEC',1);
(3)首先查看测试SQL执行时间以及SQL执行计划各个操作的耗时
SQL语句如下:
select count(OBJECT_ID) from TAB1 WHERE OWNER='CTISYS';
SQL执行计划如下:
1 #NSET2: [3, 1, 78]
2 #PRJT2: [3, 1, 78]; exp_num(1), is_atom(FALSE)
3 #AAGR2: [3, 1, 78]; grp_num(0), sfun_num(1) slave_empty(0)
4 #BLKUP2: [3, 3477, 78]; IDX_TAB1_OWNER(TAB1)
5 #SSEK2: [3, 3477, 78]; scan_type(ASC), IDX_TAB1_OWNER(TAB1), scan_range['CTISYS','CTISYS']
使用et(sql执行号)查看执行计划中各个步骤的耗时情况:
SQL> ET(6007);
行号 OP TIME(US) PERCENT RANK SEQ N_ENTER
---------- ------ -------------------- ------- -------------------- ----------- -----------
1 PRJT2 4 0% 6 2 4
2 DLCK 7 0% 5 0 2
3 NSET2 218 0.09% 4 1 3
4 AAGR2 648 0.26% 3 3 467
5 SSEK2 29371 11.99% 2 5 465
6 BLKUP2 214733 87.65% 1 4 930
BLKUP2操作符表示通过rowid回表,即通过索引记录的ROWID访问表中的数据。索引返回多少行数据,回表就要回多少次,回表的次数太多会严重影响SQL性能。对于SQL中严重影响性能的回表操作,应尽可能的消除,在无法创建较好的组合索引的情况下,反而还不如走全表扫描高效。
(5)SQL语句中添加HINT
HINT的使用以及查看可以参考《DM8 DBA手册》或者达梦社区(https://eco.dameng.com)中相关文档。
使用hint让表不走IDX_TAB1_OWNER索引如下:
select /*+ no_index(TAB1 IDX_TAB1_OWNER)*/ count(OBJECT_ID) from TAB1 WHERE OWNER='CTISYS';
执行计划如下:
SQL> explain select /*+ no_index(TAB1 IDX_TAB1_OWNER)*/ count(OBJECT_ID) from TAB1 WHERE OWNER='CTISYS';
1 #NSET2: [18, 1, 78]
2 #PRJT2: [18, 1, 78]; exp_num(1), is_atom(FALSE)
3 #AAGR2: [18, 1, 78]; grp_num(0), sfun_num(1) slave_empty(0)
4 #SLCT2: [18, 3477, 78]; TAB1.OWNER = 'CTISYS'
5 #CSCN2: [18, 139099, 78]; INDEX33556683(TAB1)
ET查看执行计划各个操作耗时如下:
SQL> et(6105);
行号 OP TIME(US) PERCENT RANK SEQ N_ENTER
---------- ----- -------------------- ------- -------------------- ----------- -----------
1 PRJT2 4 0.01% 6 2 4
2 DLCK 9 0.03% 5 0 2
3 NSET2 99 0.32% 4 1 3
4 AAGR2 107 0.34% 3 3 467
5 SLCT2 2598 8.29% 2 4 930
6 CSCN2 28509 91.01% 1 5 465
从上面测试SQL中执行计划每个步骤的耗时,可以发现全表扫描(CSCN2)耗时28ms,而上面走索引之后回表(BLKUP2)耗时214ms,在这种情况下走全表扫描效率会更快。
在SQL语句中添加hint需要修改程序代码中的SQL,而某些情况下需要在不修改SQL语句的情况下为SQL指定相应hint,这种情况下就可以使用SF_INJECT_HINT为SQL语句指定HINT。
(6)使用SF_INJECT_HINT为SQL语句指定HINT
SF_INJECT_HINT('select count(OBJECT_ID) from TAB1 WHERE OWNER=''CTISYS'';','no_index(TAB1 IDX_TAB1_OWNER)','INJECT_HINT_1',null,TRUE,FALSE);
上述语句表示的意思为:为SQL语句指定hint为no_index(TAB1 IDX_TAB1_OWNER),规则名称为INJECT_HINT_1,规则描述为空,并生效,SQL的匹配规则为精准匹配。
注意:
如果SQL语句中存在单引号,则在使用SF_INJECT_HINT时需要加单引号进行转义。
通过SYSINJECTHINT系统表可以查看相关信息:
SQL> select * from SYSINJECTHINT;
行号 NAME DESCRIPTION VALIDATE
---------- ------------- ----------- --------
SQL_TEXT
-------------------------------------------------------
HINT_TEXT CREATOR CRTDATE INFO1
----------------------------- ------- -------------------------- -----------
INFO2 INFO3
---------- ----------
1 INJECT_HINT_1 NULL TRUE
select count(OBJECT_ID) from TAB1 WHERE OWNER='CTISYS';
no_index(TAB1 IDX_TAB1_OWNER) SYSDBA 2021-12-18 21:40:51.056164 0
NULL NULL
删除指定的INJECTHINT规则:
SF_DEINJECT_HINT('INJECT_HINT_1');
(7)使用SQL模糊匹配,仅使用部分SQL语句让符合规则的SQL语句使用指定HINT
遇到某些业务SQL语句比较长,而且语句中间空格等较多的情况下,这时如果SQL语句少了一个空格等,使用SQL语句精确匹配的规则可能存在指定HINT无法生效的情况。
示例:
以hint STAT为例,stat hint的作用如下:
使用SF_INJECT_HINT为SQL语句执行stat(A 1000M)的hint,SF_INJECT_HINT中的SQL语句为’select OBJECT_ID’,SQL语句匹配规则为模糊匹配,如下:
SF_INJECT_HINT('select OBJECT_ID','STAT(A 1000M)','INJECT_HINT_2',null,TRUE,TRUE);
查看效果:
创建表TAB2,表结构与TAB1相同,数据为1条,执行SQL语句为:select OBJECT_ID,OBJECT_TYPE FROM TAB2 A; ,测试如下:
可以看到,SQL语句模糊匹配时,执行的SQL语句必须与SF_INJECT_HINT规则中的SQL语句完全相同(包括SQL语句中的空格)。同时,指定的HINT对所有符合的SQL语句均生效。
(1)在DM V8 1-1-190左右版本开始,SF_INJECT_HINT支持SQL模糊匹配,这对生产应用环境有非常大的帮助。由于很多业务SQL语句很长而且语句中的空格等也比较多,应用代码不好调整的情况下,使用模糊匹配可以非常方便的为SQL语句指定HINT让其走比较好的执行计划。
(2)SQL语句模糊匹配时,执行的SQL语句必须与SF_INJECT_HINT规则中的SQL语句完全相同(包括SQL语句中的空格)。同时,指定的HINT对所有符合的SQL语句均生效。
更多资讯请上达梦技术社区了解:https://eco.dameng.com