当前位置: 首页 > 科技观察

SQL优化之Oracle性能优化【上】

时间:2023-03-12 19:41:23 科技观察

(1)选择最高效的表名顺序(只在rule-basedoptimizer(Oracle有两种优化器:RBOrule-basedoptimizer和CBOcost-basedoptimizer):ORACLE的parser按照从右到左的顺序处理FROM子句中的表名,FROM子句中***写的表(基本表驱动表)会被***处理,当FROM子句包含多个表时,必须选择记录数最少的表作为基表,如果表连接查询超过3个,需要选择交集表作为基表,交集表是指被引用的表(2)WHERE子句中的连接顺序。:ORACLE按照自下而上的顺序解析WHERE子句。根据这个原则,表之间的连接必须写在其他WHERE条件之前,那些可以过滤的条件出最大数记录的数量必须写在WHERE子句的末尾。(3)避免在SELECT子句中使用'*':ORACLE在解析过程中会将'*'依次转换为所有的列名。这项工作是通过查询数据字典来完成的,这意味着它会花费更多的时间。(4)减少对数据库的访问次数:ORACLE内部进行了大量的工作:解析SQL语句、估计索引利用率、绑定变量、读取数据块等;(5)在SQL*Plus、SQL*Forms和Pro*中重新设置C中的ARRAYSIZE参数可以增加每次访问数据库的检索数据量,推荐值为200。(6)使用DECODE函数减少处理时间:使用DECODE函数可以避免重复扫描相同的记录或重复连接到相同的表。(7)整合简单的、不相关的数据库访问:如果你有几个简单的数据库查询语句,你可以将它们整合成一个查询(即使它们之间没有任何关系)(8)删除重复记录:***删除的有效方法重复记录(因为使用了ROWID)示例:DELETEFROMEMPEWHEREE.ROWID>(SELECTMIN(X.ROWID)FROMEMPXWHEREX.EMP_NO=E.EMP_NO);(9)ReplacewithTRUNCATEDELETE:在删除表中的记录时,一般会使用回滚段(rollbacksegments)来存放可以恢复的信息。如果没有COMMIT事务,ORACLE会将数据恢复到删除前的状态(准确的说,恢复到删除命令执行前的状态),当使用TRUNCATE时,回滚段不再存储任何可恢复的信息.命令执行后,数据无法恢复。因此调用的资源很少,执行时间会很短。多使用COMMIT,这样程序的性能就提高了,需求也会因为COMMIT释放的资源而减少:COMMIT释放的资源:a.用于在回滚段上恢复数据的信息b.由程序语句c获得的锁。重做日志缓冲区d中的空间。ORACLE管理上述3种资源的内部成本(11)将HAVING子句替换为Where子句:避免使用HAVING子句,HAVING只会在检索到所有记录集后才检查结果过滤。此处理需要进行排序和总计等操作。如果可以通过WHERE子句限制记录数,就可以减少这种开销。(oracle中没有)on、where、having三个可以加条件的子句中,on是***执行,后面是where、having***,因为on是过滤不执行的记录先满足条件。只有经过统计,才能减少中间操作要处理的数据。按理说应该是最快的,而且where应该比having快,因为它在求和之前先过滤数据,只有在两表join的时候才会用到。on,所以在一个表中,只剩下where与having进行比较。在单表查询统计的情况下,如果要过滤的条件不涉及要计算的字段,他们的结果是一样的,但是where可以用rushmore技术,having不能,而且后者比较慢的速度。如果涉及计算字段,则说明该字段的值在计算之前是不确定的。按照上一篇写的工作流程,where的动作时间是在计算之前完成的,而having是在计算之后计算的。有效,所以在这种情况下,两者的结果会有所不同。多表连接查询时,on比where早工作。系统首先根据表之间的join条件,将多个表组合成一个临时表,然后按where过滤,然后计算,计算完再用having过滤。由此可见,要想使过滤条件发挥正确的作用,首先要了解条件应该在什么时候起作用,然后再决定放在哪里(12)减少对表的查询:在包含子查询,要特别注意减少对表的查询。例子:SELECTTAB_NAMEFROMTABLESWHERE(TAB_NAME,DB_VER)=(SELECTTAB_NAME,DB_VERFROMTAB_COLUMNSWHEREVERSION=604)(13)通过内部函数提高SQL效率:复杂的SQL往往牺牲执行效率。能够掌握以上使用函数解决问题的方法在实际工作中是非常有意义的(十四)使用表别名(Alias):在SQL语句中连接多个表时,请使用表别名,并在每个别名前加上前缀柱子。这减少了解析时间并减少了由Column歧义引起的语法错误。(15)ReplaceINwithEXISTSandNOTINwithNOTEXISTS:在很多基于底层表的查询中,为了满足一个条件,往往需要连接另一个表。在这种情况下,使用EXISTS(或NOTEXISTS)通常会提高查询效率。在子查询中,NOTIN子句将执行内部排序和合并。无论哪种情况,NOTIN都是最有效的(因为它对子查询中的表执行全表遍历)。为了避免使用NOTIN,我们可以将其改写为OuterJoins或NOTEXISTS。示例:(高效)SELECT*FROMEMP(基本表)WHEREEMPNO>0ANDEXISTS(SELECT'X'FROMDEPTWHEREDEPT.DEPTNO=EMP.DEPTNOANDLOC='MELB')(低效)SELECT*FROMEMP(基table)WHEREEMPNO>0ANDDEPTNOIN(SELECTDEPTNOFROMDEPTWHERELOC='MELB')(16)识别'lowSQL语句的高效执行:虽然各种用于SQL优化的图形化工具层出不穷,但始终是编写自己的SQL工具来解决问题的最佳方法:SELECTEXECUTIONS,DISK_READS,BUFFER_GETS,ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2)Hit_radio,ROUND(DISK_READS/EXECUTIONS,2)Reads_per_run,SQL_TEXTFROMV$SQLAREAWHEREEXECUTIONS>0ANDBUFFER_GETS>0AND(BUFFER_GETS-DISK_READS)/BUFFER_GETS<0.8ORDERBY17)DESCwithindex(效率:索引是表的概念部分,用于提高数据检索效率,ORACLE使用复杂的自平衡B-树结构,一般情况下,通过索引查询数据比全量查询要快表扫描。当ORACLE找到执行查询和Update语句的最佳路径时,ORACLE优化器将使用该索引。连接多张表时也使用索引可以提高效率。使用索引的另一个好处是它提供了主键的唯一性验证。您几乎可以为任何LONG或LONGRAW数据类型的列建立索引。一般来说,索引对大表特别有效。当然你也会发现在扫描小表的时候使用索引也可以提高效率。虽然索引的使用可以提高查询效率,但是我们也要注意它的成本。索引需要空间用于存储和定期维护。每当在表中添加或删除一条记录或修改索引列时,索引本身也会被修改,这意味着每条记录的INSERT、DELETE和UPDATE将花费更多的Pays4、5磁盘I/O。因为索引需要额外的存储空间和处理,不必要的索引实际上会减慢查询响应时间。定期重建索引是必要的:ALTERINDEXREBUILD