暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

点滴学习-达梦数据库不更改SQL语句而改变其执行计划

213

在达梦数据库中,HINT注入是一种高级优化技术,允许在不修改SQL语句的情况下,通过外部配置为查询添加 HINT,从而优化查询性能。enable_inject_hint 是一个用于控制是否启用SQL语句中Hint提示注入的功能参数。sf_inject_hint 是一个与HINT注入相关的系统函数,用于动态为SQL语句添加HINT以优化查询性能。

1、HINT注入的作用

HINT注入功能允许DBA在不修改应用程序代码的情况下,为特定SQL语句动态添加HINT。这在以下场景中非常有用:

(1)无法直接修改 SQL 语句(例如第三方应用程序)。

(2)需要临时调整查询执行计划以解决性能问题。

(3)在测试环境中验证不同 HINT 的效果。

2、enable_inject_hint参数

参数名称:enable_inject_hint

作用:控制是否启用 HINT 注入功能。

1:启用 HINT 注入。

0:禁用 HINT 注入(默认值)。

3、查看当前设置

可以通过以下SQL语句查看enable_inject_hint的当前值:

    SHOW PARAMETER 'enable_inject_hint';

    4、修改设置

    可以通过以下SQL语句修改enable_inject_hint的值:

      - 启用 Hint 注入:
        ALTER SYSTEM SET 'enable_inject_hint' = 1;
      - 禁用 Hint 注入:
        ALTER SYSTEM SET 'enable_inject_hint' = 0;

      5、配置 HINT 注入规则

      通过达梦数据库的HINT注入功能,可以为特定的SQL语句动态添加HINT。通常需要配置以下内容:

        sf_inject_hint 的语法通常如下:
        sf_inject_hint(sql_fingerprint, hint_text);
        sql_fingerprint:目标 SQL 语句的指纹(唯一标识),可以是SQL语句的文本或哈希值。
        hint_text:需要注入的 HINT 内容。
        例如:
        sf_inject_hint('SELECT * FROM emp WHERE emp_id = ?''INDEX(emp emp_id_idx)');

        6、验证 HINT 注入效果

        执行目标SQL语句,并通过EXPLAIN或性能监控工具确认HINT是否生效。

        7、实验示例

        (1)创建测试表与测试数据

          create table test as select * from dba_objects;
          insert into test select * from test;
          执行多次插入
          SQL> select count(*from test;
          LINEID     COUNT(*)            
          ---------- --------------------
          1          1099776

          (2)创建索引

            create index idx_status on test(status);

            (3)收集单表统计信息

              BEGIN
                  DBMS_STATS.GATHER_TABLE_STATS(
                      ownname    => 'SYSDBA',
                      tabname    => 'TEST',
                      estimate_percent => 100,
                      method_opt => 'FOR ALL COLUMNS SIZE AUTO'
                  );
              END;
              /

              (4)查看优化前执行计划(CSCN2:聚集索引全表扫描表)

                explain select owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                SQL> explain select owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                1   #NSET2: [3222046156
                2     #PRJT2: [3222046156]; exp_num(2), is_atom(FALSE
                3       #SLCT2: [3222046156]; (TEST.STATUS = 'VALID' AND TEST.OBJECT_NAME = '##PLAN_TABLE')
                4         #CSCN2: [3222199552156]; INDEX33555474(TEST); btr_scan(1)
                used time1.388(ms). Execute id is 0.

                (5)使用hint提示调整执行计划( SSEK2 索引扫描)

                  explain select /*+ INDEX(test idx_status) */ owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                  SQL> explain select /*+ INDEX(test idx_status) */ owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                  1   #NSET2: [26052046156
                  2     #PRJT2: [26052046156]; exp_num(2), is_atom(FALSE
                  3       #SLCT2: [26052046156]; TEST.OBJECT_NAME = '##PLAN_TABLE'
                  4         #BLKUP2: [26052197504156]; IDX_STATUS(TEST)
                  5           #SSEK2: [26052197504156]; scan_type(ASC), IDX_STATUS(TEST), scan_range['VALID','VALID'], is_global(0)
                  used time2.092(ms). Execute id is 0.

                  (6)INJECT HINT函数使用示例(模糊匹配)

                    sf_inject_hint(
                    sql_text => 'select owner from test where STATUS=',
                    hint_text =>'index(test,idx_status)',
                    name =>'TEST_INDEX',
                    description => 'this is a test join hint.',
                    validate => true,
                    fuzzy => true
                    );

                    使用HINT的INI参数可通过V$HINT_INI_INFO 动态视图查询。

                    (7)验证 HINT 注入效果( SSEK2 索引扫描)

                    执行目标 SQL 语句,并通过 EXPLAIN 或性能监控工具确认 HINT 已生效(序号5走索引查询)。

                      explain select owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                      SQL> explain select owner from test where STATUS='VALID' and object_name='##PLAN_TABLE';
                      1   #NSET2: [26052046156
                      2     #PRJT2: [26052046156]; exp_num(2), is_atom(FALSE
                      3       #SLCT2: [26052046156]; TEST.OBJECT_NAME = '##PLAN_TABLE'
                      4         #BLKUP2: [26052197504156]; IDX_STATUS(TEST)
                      5           #SSEK2: [26052197504156]; scan_type(ASC), IDX_STATUS(TEST), scan_range['VALID','VALID'], is_global(0)
                      used time1.625(ms). Execute id is 0.

                      (8)INJECT HINT设置查看

                      查询SYSINJECTHINT视图可以查看已指定的SQL语句和对应的HINT:

                        select NAME, DESCRIPTION, VALIDATE, SQL_TEXT, HINT_TEXT, CREATOR, CRTDATE from SYSINJECTHINT;
                        LINEID     NAME       DESCRIPTION               VALIDATE SQL_TEXT                             HINT_TEXT              CREATOR CRTDATE                   
                        ---------- ---------- ------------------------- -------- ------------------------------------ ---------------------- ------- --------------------------
                        1          TEST_INDEX this is a test join hint. TRUE     select owner from test where STATUS= index(test,idx_status) SYSDBA  2025-02-02 00:13:16.314089
                        used time: 1.336(ms). Execute id is 1422.

                        (9)INJECT HINT状态修改

                        使用SF_ALTER_HINT函数可以设置INJECT HINT无效,置为无效后,相关的sql hint将不再生效。

                          SF_ALTER_HINT('TEST_INDEX' ,'STATUS''DISABLED');

                          (10)INJECT HINT设置删除

                          SF_DEINJECT_HINT函数可以将设置INJECT hint删除。

                            sf_deinject_hint('TEST_INDEX');

                            8、参考链接

                            DM如何实现不更改SQL而改变其执行计划

                            DM8 HINT使用小技巧

                            达梦慢SQL处理方案

                            达梦数据库DM8的SQL性能优化思路浅谈系列(三)

                            近期热门文章:
                            👉Oracle RAC集群OCR注册信息恢复案例分享
                            👉学习笔记-DM8达梦数据库启动过程
                            👉达梦数据库DM8小版本升级案例分享
                            👉如何利用RMAN Debug命令来诊断问题
                            👉达梦数据守护集群异常脑裂处理案例总结
                            👉Linux运维技能-du命令常见用例总结
                            👉Oracle 10g 备份恢复及容灾部署技术问题总结
                            👉TiDB 7.5 实验测试环境搭建及小插曲处理
                            👉DBA实验手册第3讲 运用bbed工具恢复delete误删除的数据
                            👉DBA实验手册第5讲 运用bbed工具恢复truncate表及反向构造段头块
                            全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~

                            文章转载自数据库运维之道,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                            评论