• 达梦数据库在不修改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);
    
    • 1

    参数说明如下:

       SQL_TEXT:要指定HINT的SQL语句;
       HINT_TEXT:要为SQL指定的HINT;多个hint使用空格隔开;
       NAME:可以指定名称,或者设为NULL让系统自动创建名称;
       DESCRIPTION:对规则的详细描述,可为NULL;
       VALIDATA:规则是否生效,可为NULL,则为默认值TRUE;
       FUZZY:SQL的匹配规则为精准匹配或模糊匹配。值为TRUE或NULL时,模糊匹配;值为FALSE或缺省时,精准匹配; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意:

    FUZZY参数在老的版本中是不支持的(DM V8 1-1-190附近的版本才开始支持)

    使用时的限制条件如下:

    (1)INI参数ENABLE_INJECT_HINT需设置为1;
    (2)SQL只能是语法正确的增删改查语句;
    (3)SQL会经过系统格式化,格式化之后的SQL和指定的规则名称必须全局唯一;
    (4)HINT一指定,则全局生效;
    (5)系统检查SQL匹配时,必须是整条语句完全匹配,不能是语句中子查询匹配;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用场景:

    通过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);   
    
    • 1

    (2)会话级开启MONITOR_SQL_EXEC,方便使用ET查看SQL执行计划各个操作消耗的时间

    sf_set_session_para_value('MONITOR_SQL_EXEC',1);
    
    • 1

    (3)首先查看测试SQL执行时间以及SQL执行计划各个操作的耗时

    SQL语句如下:

    select count(OBJECT_ID) from TAB1 WHERE OWNER='CTISYS';
    
    • 1

    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']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    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';
    
    • 1

    执行计划如下:

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    从上面测试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);
    
    • 1

    上述语句表示的意思为:为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    删除指定的INJECTHINT规则:

    SF_DEINJECT_HINT('INJECT_HINT_1');
    
    • 1

    (7)使用SQL模糊匹配,仅使用部分SQL语句让符合规则的SQL语句使用指定HINT

    遇到某些业务SQL语句比较长,而且语句中间空格等较多的情况下,这时如果SQL语句少了一个空格等,使用SQL语句精确匹配的规则可能存在指定HINT无法生效的情况。

    示例:

    以hint STAT为例,stat hint的作用如下:

    image-20211218215736512

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

    image-20211218220154076

    查看效果:

    image-20211218220438878

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

    image-20211218220729984

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

  • 相关阅读:
    嬴图 | LLM+Graph:大语言模型与图数据库技术的协同
    Java“牵手”ebay商品详情数据,ebay商品详情API接口,ebayAPI接口申请指南
    开发了一个深度神经网络
    【开源软件推荐】gorm 数据库反向生成status结构工具 gormt
    【Linux】冯诺依曼体系结构、操作系统、进程概念、进程状态、环境变量、进程地址空间
    Java Pattern.group()方法具有什么功能呢?
    antDesign Form表单校验(react)
    2022TWS蓝牙耳机推荐,盘点600元真无线蓝牙耳机
    【树】【图论】【树路径】【深度优先搜索】2867. 统计树中的合法路径数目
    【路径规划-TSP问题】基于粒子群结合蚁群算法求解旅行商问题附matlab代码
  • 原文地址:https://blog.csdn.net/Mrkill123/article/details/127459544