oracle sql语句优化(转载)

(1)       选择最有效率的表名顺序   (   只在基于规则的优化器中有效   )  
ORACLE  的解析器按照从右到左的顺序处理  FROM  子句中的表名,  FROM  子句中写在最后的表  (  基础表  driving table)  将被最先处理,在  FROM  子句中包含多个表的情况下  ,  你必须选择记录条数最少的表作为基础表。如果有  3  个以上的表连接查询  那就需要选择交叉表  (intersection table)  作为基础表  交叉表是指那个被其他表所引用的表  .
(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)  例子:
DELETE  FROM  EMP E  WHERE  E.ROWID > (SELECT MIN(X.ROWID) 
FROM  EMP X  WHERE  X.EMP_NO = E.EMP_NO);
(9)         TRUNCATE  替代  DELETE 
当删除表中的记录时  ,  在通常情况下  回滚段  (rollback segments )  用来存放可以被恢复的信息  如果你没有  COMMIT  事务  ,ORACLE  会将数据恢复到删除之前的状态  ( 准确地说是  恢复到执行删除命令之前的状况  而当运用  TRUNCATE    回滚段不再存放任何可被恢复的信息  .  当命令运行后  ,  数据不能被恢复  .  因此很少的资源被调用  ,  执行时间也会很短  . (  译者按  : TRUNCATE  只在删除全表适用  ,TRUNCATE    DDL  不是  DML)
(10)   尽量多使用  COMMIT 
只要有可能  ,  在程序中尽量多使用  COMMIT,  这样程序的性能得到提高  ,  需求也会因为  COMMIT  所释放的资源而减少 
COMMIT
  所释放的资源 
a. 
回滚段上用于恢复数据的信息 
b. 
被程序语句获得的锁 
c. redo log buffer 
中的空间 
d. ORACLE
  为管理上述  3  种资源中的内部花费
(11)     Where  子句替换  HAVING  子句:
避免使用  HAVING  子句  , HAVING  只会在检索出所有记录之后才对结果集进行过滤  这个处理需要排序  ,  总计等操作  如果能通过  WHERE  子句限制记录的数目  ,  那就能减少这方面的开销  .  (    oracle    )  on    where    having  这三个都可以加条件的子句中,  on  是最先执行,  where  次之,  having  最后,因为  on  是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,  where  也应该比  having  快点的,因为它过滤数据后才进行  sum  ,在两个表联接时才用  on 的,所以在一个表的时候,就剩下  where    having  比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是  where  可以使用  rushmore  技术,而  having  就不能,在速度上后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据上篇写的工作流程,  where  的作用时间是在计算之前就完成的,而  having  就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时,  on    where  更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由  where  进行过滤,然后再计算,计算完后再由  having  进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里
(12)   减少对表的查询:
在含有子查询的  SQL  语句中  ,  要特别注意减少对表的查询  .  例子:
      SELECT   TAB_NAME  FROM  TABLES  WHERE  (TAB_NAME,DB_VER) = (  SELECT
TAB_NAME,DB_VER   FROM   TAB_COLUMNS    WHERE   VERSION = 604)
(13)   通过内部函数提高  SQL  效率  . 
复杂的  SQL  往往牺牲了执行效率  能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的
(14)   使用表的别名  (Alias) 
当在  SQL  语句中连接多个表时  请使用表的别名并把别名前缀于每个  Column    .  这样一来  ,  就可以减少解析的时间并减少那些由  Column  歧义引起的语法错误  .
(15)     EXISTS  替代  I  N      NOT EXISTS  替代  NOT IN 
在许多基于基础表的查询中  ,  为了满足一个条件  ,  往往需要对另一个表进行联接  .  在这种情况下  使用  EXISTS(    NOT EXISTS)  通常将提高查询的效率  在子查询中 ,NOT IN  子句将执行一个内部的排序和合并  无论在哪种情况下  ,NOT IN  都是最低效的  (  因为它对子查询中的表执行了一个全表遍历  ).  为了避免使用  NOT IN ,  我们可以把它改写成外连接  (Outer Joins)    NOT EXISTS.
例子:
  高效    SELECT  FROM   EMP (  基础表  )    WHERE   EMPNO > 0    AND     EXISTS  (  SELECT  ‘X'    FROM  DEPT    WHERE   DEPT.DEPTNO = EMP.DEPTNO    AND  LOC = ‘MELB')
(  低效  )  SELECT   *  FROM   EMP (  基础表  )    WHERE   EMPNO > 0    AND   DEPTNO  IN  (SELECT  DEPTNO    FROM   DEPT    WHERE   LOC = ‘MELB'  )
(16)  识别 ' 低效执行 '  SQL 语句:
虽然目前各种关于  SQL  优化的图形化工具层出不穷  ,  但是写出自己的  SQL  工具来解决问题始终是一个最好的方法:
SELECT   EXECUTIONS , DISK_READS, BUFFER_GETS, 
ROUND  ((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2  )  Hit_radio, 
ROUND  (DISK_READS/EXECUTIONS,2) Reads_per_run, 
SQL_TEXT 
FROM   V$SQLAREA 
WHERE   EXECUTIONS>0 
AND   BUFFER_GETS > 0 
AND   (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8 
ORDER BY    DESC  ;
(17)   用索引提高效率:
索引是表的一个概念部分  ,  用来提高检索数据的效率,  ORACLE  使用了一个复杂的自平衡  B-tree  结构  通常  ,  通过索引查询数据比全表扫描要快    ORACLE  找出执行查询和  Update  语句的最佳路径时  , ORACLE  优化器将使用索引  同样在联结多个表时使用索引也可以提高效率  另一个使用索引的好处是  ,  它提供了主键  (primary key)  的唯一性验证  .  。那些  LONG    LONG RAW  数据类型  你可以索引几乎所有的列  通常  在大型表中使用索引特别有效  当然  ,  你也会发现  在扫描小表时  ,  使用索引同样能提高效率  虽然使用索引能得到查询效率的提高  ,  但是我们也必须注意到它的代价  索引需要空间来存储  ,  也需要定期维护  每当有记录在表中增减或索引列被修改时  索引本身也会被修改  这意味着每条记录的  INSERT , DELETE , UPDATE  将为此多付出  4 , 5  次的磁盘  I/O .  因为索引需要额外的存储空间和处理  ,  那些不必要的索引反而会使查询反应时间变慢  .  。定期的重构索引是有必要的  . 
ALTER     INDEX  <INDEXNAME>  REBUILD  <TABLESPACENAME>
(18)     EXISTS  替换  DISTINCT 
当提交一个包含一对多表信息  (  比如部门表和雇员表  )  的查询时  ,  避免在  SELECT  子句中使用  DISTINCT.  一般可以考虑用  EXIST  替换  , EXISTS  使查询更为迅速  ,  因为 RDBMS  核心模块将在  子查询的条件一旦满足后  ,  立刻返回结果  例子:
        (  低效  ): 
SELECT     DISTINCT   DEPT_NO,DEPT_NAME    FROM   DEPT D , EMP E
WHERE   D.DEPT_NO = E.DEPT_NO 
(  高效  ): 
SELECT   DEPT_NO,DEPT_NAME    FROM   DEPT D    WHERE     EXISTS ( SELECT  ‘X' 
FROM   EMP E    WHERE   E.DEPT_NO = D.DEPT_NO  )  ;
(19)   sql  语句用大写的  ;因为  oracle  总是先解析  sql  语句,把小写的字母转换成大写的再执行
(20)     java  代码中尽量少用连接符“+”连接字符串
(21)  避免在索引列上使用 NOT 通常  , 
我们要避免在索引列上使用  NOT, NOT  会产生在和在索引列上使用函数相同的  影响    ORACLE”  遇到  ”NOT,  他就会停止使用索引转而执行全表扫描  .
(22)   避免在索引列上使用计算. 
WHERE
  子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描. 
举例 
低效: 
SELECT … FROM  DEPT  WHERE SAL * 12 > 25000; 
高效 
SELECT … FROM DEPT WHERE SAL > 25000/12;
(23)     >=  替代  >
高效 
SELECT * FROM  EMP  WHERE  DEPTNO >=4 
低效 
SELECT * FROM EMP WHERE DEPTNO >3 
两者的区别在于  前者  DBMS  将直接跳到第一个  DEPT  等于  4  的记录而后者将首先定位到  DEPTNO=3  的记录并且向前扫描到第一个  DEPT  大于  3  的记录  .
(24)   UNION 替换 OR ( 适用于索引列 )
通常情况下    UNION  替换  WHERE  子句中的  OR  将会起到较好的效果  对索引列使用  OR  将造成全表扫描  注意  以上规则只针对多个索引列有效  如果有  column  没有被索引  查询效率可能会因为你没有选择  OR  而降低  在下面的例子中  , LOC_ID    REGION  上都建有索引 
高效 
SELECT  LOC_ID , LOC_DESC , REGION 
FROM  LOCATION 
WHERE  LOC_ID = 10 
UNION 
SELECT  LOC_ID , LOC_DESC , REGION 
FROM  LOCATION 
WHERE  REGION = “MELBOURNE” 
低效 
SELECT  LOC_ID , LOC_DESC , REGION 
FROM  LOCATION 
WHERE  LOC_ID = 10  OR  REGION = “MELBOURNE” 
如果你坚持要用  OR,  那就需要返回记录最少的索引列写在最前面  .
(25)   IN 来替换 OR  
这是一条简单易记的规则,但是实际的执行效果还须检验,在  ORACLE8i  下,两者的执行路径似乎是相同的. 
低效 
SELECT  ….  FROM  LOCATION  WHERE  LOC_ID = 10  OR  LOC_ID = 20  OR  LOC_ID = 30 
高效 
SELECT  …  FROM  LOCATION  WHERE  LOC_IN    IN  (10,20,30);
(26)  避免在索引列上使用 IS NULL  IS NOT NULL
避免在索引中使用任何可以为空的列,  ORACLE  将无法使用该索引  .对于单列索引,如果列包含空值,索引中将不存在此记录  对于复合索引,如果每个列都为空,索引中同样不存在此记录  .   如果至少有一个列不为空,则记录存在于索引中.  举例  如果唯一性索引建立在表的  A  列和  B  列上  并且表中存在一条记录的  A,B  值为  (123,null) , ORACLE  将不接受下一条具有相同  A,B  值(  123,null  )的记录  (  插入  ).  然而如果  所有的索引列都为空,  ORACLE  将认为整个键值为空而空不等于空  因此你可以插入  1000  条具有相同键值的记录  ,  当然它们都是空  因为空值不存在于索引列中  ,  所以  WHERE  子句中对索引列进行空值比较将使  ORACLE  停用该索引  .
低效  : (  索引失效 
SELECT  …  FROM   DEPARTMENT    WHERE   DEPT_CODE  IS NOT NULL 
高效  : (  索引有效 
SELECT  …  FROM   DEPARTMENT    WHERE   DEPT_CODE  >=  0;
(27)  总是使用索引的第一个列 
如果索引是建立在多个列上  只有在它的第一个列  (leading column)    where  子句引用时  ,  优化器才会选择使用该索引  这也是一条简单而重要的规则,当仅引用索引的第二个列时  ,  优化器使用了全表扫描而忽略了索引
(28)   UNION-ALL 替换 UNION ( 如果有可能的话 ) 
  SQL  语句需要  UNION  两个查询结果集合时  ,  这两个结果集合会以  UNION-ALL  的方式被合并  然后在输出最终结果前进行排序  如果用  UNION ALL  替代  UNION,  这样排序就不是必要了  效率就会因此得到提高  需要注意的是    UNION ALL  将重复输出两个结果集合中相同记录  因此各位还是  要从业务需求分析使用  UNION ALL  的可行性  . UNION  将对结果集合排序  ,  这个操作会使用到  SORT_AREA_SIZE  这块内存  对于这  块内存的优化也是相当重要的  下面的  SQL  可以用来查询排序的消耗量
低效: 
SELECT   ACCT_NUM, BALANCE_AMT 
FROM   DEBIT_TRANSACTIONS 
WHERE  TRAN_DATE = '31-DEC-95' 
UNION 
SELECT  ACCT_NUM, BALANCE_AMT 
FROM  DEBIT_TRANSACTIONS 
WHERE  TRAN_DATE = '31-DEC-95' 
高效 
SELECT  ACCT_NUM, BALANCE_AMT 
FROM  DEBIT_TRANSACTIONS 
WHERE TRAN_DATE = '31-DEC-95' 
UNION  ALL 
SELECT  ACCT_NUM, BALANCE_AMT 
FROM  DEBIT_TRANSACTIONS 
WHERE  TRAN_DATE = '31-DEC-95'
(29)   WHERE 替代 ORDER BY 
ORDER BY  子句只在两种严格的条件下使用索引 
ORDER BY
  中所有的列必须包含在相同的索引中并保持在索引中的排列顺序 
ORDER BY
  中所有的列必须定义为非空 
WHERE
  子句使用的索引和  ORDER BY  子句中所使用的索引不能并列  .
例如 
  DEPT  包含以下列 
DEPT_CODE PK NOT NULL 
DEPT_DESC NOT NULL 
DEPT_TYPE NULL
低效  : (  索引不被使用 
SELECT  DEPT_CODE   FROM   DEPT    ORDER BY   DEPT_TYPE 
高效  : (  使用索引 
SELECT  DEPT_CODE    FROM   DEPT    WHERE   DEPT_TYPE > 0
(30)  避免改变索引列的类型 .:
当比较不同数据类型的数据时  , ORACLE  自动对列进行简单的类型转换  .
假设  EMPNO  是一个数值类型的索引列 
SELECT  …    FROM  EMP    WHERE     EMPNO = ‘123' 
实际上  ,  经过  ORACLE  类型转换  语句转化为 
SELECT  …    FROM  EMP  WHERE   EMPNO = TO_NUMBER(‘123') 
幸运的是  ,  类型转换没有发生在索引列上  ,  索引的用途没有被改变 
现在  ,  假设  EMP_TYPE  是一个字符类型的索引列 
SELECT  …    FROM  EMP    WHERE  EMP_TYPE = 123 
这个语句被  ORACLE  转换为 
SELECT  …    FROM  EMP    WHERE  TO_NUMBER(EMP_TYPE)=123 
因为内部发生的类型转换  这个索引将不会被用到  为了避免  ORACLE  对你的  SQL  进行隐式的类型转换  最好把类型转换用显式表现出来  注意当字符和数值比较时  , ORACLE 会优先转换数值类型到字符类型
(31)  需要当心的 WHERE 子句 :
某些  SELECT  语句中的  WHERE  子句不使用索引  这里有一些例子 
在下面的例子里  (1)  ‘!='  将不使用索引  记住  索引只能告诉你什么存在于表中  而不能告诉你什么不存在于表中  .  (2)  ‘||'    字符连接函数  就象其他函数那样  停用了索引 .  (3)  ‘+'  是数学函数  就象其他数学函数那样  停用了索引  (4)  相同的索引列不能互相比较  ,  这将会启用全表扫描  .
(32)   a.  如果检索数据量超过  30%  的表中记录数  .  使用索引将没有显著的效率提高 
b. 
在特定情况下  使用索引也许会比全表扫描慢  但这是同一个数量级上的区别  而通常情况下  ,  使用索引比全表扫描要块几倍乃至几千倍  !
(33)  避免使用耗费资源的操作 :
带有  DISTINCT,UNION,MINUS,INTERSECT,ORDER BY    SQL  语句会启动  SQL  引擎 
执行耗费资源的排序  (SORT)  功能  . DISTINCT  需要一次排序操作  而其他的至少需要执行两次排序  通常  带有  UNION, MINUS , INTERSECT    SQL  语句都可以用其他方式重写  如果你的数据库的  SORT_AREA_SIZE  调配得好  使用  UNION , MINUS, INTERSECT  也是可以考虑的  毕竟它们的可读性很强
(34)  优化 GROUP BY:
提高  GROUP BY  语句的效率  可以通过将不需要的记录在  GROUP BY  之前过滤掉  .  下面两个查询返回相同结果但第二个明显就快了许多  .
低效 
SELECT JOB , AVG(SAL) 
FROM EMP 
GROUP  JOB 
HAVING  JOB = ‘PRESIDENT' 
OR  JOB = ‘MANAGER' 
高效 
SELECT JOB , AVG(SAL) 
FROM EMP 
WHERE JOB = ‘PRESIDENT' 
OR JOB = ‘MANAGER' 
GROUP  JOB
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 性能优化 1.1 避免频繁 commit,尤其是把 commit 写在循环体中每次循环都进行commit。 1.2 使用绑定变量,避免常量的直接引用。 示例:以下书写不符合本规范。 INSERT INTO sm_users (user_id, user_name, created_by, creation_date) VALUES (1, 'Tang', -1, SYSDATE); 建议用如下方式操作: DECLARE v_user_id sm_users.user_id%TYPE; v_user_name sm_users_user_name%TYPE; v_created_by sm_users.created_by%TYPE; v_creation_date sm_users.creation_date%TYPE; BEGIN ... INSERT INTO sm_users (user_id, user_name, created_by, creation_date) VALUES (v_user_id, v_user_name, v_created_by, v_creation_date); END; 1.3 Operator 的使用规范  IN  比较容易写及清晰易懂  但效能是比较低的  ORACLE试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。  NOT IN  此操作是强列推荐不使用的,因为不能应用表的索引。  推荐方案:用NOT EXISTS 或(Outer-Join+判断为空)方案代替 例如: SELECT deptno FROM dept WHERE deptno NOT IN(SELECT deptno FROM emp) 建议写成: SELECT deptno FROM dept, emp WHERE dept.deptno = emp.deptno(+) AND emp.deptno IS NULL  <>  永远不会用到索引的  推荐方案:用其它相同功能的操作运算代替,如: a<>0 改为 a>0 or a<0 a<>’’ 改为 a>’’  IS NULL 或IS NOT NULL  一般是不会应用索引的,因为B-tree索引是不索引空值的。  推荐方案:用其它相同功能的操作运算代替,如: a is not null 改为 a>0 或a>’’  不允许字段为空,而用一个default代替空值,如业扩申请中状态区位不允许为空, default为申请。  > 及 <  有索引就会采用索引查找  但有的情况下可以对它进行优化  如一个表有100万记录,一个数值型字段A,30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。  LIKE  LIKE可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。性能肯定大大提高。  UNION  SQL在运行时先取出数个查询的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。  实际大部分应用中是不会产生重复的记录,推荐采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。  Exists 示例:当有 A、B 两个结果集,当结果集 B 很大时,A 较小时,适用 exists,如: SELECT * FROM a WHERE EXISTS(SELECT 1 FROM b WHERE a.COLUMN = b.COLUMN); 当结果集 A 很大时,B 很小时,适用 in,如: SELECT * FROM a WHERE a.COLUMN IN(SELECT b.COLUMN FROM b) 1.4 SQL书写的影响  同一功能同一性能不同写法SQL的影响  Select * from zl_yhjbqk  Select * from dlyx.zl_yhjbqk(带表所有者的前缀)  Select * from DLYX.ZL_YHJBQK(大写表名)  Select * from DLYX.ZL_YHJBQK(中间多了空格)  以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的原理,可以得出ORACLE对每个SQL 都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写得完全相同则ORACLE只会分析一次,共享内存也只会留下一次的分析结果,这不仅可以减少分析SQL的时间,而且可以减少共享内存重复的信息,ORACLE也可以准确统计SQL的执行频率。  WHERE后面的条件顺序影响  Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1  Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'  以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。  查询表顺序的影响  在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的情况下ORACLE会按表出现的顺序进行链接,由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析,ORACLE会自动先进小表的链接,再进行大表的链接)  对条件字段的一些优化  采用函数处理的字段不能利用索引,如: substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’ trunc(sk_rq)=trunc(sysdate), 优化处理: sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)  进行了显式或隐式的运算的字段不能进行索引,如: ss_df+20>50,优化处理:ss_df>30 ‘X’||hbs_bh>’X5400021452’,优化处理:hbs_bh>’5400021542’ sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5 hbs_bh=5401002554,优化处理:hbs_bh=’ 5401002554’ 注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型  条件内包括了多个本表的字段运算时不能进行索引,如: ys_df>cx_df,无法进行优化 qc_bh||kh_bh=’5400250000’,优化处理:qc_bh=’5400’ and kh_bh=’250000’  HINT  是在ORACLE产生的SQL分析执行路径不满意的情况下要用到的。它可以对SQL进行以下方面的提示  目标方面的提示:  COST(按成本优化)  RULE(按规则优化)  CHOOSE(缺省)(ORACLE自动选择成本或规则进行优化)  ALL_ROWS(所有的行尽快返回)  FIRST_ROWS(第一行资料尽快返回)  执行方法的提示:  USE_NL(使用NESTED LOOPS方式联合)  USE_MERGE(使用MERGE JOIN方式联合)  USE_HASH(使用HASH JOIN方式联合)  索引提示:  INDEX(TABLE INDEX)(使用提示的表索引进行查询)  其它高级提示(如并行处理等等) 1.5 索引的规则: 建立索引常用的原则如下: 1. 表的主键、外键必须有索引 2. 数据量超过 1000 行的表应该有索引 3. 经常与其它表进行连接的表,在边接字段上应建立索引 4. 经常出现在 where 子句中的字段且过滤性极强的,特别是大表的字段,应该建立索引 5. 索引字段,尽量避免值为 null 6. 复合索引的建立需要仔细分析;尽量考虑用单字段索引代替:  正确选择复合索引中的第一个字段,一般是选择性较好的且在 where 子句中常的字段上。  复合索引的几个字段是否经常同时以and方式出现在where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引。  如果复合索引中包含的字段经常单独出现在 where 子句中,则分解为多个单字段索引。  如果复合索引所包含的字段超过 3 个,那么仔细考虑其必要性,考虑减少复合的字段。  如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引; 7. 频繁 DDL 的表,不要建立太多的索引 8. 删除无用的索引,避免对执行计划造成负面影响 9. 让 SQL 语句用上合理的索引,合理让 SQL 语句使用索引的原则如下:  首先,看是否用上了索引,对于该使用索引而没有用上索引的 SQL 语句,应该想办法用上索引。  其次,看是否用上正确的索引了,特别复杂的 SQL 语句,当其中 where 子句包含多个带有索引的字段时,更应该注意索引的选择是否合理。错误的索引不仅不会带来性能的提高,相反往往导致性能的降低。  针对如何用上合理的索引,以 Oracle 数据中的例子进行说明:  任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。  避免不必要的类型转换,要了解“隐藏”的类型转换。  增加查询的范围,限制全范围的搜索。  索引选择性低,但资料分布差异很大时,仍然可以利用索引提高效率。  Oracle 优化器无法用上合理索引的情况下,利用 hint 强制指定索引。  使用复合索引且第一个索引字段没有出现在 where 中时,建议使用 hint 强制。 1.6 索引使用优化  建立Plan_Table CREATE TABLE PLAN_TABLE ( STATEMENT_ID VARCHAR2(30), TIMESTAMP DATE, REMARKS VARCHAR2(80), OPERATION VARCHAR2(30), OPTIONS VARCHAR2(30), OBJECT_NODE VARCHAR2(128), OBJECT_OWNER VARCHAR2(30), OBJECT_NAME VARCHAR2(30), OBJECT_INSTANCE NUMBER(38), OBJECT_TYPE VARCHAR2(30), OPTIMIZER VARCHAR2(255), SEARCH_COLUMNS NUMBER(38), ID NUMBER(38), PARENT_ID NUMBER(38), POSITION NUMBER(38), OTHER LONG )  Syntax 说明: explain plan set statement_id = user_define for select ... 将结果显示 SELECT LPAD(' ', 2 *(LEVEL - 1)) || operation op, options, object_name, POSITION FROM plan_table START WITH ID = 0 AND STATEMENT_ID = user_define CONNECT BY PRIOR ID = parent_id AND STATEMENT_ID = user_define  示例 如要测试下面SQL: SELECT c.short, a.cday, a.card_no, a.qty FROM sales.stockiohis a, sales.product_info b, sales.vendor c WHERE a.card_no = b.card_no AND b.vendorid = c.vendorid AND a.produce_no = '2007090001' AND a.CATEGORY = '10' AND a.iotype = '1' 新增文件:例 d:\mydoc\plan.sql '0001'为user_define为使用者自定义编号 EXPLAIN PLAN SET STATEMENT_ID = '0001' FOR SELECT 'X' FROM sales.stockiohis a ,sales.product_info b ,sales.vendor c WHERE a.card_no = b.card_no AND b.vendorid = c.vendorid AND a.produce_no = '2007090001' AND a.CATEGORY = '10' AND a.iotype = '1' / SET arraysize 1 SET line 100 COLUMN op format a40 COLUMN object_name format a20 COLUMN options format a20 SELECT LPAD(' ', 2 *(LEVEL - 1)) || operation op, options, object_name, POSITION FROM plan_table START WITH ID = 0 AND STATEMENT_ID = '0001' CONNECT BY PRIOR ID = parent_id AND STATEMENT_ID = '0001' / DELETE FROM plan_table WHERE STATEMENT_ID = '0001' / COMMIT / 结果 1.7 避免不必要的排序 说明:对查询结果进行排序会大大的降低系统的性能,group与union都会对数据作排序,要耗费较多的内存,视状况用union all既可,不然有时数据太大又要进行union的排序,会导致Oracle数据库SORT_AREA_SIZE不足发生系统错误。 1.8 对于数字型的Primary Key,建议用序列 sequence 产生。 说明:除非是单据的单号,要求必须是唯一,并且依据流水号不可以跳号,不然在大量交易的表格中,不在乎跳耗时,要取得唯一的Primary Key 建议使用Oracle Sequence这样速度会较快,而且不会有锁定(Lock)的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值