数据库sql提高性能遵守原则

1. 选择最有效率的表名顺序 ( 记录少的放在后面 )
ORACLE 的解析器按照从右到左的顺序处理 FROM 子句中的表名 , 因此 FROM 子句中写在最后的表 ( 基础表  driving table) 将被最先处理 FROM 子句中包含多个表的情况下 , 你必须选择记录条数最少的表作为基础表 . ORACLE 处理多个表时 会运用排序及合并的方式连接它们 . 首先 , 扫描第一个表 (FROM 子句中最后的那个表 ) 并对记录进行派序 , 然后扫描第二个表 (FROM 子句中最后第二个表 ), 最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并 .
例如 :
表  TAB1 16,384  条记录
表  TAB2 1 条记录
选择 TAB2 作为基础表  ( 最好的方法 )
select count(*) from tab1,tab2  执行时间 0.96
选择 TAB2 作为基础表  ( 不佳的方法 )
select count(*) from tab2,tab1     执行时间 26.09
如果有 3 个以上的表连接查询 那就需要选择交叉表 (intersection table) 作为基础表 交叉表是指那个被其他表所引用的表 .
例如 :    EMP 表描述了 LOCATION 表和 CATEGORY 表的交集 .
1. SELECT *  
2. FROM LOCATION L ,  
3.        CATEGORY C,  
4.        EMP E  
5. WHERE E.EMP_NO BETWEEN 1000 AND 2000  
6. AND E.CAT_NO = C.CAT_NO  
7. AND E.LOCN = L.LOCN
将比下列 SQL 更有效率
1. SELECT *  
2. FROM EMP E ,  
3. LOCATION L ,  
4.        CATEGORY C  
5. WHERE   E.CAT_NO = C.CAT_NO  
6. AND E.LOCN = L.LOCN  
7. AND E.EMP_NO BETWEEN 1000 AND 2000
2. WHERE 子句中的连接顺序 ( 条件细的放在后面 )
ORACLE 采用自下而上的顺序解析 WHERE 子句 , 根据这个原理 , 表之间的连接必须写在其他 WHERE 条件之前 那些可以过滤掉最大数量记录的条件必须写在 WHERE 子句的末尾 .
例如 :
( 低效 , 执行时间 156.3 )
1. SELECT …  
2. FROM EMP E  
3. WHERE   SAL > 50000  
4. AND     JOB = ‘MANAGER’  
5. AND     25 < (SELECT COUNT(*) FROM EMP  
6. WHERE MGR=E.EMPNO);  
7. ( 高效 , 执行时间 10.6 )  
8. SELECT …  
9. FROM EMP E  
10. WHERE 25 < (SELECT COUNT(*) FROM EMP  
11.               WHERE MGR=E.EMPNO)  
12. AND     SAL > 50000  
13. AND     JOB = ‘MANAGER’;
3. SELECT 子句中避免使用 '* '
当你想在 SELECT 子句中列出所有的 COLUMN , 使用动态 SQL 列引用  '*'  是一个方便的方法 . 不幸的是 , 这是一个非常低效的方法 实际上 ,ORACLE 在解析的过程中 会将 '*'  依次转换成所有的列名 这个工作是通过查询数据字典完成的 这意味着将耗费更多的时间 .
4. 减少访问数据库的次数
当执行每条 SQL 语句时 , 内部执行了许多工作 解析 SQL 语句 估算索引的利用率 绑定变量  读数据块等等 由此可见 减少访问数据库的次数  就能实际上减少 ORACLE 的工作量 .
方法 1 ( 低效 )
1. SELECT EMP_NAME , SALARY , GRADE  
2.      FROM EMP  
3.      WHERE EMP_NO = 342;  
4.       SELECT EMP_NAME , SALARY , GRADE  
5.      FROM EMP  
6.      WHERE EMP_NO = 291;
方法 2 ( 高效 )
1. SELECT A.EMP_NAME , A.SALARY , A.GRADE,  
2.              B.EMP_NAME , B.SALARY , B.GRADE  
3.      FROM EMP A,EMP B  
4.      WHERE A.EMP_NO = 342
5.      AND    B.EMP_NO = 291;
5. 删除重复记录
最高效的删除重复记录方法  因为使用了 ROWID)
1. DELETE FROM EMP E  
2. WHERE E.ROWID > (SELECT MIN(X.ROWID)  
3.                     FROM EMP X  
4.                     WHERE X.EMP_NO = E.EMP_NO);
6. 用 TRUNCATE 替代 DELETE
当删除表中的记录时 , 在通常情况下 回滚段 (rollback segments )  用来存放可以被恢复的信息 如果你没有 COMMIT 事务 ,ORACLE 会将数据恢复到删除之前的状态 ( 准确地说是恢复到执行删除命令之前的状况 ) ,而当运用 TRUNCATE 回滚段不再存放任何可被恢复的信息 . 当命令运行后 , 数据不能被恢复 . 因此很少的资源被调用 , 执行时间也会很短 .
7 . 减少对表的查询
在含有子查询的 SQL 语句中 , 要特别注意减少对表的查询 .
例如:
低效:
1. SELECT TAB_NAME  
2.            FROM TABLES  
3.            WHERE TAB_NAME = ( SELECT TAB_NAME  
4.                                  FROM TAB_COLUMNS  
5.                                  WHERE VERSION = 604)  
6.            AND  DB_VER= ( SELECT DB_VER  
7.                             FROM TAB_COLUMNS  
8.                             WHERE VERSION = 604
高效:
1. SELECT TAB_NAME  
2.            FROM TABLES  
3.            WHERE   (TAB_NAME,DB_VER)  
4. = ( SELECT TAB_NAME,DB_VER)  
5.                     FROM TAB_COLUMNS  
6.                     WHERE VERSION = 604)
Update  多个 Column  例子 :
低效:
1. UPDATE EMP  
2.             SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),  
3.                SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)  
4.             WHERE EMP_DEPT = 0020;
高效 :
1. UPDATE EMP  
2.             SET (EMP_CAT, SAL_RANGE)  
3. = (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)  
4. FROM EMP_CATEGORIES)  
5.             WHERE EMP_DEPT = 0020;
8. 用 EXISTS 替代 IN, NOT EXISTS 替代 NOT IN
在许多基于基础表的查询中 , 为了满足一个条件 , 往往需要对另一个表进行联接 . 在这种情况下 使用 EXISTS( NOT EXISTS) 通常将提高查询的效率 .
低效 :
1. SELECT *  
2. FROM EMP ( 基础表 )  
3. WHERE EMPNO > 0  
4. AND DEPTNO IN (SELECT DEPTNO  
5. FROM DEPT  
6. WHERE LOC = ‘MELB’)
高效 :
1. SELECT *  
2. FROM EMP ( 基础表 )  
3. WHERE EMPNO > 0  
4. AND EXISTS (SELECT ‘X’  
5. FROM DEPT  
6. WHERE DEPT.DEPTNO = EMP.DEPTNO  
7. AND LOC = ‘MELB’)
( 相对来说 , NOT EXISTS 替换 NOT IN  将更显著地提高效率 )
在子查询中 ,NOT IN 子句将执行一个内部的排序和合并 无论在哪种情况下 ,NOT IN 都是最低效的  ( 因为它对子查询中的表执行了一个全表遍历 ).    为了避免使用 NOT IN , 我们可以把它改写成外连接 (Outer Joins) NOT EXISTS.
例如 :
1. SELECT …  
2. FROM EMP  
3. WHERE DEPT_NO NOT IN (SELECT DEPT_NO  
4.                           FROM DEPT  
5.                           WHERE DEPT_CAT='A');
为了提高效率 . 改写为 :
( 方法一 高效 )
1. SELECT ….  
2. FROM EMP A,DEPT B  
3. WHERE A.DEPT_NO = B.DEPT(+)  
4. AND B.DEPT_NO IS NULL  
5. AND B.DEPT_CAT(+) = 'A'
( 方法二 最高效 )
1. SELECT ….  
2. FROM EMP E  
3. WHERE NOT EXISTS (SELECT 'X'  
4.                      FROM DEPT D  
5.                      WHERE D.DEPT_NO = E.DEPT_NO  
6.                      AND DEPT_CAT = 'A');
当然 , 最高效率的方法是有表关联 . 直接两表关系对联的速度是最快的 !
9. 识别 ' 低效执行 ' SQL 语句
用下列 SQL 工具找出低效 SQL:
1. SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,  
2.          ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,  
3.          ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,  
4.          SQL_TEXT  
5. FROM    V$SQLAREA  
6. WHERE   EXECUTIONS>0  
7. AND      BUFFER_GETS > 0  
8. AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
9. ORDER BY 4 DESC;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值