达梦数据库SQL调优

一、概述

SQL 调优作为数据库性能调优中的最后一个环节,对查询性能产生着直接的影响。在进 行正式的 SQL 调优前,用户首先要关注下列几点:

1.达梦数据库安装时的配置参数是否符合应用场景需求;

2.达梦数据库的 INI 配置文件中各项参数是否已经处于最优配置;

3.应用系统中数据库设计是否合理。

二、目标

SQL 调优的整体目标是使用最优的执行计划,这意味着 IO 以及 CPU 代价最小。具体而言调优主要关注下列方面:

1、表扫描

如果计划中对某大表使用了全索引扫描,那么用户需要关注是否存在着该表的某个查询 条件使得过滤后可以淘汰至少一半的数据量。通过添加相应的索引,全索引扫描可能被转换 为范围扫描或等值查找。

添加的二级索引可以包含该表上所有被选择项以避免 BLKUP2 操作 符的查找操作带来的第二次 IO 开销,但无疑这会增加二级索引的大小。用户需权衡二者的 利弊以选择正确的处理方式。

2、连接操作的顺序和类型

多表连接时,不同的连接顺序会影响中间结果集数量的大小,这时调优的目标就是要找到一种能使中间结果保持最小的连接顺序。

对于给定的一个连接或半连接,DM 可以用 HASH 连接、嵌套循环连接、索引连接或者是归并连接实现。通过分析表的数据量大小和索引信息,SQL 调优目标是选择最适宜的操作符。

对半连接而言,HASH 连接还可细分为左半 HASH 和右半 HASH。用户可以通过始终对数据量小的一侧建立 HASH 来进行调优。

3、分组操作

分组操作往往要求缓存所有数据以找到属于同一组的所有数据,在大数据量情况下这会 带来大量的 IO。用户应该检查 SQL 查询和表上索引信息,如果可以利用包含分组列的索引, 那么执行计划就会使用排序分组从而不用缓存中间结果。

三、确定高负载的 SQL

在打开监控开关(ENABLE_MONITOR=1MONITOR_TIME=1)后,可以通过查询动态视图 V$LONG_EXEC_SQLS V$SYSTEM_LONG_EXEC_SQLS来确定高负载的 SQL 语句。 前者显示最近 1000 条执行时间较长的 SQL 语句,后者显示服务器启动以来执行时间最长的20 SQL 语句。例如:

SELECT * FROM V$LONG_EXEC_SQLS;

或者:

SELECT * FROM V$SYSTEM_LONG_EXEC_SQLS;

四、自动 SQL 调整

使用查询优化向导工具,输入需要进行调整的 SQL 语句,向导工具将在分析完执行计划 后给出推荐索引的提示。用户只需按提示建立相应索引即可。

五、开发有效的SQL语句

SQL 语言是一种相当灵活的结构化查询语言。用户可以利用多种不同形式的查询语句完成相同的查询功能。为了使执行效率达到最优,用户需要参考以下原则以开发出有效的 SQL语句:

1.避免使用 OR 子句

OR 子句在实际执行中会被转换为类似于 UNION 的查询。如果某一个 OR 子句不能利用上索引则会使用全表扫描造成效率低下,应避免使用。

如果 OR 子句都是对同一列进行过滤,用户可以考虑使用 IN VALUE LIST 的过滤形式。如:

SELECT ... WHERE CITY = 'SHANGHAI' OR CITY = 'WUHAN' OR CITY = 'BEIJING';

调整为

SELECT ... WHERE CITY IN( 'SHANGHAI','WUHAN','BEIJING');

2.避免使用困难的正则表达式

SQL 语言中,LIKE 关键字支配通配符匹配,含通配符的表达式被称为正则表达式。有的正则表达式可以自动优化为非匹配的。例如:a LIKE 'L%'可以优化为 a>='L' AND a <'M',这样就可以用到 a 上的索引。即使没有索引,转换后的比较也更快。

再如:a LIKE 'LM_'可以转化为 a>='LM' AND a<'LN' AND a LIKE 'LM_'。虽然仍然包含着通配符匹配,但大大缩小了匹配的范围。

所谓困难的正则表达式是指开头和结尾都为通配符的正则表达式,如'_L%'、'%L_',优化器没办法缩小它们的匹配范围,也不可能用到索引而必须使用全表扫描。因此要尽可能避免这样的正则表达式。

