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

【干货攻略】达梦数据库DM8的SQL性能优化思路浅谈系列(一)

达梦E学 2023-03-30
1955

前言
作为一名DBA,SQL优化是我们工作中必不可少的技能。在投产的系统中,存在大量的SQL语句需要我们分析和快速处理,非常考验DBA的能力。

这些慢SQL的原因有很多,比如:SQL编码不规范、设计有缺陷、SQL场景未考虑全面、数据量未评估、预先需要建立索引的表而未设计建立、需分表分区的未进行拆解,也有环境因素造成的缺陷,或是出厂测试之前没有问题但实际部署到客户现场时候却出了问题。

这些异常语句,如果不及时处理,会造成对数据库的一个性能瓶颈,直接影响着目标用户的使用和体验感。所以数据库SQL的性能优化处理显得尤为重要。
希望通过本文,让读者掌握达梦SQL优化的基础、SQL性能分析的思路、参数配置标准和工艺化理念、性能辅助工具应用。文章最后也整合了第三方的常见分析工具,辅助达梦数据库性能压测时候的一种分析手段。由于本文篇幅过长,因此分为三部分给大家分享。因个人能力有限,文章中难免有纰漏,也欢迎读者指正!



预估执行计划生成及基础说明


我们以达梦数据库DM8为例,拿到一条SQL的时候,首先要参考《DM8_SQL语言使用手册》和《DM8系统管理员手册.pdf》中提出的有效SQL规范、是否命中了特殊OR子句的不规范、是否用了复杂的正则表达式、避免重复很高的索引、UINON ALL是否可以替换UNION操作等。

