马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
×
做了一大半年的业务数据库优化了,有一点感想,写出来自励一下。 公司开发的产品基本上都使用ORACLE数据库,而且业务系统中存储和使用的数据量很大,使用业务系统的用户也很多。在系统忙时,大约会有一千个用户同事访问数据库系统,因此经常会有用户抱怨系统慢,点击查询后,系统出现假死机现象,后台运行ORACLE系统的小型机的IDLE值偏低(甚至出现IDLE为0的情况,这时用户会惊呼数据库系统会瘫掉,虽然小型型机在IDLE值为0的情况下也不一定会瘫机,但这无疑会增加用户的担忧),系统运行在一个不安全的状态等等。 对于我现在所做的ORACLE优化,其实还停留在SQL优化的层次(以前我的前辈曾给我说关于数据库优化的三个层次:一是针对SQL的优化,如使用正确是索引,使用ORACLE提示等;二是针对数据库对象的优化,如增加索引,微调表结构等;三针对业务的优化,需要更改业务逻辑或者表结果,此类优化一般代价比较大,一般很少针对正在运行的系统做类似的操作)。 公司的客户很多,大多数情况会在公司远程处理客户的数据库问题。作为问题的定位者,一定要搞清楚实际运行的数据库系统到底出现了什么问题。现场的维护人员和用户最喜欢使用的形容词是:系统很慢;数据库锁表了等等。用户向外面传达的信心往往是非常模糊的,在开始接触这个问题时候起,我们就要引导用户去帮外面了解系统真实的情况。有几个东西是一定要看看的,一个是ORACLE系统的警告日志文件,在系统运行的有问题或者是忙时的几份STATSPACK报告(一般间隔时间10到15分钟),UNIX下SAR命令的输入结果(该命令可以按既定的时间间隔收集小型机系统CPU的使用情况)。通过这三个从现场收集的结果,我们基本可以了解现场数据库的运行情况。 其中ORACLE系统的警告日志文件能让我们了解ORACLE系统运行有没有一些重大的问题。 STATSPACK报告中概括了数据库系统的运行基本情况,其中关于如何解读报告可以写一本书了,不过我们首先要关注的是报告中有一段“Top 5 Timed Events”,这一段描述了当前ORACLE主要的等待事件是什么(关于ORACLE等待事件的概念可以参考相关的资料)。 SAR命令的输入我们要关注三个输出的分布情况USR、WIO、IDLE。其中SYS+USR+WIO+IDLE应该等于100%,USR占的比例高,一般说明SQL语句执行效率有问题,这种问题一般是由于索引选择性不高、表连接顺序和方式不对等等;WIO高一般说明SQL语句频繁进行I/O操作。对于具体的问题,则需要对具体的SQL语句进行分析,在分析过程中,阅读执行计划是我们的一个重要的工具。 在对ORACLE系统的整体情况有了一定的了解之后,下一步需要分析的就是系统运行过程效率不高的SQL,这是对业务优化的一个起点。如果这时不能够在实际系统中操作,了解SQL的运行过程是一个比较费时的过程的。不管怎么样,对于我们怀疑有问题的SQL,首先要阅读的就是该SQL的在实际系统中的执行计划,语句涉及到的表的数据量,访问表使用索引的选择性如何,表连接的顺序,多表之间的关联关系等等。 对于ORACLE应用系统的优化,大方向上有一个顺序,首先考虑优化业务系统、再考虑优化ORACLE系统本身的参数(如内存分配等),再考虑操作系统本身的优化;在优化业务系统中,首先是首先相关的SQL,以SQL入手分析表是否缺少索引,表连接顺序是否正确,使用的索引是否正确等,然后再考虑调整表结构,调整业务逻辑等等。因此,SQL语句是我们对一个ORACLE业务系统进行优化的敲门砖。 对于SQL优化,前面提到了,ORACLE的执行计划是我们必须使用的工具。本来按ORACLE系统本身提供的方法获取执行计划是一件非常麻烦的事情,不过现在的可视化工具比如PL/SQL DEVELOP或者TOAD等都给我们提供了非常方便的手段来获取SQL语句的执行计划,不过我认为ORACLE本身提供的方法还是有必要会的,特别是在远程处理问题的时候(我也不会,一定要学习一下)。 获取有性能问题的SQL语句,我们主要有两个途径,一个是通过STATSPACK报告。报告中有两节是我们需要重点关注的:《SQL ordered by Gets for》和《SQL ordered by Reads for DB》,这两节中分别按语句读取内存数据库块和读取的物理数据库块(数据库块是指ORACLE的块大小,一般是操作系统最小块的整数倍)的数量倒序排列,如果其中的语句不全(太长),可通过HASH_VALUE值到ORACLE的动态视图V$SQLTEXT中获取该SQL的全部语句。第二个是通过ORACLE系统的动态视图,V$SQL,该视图记录了每个SQL语句的执行次数,物理读和内存读、执行时间等等很多SQL语句的执行信息,可以通过如下语句选择一下物理读和内存读较高的语句: SELECT t.HASH_VALUE, t.EXECUTIONS, t.DISK_READS, round(t.DISK_READS/t.EXECUTIONS) AS perDiskReads, t.BUFFER_GETS, round(t.BUFFER_GETS/t.EXECUTIONS) AS perBufferReads, t.ELAPSED_TIME, round(t.ELAPSED_TIME/t.EXECUTIONS) AS perElayTime, t.CPU_TIME, round(t.CPU_TIME/t.EXECUTIONS) AS perCpuTime, t.FIRST_LOAD_TIME, t.SQL_TEXT FROM v$sql t WHERE (t.DISK_READS/t.EXECUTIONS > 500 OR t.BUFFER_GETS/t.EXECUTIONS > 20000) AND t.EXECUTIONS > 0 ORDER BY 6 DESC; |
这个语句查询出来的SQL可能也不全,也可以通过HASH_VALUE在V$SQLTEXT中找到其全部的SQL。 对于找到的SQL语句我们可以逐一分析其执行计划,结合涉及到的表的数据量,我们可以估算或者测试该语句的执行效率,分析表WHERE条件中涉及的字段(术语叫做谓词),该字段数据分布如何,选择性是否好,是否有索引。这是一个非常繁杂和琐碎的工作,但从这些琐碎的工作中,我们能发现那些SQL执行时选择的索引不对,哪些表缺少相应的索引导致了全表扫描,哪些语句条件不够导致对分区表进行了全表扫描。总之,对于一个给定的SQL,我们结合其表数据量的大小和分布,SQL中使用的查询条件,能够找到一个性能最优的执行方式,通过调整索引、使用ORACLE提示,使ORACLE系统按照最优的方式来执行SQL。如何去分析和确定ORACLE的执行方式,一个最普遍的原则就是尽量根据其谓词(查询条件),使用选择性最好的索引(当然,对于一些小表,可以考虑使用全表扫描的方式性能会更好)。对于SQL的执行方式,需要在工作中不断积累经验,比如曾经在一次优化中发现对一个表安三个字段查询的非常多,因此决定建立该三个字段的复合索引,但结果其语句执行效率却更差。 |