`

SQL优化的一些注意事项

阅读更多

4. 选择最有效率的表名顺序(只在基于规则的优化器中有效)
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并.
例如:      表 TAB1 16,384 条记录
         表 TAB2 1      条记录
     选择TAB2作为基础表 (最好的方法)
     select count(*) from tab1,tab2   执行时间0.96秒
     选择TAB2作为基础表 (不佳的方法)


--------------------------------------------------------------------------------
 txfy 回复于:2003-12-02 10:06:03

select count(*) from tab2,tab1   执行时间26.09秒
如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.
例如:   EMP表描述了LOCATION表和CATEGORY表的交集.
SELECT * 
FROM LOCATION L , 
      CATEGORY C,
      EMP E 
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
 将比下列SQL更有效率
SELECT * 
FROM EMP E ,
LOCATION L , 
      CATEGORY C
WHERE  E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000

 
5.       WHERE子句中的连接顺序.
   ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.
 例如:
 (低效,执行时间156.3秒)
SELECT … 
FROM EMP E
WHERE  SAL >; 50000
AND    JOB = ‘MANAGER’
AND    25 < (SELECT COUNT(*) FROM EMP


--------------------------------------------------------------------------------
 txfy 回复于:2003-12-02 10:06:21

WHERE MGR=E.EMPNO);
 (高效,执行时间10.6秒)
SELECT … 
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
             WHERE MGR=E.EMPNO)
AND    SAL >; 50000
AND    JOB = ‘MANAGER’;


6.     SELECT子句中避免使用 ‘ * ‘
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘*’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将’*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间. 


7.     减少访问数据库的次数
当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等等. 由此可见, 减少访问数据库的次数 , 就能实际上减少ORACLE的工作量.
 例如,
    以下有三种方法可以检索出雇员号等于0342或0291的职员.
 方法1 (最低效)
    SELECT EMP_NAME , SALARY , GRADE
    FROM EMP 
    WHERE EMP_NO = 342;
     SELECT EMP_NAME , SALARY , GRADE
    FROM EMP 
    WHERE EMP_NO = 291;
方法2 (次低效)
       DECLARE 
        CURSOR C1 (E_NO NUMBER) IS 
        SELECT EMP_NAME,SALARY,GRADE


--------------------------------------------------------------------------------
 txfy 回复于:2003-12-02 10:06:58

FROM EMP 
        WHERE EMP_NO = E_NO;
    BEGIN 
        OPEN C1(342);
        FETCH C1 INTO …,..,.. ;
                OPEN C1(291);
       FETCH C1 INTO …,..,.. ;
         CLOSE C1;
      END;
方法3 (高效)
    SELECT A.EMP_NAME , A.SALARY , A.GRADE,
            B.EMP_NAME , B.SALARY , B.GRADE
    FROM EMP A,EMP B
    WHERE A.EMP_NO = 342
    AND   B.EMP_NO = 291;
 注意:
在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200.


8.       使用DECODE函数来减少处理时间
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.
例如:
   SELECT COUNT(*),SUM(SAL)
   FROM EMP
   WHERE DEPT_NO = 0020
   AND ENAME LIKE ‘SMITH%’;
   SELECT COUNT(*),SUM(SAL)
   FROM EMP
   WHERE DEPT_NO = 0030
   AND ENAME LIKE ‘SMITH%’;
你可以用DECODE函数高效地得到相同结果
SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,
        COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,
        SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
        SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE ‘SMITH%’;
类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.


9.       整合简单,无关联的数据库访问
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)
例如:
 SELECT NAME 
FROM EMP 
WHERE EMP_NO = 1234;

 SELECT NAME 
FROM DPT
WHERE DPT_NO = 10 ;

SELECT NAME 
FROM CAT
WHERE CAT_TYPE = ‘RD’;
上面的3个查询可以被合并成一个:
 SELECT E.NAME , D.NAME , C.NAME
FROM CAT C , DPT D , EMP E,DUAL X
WHERE NVL(‘X’,X.DUMMY) = NVL(‘X’,E.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,D.ROWID(+))
AND NVL(‘X’,X.DUMMY) = NVL(‘X’,C.ROWID(+))
AND E.EMP_NO(+) = 1234
AND D.DEPT_NO(+) = 10
AND C.CAT_TYPE(+) = ‘RD’;
 (译者按: 虽然采取这种方法,效率得到提高,但是程序的可读性大大降低,所以读者 还是要权衡之间的利弊)


10.       删除重复记录
最高效的删除重复记录方法 ( 因为使用了ROWID)
DELETE FROM EMP E
WHERE E.ROWID >; (SELECT MIN(X.ROWID) 
                   FROM EMP X
                   WHERE X.EMP_NO = E.EMP_NO);


13.       计算记录条数
     和一般的观点相反, count(*) 比count(1)稍快 , 当然如果可以通过索引检索,对索引列的计数仍旧是最快的. 例如 COUNT(EMPNO)
  (译者按: 在CSDN论坛中,曾经对此有过相当热烈的讨论, 作者的观点并不十分准确,通过实际的测试,上述三种方法并没有显著的性能差别)



 14.       用Where子句替换HAVING子句
      避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.
 例如:
     低效:
     SELECT REGION,AVG(LOG_SIZE)
     FROM LOCATION
     GROUP BY REGION
     HAVING REGION REGION != ‘SYDNEY’
     AND REGION != ‘PERTH’
      高效
     SELECT REGION,AVG(LOG_SIZE)
     FROM LOCATION
     WHERE REGION REGION != ‘SYDNEY’
     AND REGION != ‘PERTH’
     GROUP BY REGION
(译者按: HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中)


15.       减少对表的查询
在含有子查询的SQL语句中,要特别注意减少对表的查询.
  例如: 
     低效
          SELECT TAB_NAME
          FROM TABLES
          WHERE TAB_NAME = ( SELECT TAB_NAME 
                                FROM TAB_COLUMNS
                                WHERE VERSION = 604)
          AND DB_VER= ( SELECT DB_VER 
                           FROM TAB_COLUMNS
                           WHERE VERSION = 604)
     高效
          SELECT TAB_NAME
          FROM TABLES
          WHERE  (TAB_NAME,DB_VER)
 = ( SELECT TAB_NAME,DB_VER) 
                   FROM TAB_COLUMNS
                   WHERE VERSION = 604)
     Update 多个Column 例子:
     低效:
           UPDATE EMP
           SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),
              SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)
           WHERE EMP_DEPT = 0020;
     高效:
           UPDATE EMP
           SET (EMP_CAT, SAL_RANGE)
 = (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)
 FROM EMP_CATEGORIES)
           WHERE EMP_DEPT = 0020;


17.       使用表的别名(Alias)
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
  (译者注: Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属)


18.       用EXISTS替代IN
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.
 低效:
SELECT * 
FROM EMP (基础表)
WHERE EMPNO >; 0
AND DEPTNO IN (SELECT DEPTNO 
FROM DEPT 
WHERE LOC = ‘MELB’)
    高效:
SELECT * 
FROM EMP (基础表)
WHERE EMPNO >; 0
AND EXISTS (SELECT ‘X’ 
FROM DEPT 
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB’)
(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出)



19.       用NOT EXISTS替代NOT IN
在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历).  为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
 例如:
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO 
                         FROM DEPT 
                         WHERE DEPT_CAT=’A’);
为了提高效率.改写为:
 (方法一: 高效)
SELECT ….
FROM EMP A,DEPT B
WHERE A.DEPT_NO = B.DEPT(+)
AND B.DEPT_NO IS NULL
AND B.DEPT_CAT(+) = ‘A’
 (方法二: 最高效)
SELECT ….
FROM EMP E
WHERE NOT EXISTS (SELECT ‘X’ 
                    FROM DEPT D
                    WHERE D.DEPT_NO = E.DEPT_NO
                    AND DEPT_CAT = ‘A’);


20.       用表连接替换EXISTS
     通常来说 , 采用表连接的方式比EXISTS更有效率
      SELECT ENAME
      FROM EMP E
      WHERE EXISTS (SELECT ‘X’ 
                      FROM DEPT
                      WHERE DEPT_NO = E.DEPT_NO
                      AND DEPT_CAT = ‘A’);
     (更高效)
      SELECT ENAME
      FROM DEPT D,EMP E
      WHERE E.DEPT_NO = D.DEPT_NO
      AND DEPT_CAT = ‘A’ ;
  (译者按: 在RBO的情况下,前者的执行路径包括FILTER,后者使用NESTED LOOP)


 21.       用EXISTS替换DISTINCT
当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换
 例如:
低效:
    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);
  EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.




36.       用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, 那就需要返回记录最少的索引列写在最前面.

49.       优化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

分享到:
评论

相关推荐

    Oracle SQL规范与优化注意事项

    以下是一些重要的优化策略和注意事项: 1. **避免语法分析重复**:尽量保持SQL语句的标准化,避免因书写格式不同而进行多次语法分析,这会增加解析开销。 2. **使用绑定变量**:共享SQL语句,使用绑定变量而非常量...

    sql 优化语句的几个常用注意事项

    保证数据库性能的sql语句写法,注意事项,使得我们在书写时避免使数据库低效率的执行命令

    SQL编程注意事项

    以下是一些关键知识点,它们涵盖了标题"SQL编程注意事项"所提及的要点。 1. NULL值处理:在SQL中,NULL表示未知或无值,与0、空字符串等不同。在进行比较和计算时,NULL值需要特别对待。例如,`NULL = NULL`返回的...

    基本的Sql编写注意事项

    以下是一些基本的SQL编写注意事项,这些技巧适用于SQL Server 2000等系统,旨在提高查询效率和减少全表扫描。 1. 避免过度使用`IN`操作符。`EXISTS`通常比`IN`更高效,因为它只需找到一个匹配项即可停止查询。例如...

    SQL_Server2005安装及注意事项

    在安装SQL Server 2005时,了解并遵循正确的步骤和注意事项至关重要,以确保顺利安装并能高效运行。 **概述** SQL Server 2005的安装是一个多步骤的过程,涉及系统兼容性检查、组件选择、服务账户配置等多个环节。...

    优化sql语句执行效率几点注意事项

    本文将详细探讨几个关于优化SQL语句执行效率的重要注意事项,旨在帮助数据库管理员和开发者提升系统性能。 首先,理解索引的作用与创建策略是优化SQL的第一步。索引可以大幅提高数据检索速度,但并不是所有字段都...

    写SQL注意事项,以下是提供的一些方法,请参考..

    在编写SQL语句时,有许多重要的注意事项需要遵循,以确保代码的效率、可读性和维护性。以下是一些关键点的详细说明: 1. **多样化解决问题的方法**:不要只关注于得到最终结果,而应探索多种实现方式,如使用...

    ORACLE培训SQL性能优化.pptx

    在 SQL 语句优化过程中,我们需要注意一些重要的注意事项。例如,我们需要检查执行计划,检查执行过程中优化器的统计信息,分析相关表的记录数、索引情况,并改写 SQL 语句、使用 HINT、调整索引、表分析。只有通过...

    SQL语法优化策略 、T-SQL编程注意事项

    SQL语法优化策略与T-SQL编程注意事项是数据库性能提升的关键环节。优化SQL语句能够显著提高查询速度,减少资源消耗,提升系统整体性能。以下是一些重要的策略和注意事项: 1. **选择性原则**:在`WHERE`子句中,应...

    SQL优化原则

    ### SQL优化原则及注意事项 #### 一、问题的提出与背景 在软件开发过程中,特别是在初期阶段,由于数据库中的数据量相对较少,开发者往往难以直观感受到不同SQL语句编写方式所带来的性能差异。然而,随着互联网...

    sqlserver优化笔记

    - **注意事项**: - 不要在索引字段上执行计算、函数调用、数据类型转换等操作。 - 避免使用 `NOT`, `&lt;&gt;`, `!=`, `IS NULL` 和 `IS NOT NULL` 在索引列上。 - 避免在索引列中使用空值。 **1.3 复杂操作优化** -...

    ORACLE-SQL优化

    在进行SQL优化时,还需要注意一些关键事项,如避免复杂的查询操作、合理使用索引、考虑查询中涉及的数据量、检查数据的分布情况以及统计信息的准确性等。 九、调优领域 调优工作可以从不同的领域进行,包括应用程序...

    sql优化宝典

    ### SQL优化宝典:提升Oracle查询效率的关键策略 #### 一、引言 在软件开发过程中,数据库查询的性能往往直接影响到整个应用系统的响应时间和用户体验。特别是在使用Oracle数据库时,合理的SQL语句编写技巧和优化...

    # sql基础与优化

    对于SQL优化,我们关注: 1. **索引的创建和使用**:在频繁查询的列上创建索引可以加速查询。B树、位图、函数索引等都是不同的索引类型,适用于不同场景。 2. **避免全表扫描**:尽可能利用索引来避免对整个表的数据...

    oracle培训sql性能优化ppt

    注意事项** - 开发人员需了解Oracle结构,重视性能,遵守开发规范。 - SQL优化是一个系统过程,涉及多方面因素,需要综合考虑。 总之,Oracle SQL性能优化涵盖了从SQL编写、执行计划分析到系统层面的调整。通过...

    Oracle Sql 优化

    #### 二、SQL语句编写注意事项 ##### 2.1 ISNULL与ISNOTNULL 在WHERE子句中使用`IS NULL`或`IS NOT NULL`会导致Oracle优化器无法利用索引进行优化,因为NULL值并不参与索引排序。为了充分利用索引,应避免在WHERE...

    SQL执行过程和优化

    oracle SQL执行过程和优化 索引分类 索引注意事项 执行过程

    编写高性能的SQL语句注意事项

    本文将探讨编写高性能SQL语句时应注意的一些事项。 1. **处理NULL值**: - `IS NULL` 和 `IS NOT NULL` 操作在含有NULL值的列上不会使用索引,导致全表扫描。因此,尽量避免在索引列上使用NULL值,同时避免在WHERE...

Global site tag (gtag.js) - Google Analytics