另外还需要考虑,某些场景INSTR函数导致的NEST LOOP效率,需要去预估它的执行计划。预估执行计划,我们可以采用达梦客户端点击如下图解小按钮生成,也可以按快捷键F9生成,也可以在SQL前加EXPLAIN命令生成预估计划
1.1 生成预估执行计划
达梦客户端直接点击菜单栏按钮或按F9生成:
执行下方命令生成:
    EXPLAIN SELECT * FROM TEST_TAB1 WHERE DXID=11487150
    1.2 操作符讲解
    执行计划操作符,可以参考达梦官方手册《DM8系统管理员手册》附录3中执行计划操作符说明。
    常见操作符比如:聚集索引扫描(CSCN2)、全表扫描(CSCN)、索引扫描(SSEK)、二次回表(BLKUP)、除重(DISTINCT)、二级索引定位(SSEK2)等等;多表关联,我们通常会遇到:(HASH链接)HASH JOIN、嵌套循环连接(NEST LOOP JOIN)、MERGE 链接(MERGE JOIN );
    大表和大表关联主要HASH JOIN更优,而如果小表和大表关联,通常是NEST LOOP JOIN会更优,实际情况都是和数据量有关,优化器大部分能选择到合适的操作符,少数情况需要人为干涉。
    1.3 执行计划相关含义说明
    以上图示例简单解读一下执行计划相关含义
    1 #NSET2: [2478, 330721, 356]
    2 #PRJT2: [2478, 330721, 356]; exp_num(9), is_atom(FALSE)
    3 #SLCT2: [2478, 330721, 356]; TEST_TAB1.DXID = var1
    4 #CSCN2: [2478, 13228840, 356]; INDEX35162080(TEST_TAB1)
    #NSET2 表示收集结果集的操作符
    #PRJT2:投影运算,选择表达式的计算
    #SLCT2: 查询条件过滤操作符
    #CSCN2: [2478, 13228840, 356]
    说明:三元组合,3个数字分别表示【估算代价,结果条数,行数据的长度】
    CSCN2: [2478, 13228840, 356]这句含义是:这是一个全表扫描操作,涉及的整体代价估算为2478,结果集为13228840,每行数据长度为356;
    1.4 执行计划顺序讲解
    执行计划我们可以理解是一个树状,看懂执行计划顺序,会让我们更好的分析SQL性能问题,通常执行计划查看,大家可以在达梦客户端选择表格展示或文本方式显示,使用表格展示查看执行顺序会更直观;分析执行计划,文本更适合。SQL的执行顺序,并不是简单的从下而上,它的解析是要遵守规律,具体大家可以这样理解:
    1.4.1缩进越深的越先执行;
    1.4.2同样缩进的上面的先执行,下面的后执行;
    1.4.3上下的优先级高于内外;
    如上说明还是不够直观,我再图解一个样例让大家理解:
    说明:执行过程为控制流从上向下传递,数据流从下向上传递。缩进越深越先执行,同样的缩进,按从上由下的顺序执行。如上图中执行计划的执行顺序为:SSEK2->BLKUP2->SLCT2->CSCN2->HIERARCHICAL->QUERY->SLCT2->SORT3->PRJT2->NSET2。



    达梦性能分析思路


    达梦数据库的优化,我平常使用的最多的还是,达梦数据库优化“三把斧”(统计信息收集,合理的索引建立,dm.ini参数的优化),在实践中发现可以排除93%(百分比数值只是个人以往解决性能问题的估算百分比)以上的性能问题,在使用三把斧过程中,我们首先要预检查下SQL,以及SQL编写的初级错误问题,例如:OR语句、困难正则表达式、未加过滤条件、笛卡尔、隐式转换等先简单过一遍。
    在实际过程中,大部分SQL优化可以通过收集统计信息、新增索引、索引调整、达梦DM.INI参数调整等得到优化处理。而进阶一些比较难SQL分析,就涉及到了增加HINT、SQL改写等。在处理过程中,都需要根据具体SQL来判断,常见的有关联临时表查询、层次查询等容易需要Hint辅助,文章中给出浅显的例子来说明,实际优化过程中,还是需要不断的去实践,根据不同的SQL,分析执行计划,这样才能积累更加丰富的经验。

    2.1 统计信息收集基础讲解
    达梦数据库是基于代价的优化器,达梦数据库统计信息不准,会影响到执行计划的估算,导致SQL解析到错误的执行计划,如何判断统计信息有没有收集呢?

    我们看如下SQL,主要看NUM_ROWS字段,如果没有收集通常是空,第二个LAST_ANALYZED 代表收集的时间,如果没有收集这个字段也是空,第三个TEMPORARY字段附带说明,N表示不是临时表,Y表示是临时表,通常如果TEMPORARY=Y 是不用收集的,这个大家查询的时候注意下,临时表无需收集统计信息。
    用例讲解:
      SELECT NUM_ROWS,LAST_ANALYZED,TEMPORARY FROM USER_TABLES WHERE TABLE_NAME=‘TEST_TAB1’;
      我们需要对表进行查询,查询语句如下:
      当一个表缺失了统计信息我通常用如下语句修复:
        BEGIN
        DBMS_STATS.GATHER_TABLE_STATS(USER,‘TEST_TAB1’,NULL,100,TRUE,‘FOR ALL COLUMNS SIZE AUTO’);
        END;
        DBMS_STATS.GATHER_TABLE_STATS参数说明:
        第一个参数:USER是所属用户,如果你要指定其它用户,单独填写,默认USER是当前用户下的表;
        第二个参数:就是你所要收集的表;
        第三个参数:一般不是分区表名填写NULL即可,默认也是 NULL,区分大小写;
        第四个参数:采样百分比,收集的百分比,范围为 0.000001~100,默认系统自;
        第五个参数:TRUE,保留参数,是否使用随机块代替随机行,默认我们填写 TRUE即可。
        第六个参数:控制列的统计信息集合和直方图的创建的格式默认我们填写FOR ALL COLUMNS SIZE AUTO即可,表示所有列收集。
        需要深入理解的可以参考达梦官方手册DM8系统包使用手.pdf平常我比较常用的还是DBMS_STATS.GATHER_TABLE_STATS
        2.2统计信息收集简单案例
        什么时候需要收集统计信息?通常执行计划估算数据量不准的时候就需要收集了,相差不大一般没有影响,如果比较大就要收集了,否则会影响性能;这里用以下例子说明,只是对表未收集统计信息导致执行计划估算有差异的案例:
        步骤1:直接创建2个表,一般新创建的表统计信息是不会自动收集的(否则开启AUTO_STAT_OBJ全表监控的自动收集),我们查一下它的执行计划,这个时候结果集应该是估算有差异的;
          CREATE TABLE TEST1208_1 AS
          select * from dba_TAB_COLUMNS WHERE TABLE_NAME=‘ALL_ALL_TABLES’;
          CREATE TABLE TEST1208_2 AS
          select * from dba_TAB_COLUMNS WHERE TABLE_NAME=‘ALL_ALL_TABLES’;
          客户端按F9,查看预估执行计划:
          步骤2:获取真实执行计划:
            DISQL登录当前用户
            E:\dmdbms\bin>DISQL SYSDBA/SYSDBA_PWD@127.0.0.1
            然后执行如下命令:
            ALTER SESSION SET ‘MONITOR_SQL_EXEC’=1;
            set autotrace trace;
            SELECT A.COLUMN_NAME FROM TEST1208_1 A ,TEST1208_2 B WHERE A.COLUMN_NAME=B.COLUMN_NAME;
            展示服务端执行计划:
            从服务器上的执行计划这里可以看出,实际56,估算174;
            步骤3:达梦客户端,我们对这连个表统计信息进行收集;
              BEGIN
              DBMS_STATS.GATHER_TABLE_STATS(USER,‘TEST1208_1’,NULL,100,TRUE,‘FOR ALL COLUMNS SIZE AUTO’);
              DBMS_STATS.GATHER_TABLE_STATS(USER,‘TEST1208_2’,NULL,100,TRUE,‘FOR ALL COLUMNS SIZE AUTO’);
              END;
              /
              步骤4:客户端F9,我们再来看预估执行计划:
              收集统计信息后,预估执行计划是已经正确了;
              步骤5:我们重复步骤2看真实SQL计划,那继续再看收集统计信息后执行计划情况:
              发现并没有变化,这是为什么呢?我们思考一下就会想到,因为之前在未收集统计信息的时候,我们执行了一遍这个SQL,所以SQL缓存了计划,那遇到这样的情况,我们应该对这个SQL的缓存计划进行清理;
              步骤6,清理方法如下:
              数值1034139736是通过
                SELECT * FROM v$cachepln where SQLSTR LIKE ‘%TEST1208_2 B WHERE A.COLUMN_NAME%’;
                查询出来的;
                  SP_CLEAR_PLAN_CACHE(1034139736);
                  对这个SQL语句的缓存计划进行清理;
                  清理后,我们再来看下它的服务器计划,这次就正确了。
                  步骤7:我们再次重复步骤2登录查询下它的真实执行计划,看如下图,执行计划也是准确的;
                  总结:通过如上案例,可以直观的显示收集统计前后的状态,以此案例,可以对照我们实际工作中,在分析SQL的时候,当我们发现数据量差异非常大,而且SQL性能低的时候,我们就应该第一直觉想到该要收集统计信息了,如果结果集相差不大,则性能也不会有太大问题。大家主要关注相差特别大的情况。

                  2.3、达梦数据库索引创建

                  合理的索引建立(过多的索引会导致插入的性能下降,我们要根据实际业务情况合理的建立索引)有助于性能的提升,通常表,记录数300以上,离散度高,而且又是SQL的关联列,这种情况可以建立索引,提升查询速度;

                  例子说明:
                  没有索引情况下:
                  TEST_TAB1 有1300万记录,DXID是唯一值;

                  预估执行计划:
                  这里显示是4秒18毫秒;
                  总共1个语句正依次执行…
                    [执行语句1]:
                    SELECT * FROM TEST_TAB1 A WHERE a.dxid=11487148
                    执行成功, 执行耗时4秒 18毫秒. 执行号:108767008


                    1条语句执行成功执行:
                    执行计划:
                    从执行计划上看,SSEK2操作符,已经是二级索引扫描了,说明索引生效了,结果集也是在330721上,而不是13228840,查询速度28毫秒就完成了查询,这里可以说明,加上索引后,速度有140倍的提升;
                    总共1个语句正依次执行…
                      [执行语句1]:
                      SELECT * FROM TEST_TAB1 A WHERE a.dxid=11487148;
                      执行成功, 执行耗时28毫秒. 执行号:108767013
                      1条语句执行成功
                      总结:这是一个非常简单的单表过滤SQL语句,主要用例子来说明,不加索引和加索引的查询速度对比,在数据量越大的时候,差别就越大。侧面也可以看到统计信息,全表扫描和二级索引扫描的结果集相差比较大;
                      2.4 SQL调试工具性能定位思路
                      存储过程性能问题总是让人头痛,这个时候达梦调试工具就发挥还不错的作用,我们可以直接要调试的存储过程SQL进去,进行单步调试,确定他的性能SQL问题处,然后获取出SQL单独分析处理,这里演示下工具的使用:
                      2.4.1 点击客户端的绿色小飘虫;
                      2.4.2再点击执行:
                      2.4.3点击进入箭头,就进入过程内了,在调试过程中,不断点下一步,则可以真实执行,快速定位下慢的段落了,具体工具使用,在手册中《DM8_SQL程序设计.pdf》中有简单说明,操作方法,如下截图:
                      DMSQL调试工具已经满足日常的性能调试,平常我们还可以观测变量的输出,这样就可以很完整的看出变量获取异常等问题。对数据库开发人员来说也比较实用。

                      预告
                      下一期我们会分享达梦SQL性能优化中关于达梦数据库参数调整,跟踪存储过程中的慢SQL思路,辅助性能分析工具介绍和使用以及如何跟踪慢SQL。敬请期待!

                      2023年,达梦干货栏目会一如继往的给大家分享达梦数据库的相关知识。如果大家在工作中有好的想法也可以整理成文章发给我们,我们将在公众号分享给大家。欢迎投稿,期待与大家一同进步!

                      END

                      达梦知识普及

                      扫码关注我们
                      学习共享
                      知识普及

                      原文:引用自“达梦在线服务平台”,具体可点击下方“阅读原文”
                      编辑:crossrainbow
                      排版:哈哈


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

                      评论