如果仅仅是开头为通配符,用户可以在列 a 上建立 REVERSE(a)这样一个函数索引,利用函数索引反转待匹配项从而使用函数索引进行范围扫描。

3.灵活使用伪表(SYSDUAL)

首先可以利用伪表进行科学计算,执行语句 SELECT 3*4 FROM SYSDUAL,则可以得到结果 12

其次,在某些方面使用 SYSDUAL 可提高效率。例如:查询过程中要判断表 t1 中是否有满足 condition1 条件的记录存在,可执行以下语句:

SELECT COUNT(*) INTO x FROM t1 WHERE condition1;

然后根据变量 x 的取值来判断。但是当 t1 非常大时该语句执行速度很慢,而且由于不知道 SELECT 返回的个数,不能用 SELECT *代替。事实上这个查询可以利用伪表来完成:

SELECT 'A' INTO y FROM SYSDUAL

WHERE EXISTS (SELECT 1 FROM t1 WHERE condition1);

判断 y 值,如等于'A'T1 中有记录。调整后的语句执行速度明显比上一句高。

另外,在 DM 的语法里是可以省略 FROM 子句的,这时系统会自动加上 FROM SYSDUAL。因此前面的科学计算例子可以简化为 SELECT 3*4;

4SELECT 项避免‘*’

除非用户确实要选择表中所有列,否则 SELECT *这种写法将让执行器背上沉重的负荷。因为每一列的数据不得不自下往上层层向上传递。不仅仅如此,如果用户查询的是列存储表,那么列存储所带来的 IO 优势将损耗殆尽。

任何时候,用户都要了解表结构和业务需求,小心地选择需要的列并一一给出名称,避免直接用 SELECT *

5.避免功能相似的重复索引

索引并非越多越好。抛开优化器面对众多索引逐一试探所耗费的时间不谈,如果表上增删改操作频繁,那么索引的维护将会成为大麻烦,尤其是函数索引的计算开销更不能忽略。

6.使用 COUNT(*)统计结果行数

如果对单表查询 COUNT(*)且没有过滤条件,那么 DM 优化器会直接读取相关索引中存储的行数信息,加以回滚段中其他事务插入或删除元组的行数修正,迅速地给出最终结果而避免对实际数据的读取。相比之下,COUNT(列名)会对数据进行读操作,执行效率远低于COUNT(*)

即使查询中含有过滤条件,由于 DM 特有的批处理方式,COUNT(*)依旧快于其他写法。这是因为 COUNT(*)无需取得行的具体值而仅仅需要行数这一信息。

需要额外说明的是,COUNT(*)会将 NULL 值计算在内而 COUNT(列名)是不包含 NULL值的,因此用户要结合应用场景决定是否可以使用 COUNT(*)

7.使用 EXPLAIN 来查看执行计划

在查询语句或者插入、删除、更新语句前增加 EXPLAIN 关键字,DM 将显示其执行计划而无需实际执行它。查阅 V$SQL_NODE_NAME 表中每个操作符的含义,用户可以很方便且直观地了解数据如何被处理及传递。如果启用了统计信息收集,那么对照执行计划和对动态

视图 V$SQL_NODE_HISTORYV$SQL_NODE_NAME 的查询结果,用户就可以知道在实际执行中每一个操作符执行的时间,进而找出性能瓶颈。

8UNION UNION ALL 的选择

UNION UNION ALL 的区别是前者会过滤掉值完全相同的元组,为此 UNION 操作符需要建立 HASH 表缓存所有数据并去除重复,当 HASH 表大小超过了 INI 参数指定的限制时还会做刷盘。

因此如果应用场景并不关心重复元组或者不可能出现重复,那么 UNION ALL 无疑优于UNION

9.优化 GROUP BY ... HAVING

GROUP BY 最常见的实现有 HASH 分组(HAGR)和排序分组(SAGR)。前者需要缓存中间结果;如果用户在 GROUP BY 的列上建立索引,那么优化器就会判断并可能使用上该索引,这时的 GROUP BY 就会变为 SAGR

HAVING 是分组后对结果集进行的过滤,如果过滤条件无关集函数操作,用户可以考虑将过滤条件放在 WHERE 而不是 HAVING 中。DM 优化器会判断并自动转换部分等效于 WHERE的 HAVING 子句,但显式地给出最佳 SQL 语句会让优化器工作得更好。

10.使用优化器提示(HINT

利用经验对优化器的计划选择进行调整,HINT SQL 调整不可或缺的一步。我们将在另外的一篇文章给出详细说明。

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值