高效SQL技巧

http://blog.csdn.net/leshami/article/details/7406672



  1. 1) 选择最有效的表名顺序(仅适用于RBO模式)                                                                              
  2.     ORACLE的解析器总是按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中最后的一个表将作为驱动表被优先处理。当FROM子句       
  3. 存在多个表的时候,应当考虑将表上记录最少的那个表置于FROM的最右端作为基表。Oracle会首先扫描基表(FROM子句中最后的那个表)并对       
  4. 记录进行排序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并。如       
  5. 果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。                 
  6.                                                                                                                                  
  7. 下面的例子使用最常见的scott或hr模式下的表进行演示                                
  8.                                                                                                
  9. 表 EMP 有14条记录                                                                
  10. 表 DEPT 有4条记录                                                   
  11. SELECT  /*+ rule */ COUNT( * )  FROM   emp, dept;          --高效的写法    
  12.                                                                                                                                  
  13.                                                                  
  14. 4) 使用DECODE函数来减少处理时间                                
  15. -->使用decode函数可以避免重复扫描相同的行或重复连接相同的表                   
  16. select count(*),sum(sal) from emp where deptno=20 and ename like 'SMITH%';              
  17.                                                                                           
  18. select count(*),sum(sal) from emp where deptno=30 and ename like 'SMITH%';                
  19.                                                                                               
  20. -->通过使用decode函数一次扫描即可完成所有满足条件记录的处理                                        
  21. SELECT COUNT( DECODE( deptno, 20, 'x'NULL ) ) d20_count                                         
  22.      , COUNT( DECODE( deptno, 30, 'x'NULL ) ) d30_count                                      
  23.      , SUM( DECODE( deptno, 20, sal, NULL ) ) d20_sal                                          
  24.      , SUM( DECODE( deptno, 30, sal, NULL ) ) d30_sal                                            
  25. FROM   emp                                                                  
  26. WHERE  ename LIKE 'SMITH%';                                                
  27.                                                                           
  28. 类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中。                           
  29.                                                                                  
  30.                                    
  31.                                                                                                                                  
  32. 9) 计算记录条数                                                                                                                  
  33. -->一般的情况下,count(*)比count(1)稍快.如果可以通过索引检索,对索引列的计数是最快的,因为直接扫描索引即可,例如COUNT(EMPNO)   
  34. -->实际情况是经测试上述三种情况并无明显差异.                                                   
  35.                                                
  36.                                                                                         
  37. 11) 最小化表查询次数                                                                                                             
  38. -->在含有子查询的SQL语句中,要特别注意减少对表的查询                                                                             
  39. -->低效:                                                           
  40. SELECT *                                                                                      
  41. FROM   employees                                                                                   
  42. WHERE  department_id = (SELECT department_id                                                       
  43.                         FROM   departments                                                     
  44.                         WHERE  department_name = 'Marketing')                                   
  45.        AND manager_id = (SELECT manager_id                                                       
  46.                          FROM   departments                                                     
  47.                          WHERE  department_name = 'Marketing');                                  
  48. -->高效:                                                                
  49. SELECT *                                                                                    
  50. FROM   employees                                                                             
  51. WHERE  ( department_id, manager_id ) = (SELECT department_id, manager_id                                  
  52.                                         FROM   departments                                                   
  53.                                         WHERE  department_name = 'Marketing')                   
  54.                                                                                     
  55.                                                            
  56.                                     
  57.                                                                                  
  58. 13) 用EXISTS替代IN                                                                                   
  59.     在一些基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下,使用EXISTS(或NOT EXISTS)通常        
  60. 将提高查询的效率.                                                                                                               
  61. -->低效:                                 
  62. SELECT *                                                              
  63. FROM   emp                                                       
  64. WHERE  sal > 1000                                                      
  65.        AND deptno IN (SELECT deptno                                         
  66.                       FROM   dept                                          
  67.                       WHERE  loc = 'DALLAS')                                     
  68.                                                                    
  69. -->高效:                                                                               
  70. SELECT *                                                                 
  71. FROM   emp                                                             
  72. WHERE  empno > 1000                                          
  73.        AND EXISTS                                                       
  74.               (SELECT 1                                       
  75.                FROM   dept                                     
  76.                WHERE  deptno = emp.deptno AND loc = 'DALLAS')                           
  77.                      
  78. 14) 用NOT EXISTS替代NOT IN     
  79.     在子查询中,NOT IN子句引起一个内部的排序与合并.因此,无论何时NOT IN子句都是最低效的,因为它对子查询中的表执行了一个全表        
  80. 遍历.为避免该情形,应当将其改写成外部连接(OUTTER JOIN)或适用NOT EXISTS                                    
  81. -->低效:                                                                      
  82. SELECT *                                                                                        
  83. FROM   emp                                                                        
  84. WHERE  deptno NOT IN (SELECT deptno                                          
  85.                        FROM   dept                                            
  86.                        WHERE  loc = 'DALLAS');                                             
  87.                                     
  88. -->高效:                                             
  89. SELECT e.*                                                                                      
  90. FROM   emp e                                                                                      
  91. WHERE  NOT EXISTS                                                                                     
  92.           (SELECT 1                                                                                    
  93.            FROM   dept                                                                                
  94.            WHERE  deptno = e.deptno AND loc = 'DALLAS');                                       
  95.                                                                       
  96. -->最高效(尽管下面的查询最高效,并不推荐使用,因为列loc使用了不等运算,当表dept数据量较大,且loc列存在索引的话,则此时索引失效)   
  97. SELECT e.*                                                                                     
  98. FROM   emp e LEFT JOIN dept d ON e.deptno = d.deptno                                                 
  99. WHERE  d.loc <> 'DALLAS'                                                                       
  100.                                                             
  101. 15) 使用表连接替换EXISTS                                                
  102. 一般情况下,使用表连接比EXISTS更高效                                                             
  103. -->低效:                                                    
  104. SELECT *                                                                                                       
  105. FROM   employees e                                                                                         
  106. WHERE  EXISTS                                                                                                      
  107.           (SELECT 1                                                                       
  108.            FROM   departments                                                              
  109.            WHERE  department_id = e.department_id AND department_name = 'IT');                                 
  110.                                                                                     
  111. -->高效:                  
  112. SELECT *              -->经测试此写法SQLplus下比上面的写法多一次逻辑读,而在Toad下两者结果一致               
  113. FROM   employees e INNER JOIN departments d ON d.department_id = e.department_id              
  114. WHERE  d.department_name = 'IT';                                                        
  115.                                                               
  116. 16) 用EXISTS替换DISTINCT          
  117. 对于一对多关系表信息查询时(如部门表和雇员表),应避免在select 子句中使用distinct,而使用exists来替换           
  118.                                                      
  119. -->低效:                                                                
  120. SELECT DISTINCT e.department_id, d.department_name                                              
  121. FROM   departments d INNER JOIN employees e ON d.department_id = e.department_id;                   
  122.                                   
  123. -->高效:                                                            
  124. SELECT d.department_id,department_name                                                         
  125. from departments d                                                                       
  126. WHERE  EXISTS                                                                              
  127.           (SELECT 1                                                                      
  128.            FROM   employees e                                                       
  129.            WHERE  d.department_id=e.department_id);                                              
  130.                                                                       
  131. EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果                                
  132. -->经测试此写法SQLplus下比上面的写法多一次逻辑读,而在Toad下两者结果一致                                  
  133.                                                               
  134. 17) 使用 UNION ALL 替换 UNION(如果有可能的话)                                                           
  135. 当SQL语句需要UNION两个查询结果集时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序。       
  136. 如果用UNION ALL替代UNION, 这样排序就不是必要了。 效率就会因此得到提高。                                                         
  137.                                                                 
  138. 注意:                       
  139. UNION ALL会输出所有的结果集,而UNION则过滤掉重复记录并对其进行排序.因此在使用时应考虑业务逻辑是否允许当前的结果集存在重复现象   
  140.                                                                          
  141. 寻找低效的SQL语句                                                            
  142. -->下面的语句主要适用于从视图v$sqlarea中获得当前运行下且耗用buffer_gets较多的SQL语句                   
  143. SELECT executions                                                                     
  144.      , disk_reads                                                                    
  145.      , buffer_gets                                                                  
  146.      , ROUND( ( buffer_gets         
  147.                - disk_reads )       
  148.              / buffer_gets, 2 )      
  149.           hit_ratio                                      
  150.      , ROUND( disk_reads / executions, 2 ) reads_per_run                   
  151.      , sql_text                                       
  152. FROM   v$sqlarea                                                               
  153. WHERE      executions > 0                                                   
  154.        AND buffer_gets > 0                                               
  155.        AND ( buffer_gets                                                    
  156.             - disk_reads )                                                  
  157.            / buffer_gets < 0.80                                                        
  158. ORDER BY 4 DESC;                                                   
  159.                               
  160. 18) 尽可能避免使用函数,函数会导致更多的 recursive calls  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值