达梦数据库在不修改SQL的情况下为SQL指定HINT

前言

   在Oracle中可以使用outline、SQL PROFILE等手段去在无需修改SQL语句的情况下,来保证SQL执行计划在不同硬件环境下相同,从而保证SQL语句在不同环境的执行效率。那么,在达梦数据库中则可以使用SF_INJECT_HINT系统函数达到类似的效果。

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语句代价比较大的情况下使用。

SF_INJECT_HINT使用示例

(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的作用如下:

达梦数据库在不修改SQL的情况下为SQL指定HINT_第1张图片

使用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);

达梦数据库在不修改SQL的情况下为SQL指定HINT_第2张图片

查看效果:

达梦数据库在不修改SQL的情况下为SQL指定HINT_第3张图片

创建表TAB2,表结构与TAB1相同,数据为1条,执行SQL语句为:select OBJECT_ID,OBJECT_TYPE FROM TAB2 A; ,测试如下:

达梦数据库在不修改SQL的情况下为SQL指定HINT_第4张图片

可以看到,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

你可能感兴趣的:(达梦,数据库)