Oracle数据库性能调优(上)

来源:互联网 发布:淘宝客服工作好不好干 编辑:程序博客网 时间:2024/06/06 00:07

Oracle数据库性能调优
1,sql索引
索引是表的一个概念部分,用来提高检索数据的效率,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. 当ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证。

通常, 在大型表中使用索引特别有效. 当然, 在扫描小表时,使用索引同样能提高效率. 虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的。
编写原则:

1. 不要让Oracle做得太多

  • 避免复杂的多表关联:

            cw_charge_record cc where  uf.user_no = dm.user_no and dm.user_no = cc.user_no and …… and not exists(select …)??? 

    上面内容很难优化,并且随着数据量的增加性能的风险很大。

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

  • 用EXISTS替换DISTINCT:

低效

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);
  • 用UNION-ALL 替换UNION ( if possible):
    当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以
    UNION-ALL的方式被合并, 然后在输出最终结果前进行排序.

低效

SELECT ACCT_NUM, BALANCE_AMT        FROM DEBIT_TRANSACTIONS        WHERE TRAN_DATE = ’31-DEC-95UNION        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-95UNION ALL        SELECT ACCT_NUM, BALANCE_AMT        FROM DEBIT_TRANSACTIONS        WHERE TRAN_DATE = ’31-DEC-95

2. 给优化器更明确的命令

  • 自动选择索引

如果表中有两个以上(包括两个)索引,其中有一个唯一性索引,而其他是非唯一性.
在这种情况下,ORACLE将使用唯一性索引而完全忽略非唯一性索引.

SELECT ENAMEFROM EMPWHERE EMPNO = 2326  AND DEPTNO  = 20 ;

这里,只有EMPNO上的索引是唯一性的,所以EMPNO索
引将用来检索记录.

TABLE ACCESS BY ROWID ON EMP       INDEX UNIQUE SCAN ON EMP_NO_IDX
  • 至少要包含组合索引的第一列

如果索引是建立在多个列上, 只有在它的第一个列(leading column)被where子句引用时,优化器才会选择使用该索引.

SQL> create table multiindexusage ( inda number , indb number , descr varchar2(10));Table created.SQL> create index multindex on multiindexusage(inda,indb);Index created.SQL> set autotrace traceonlySQL>  select * from  multiindexusage where inda = 1;Execution Plan----------------------------------------------------------   0      SELECT STATEMENT Optimizer=CHOOSE   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'MULTIINDEXUSAGE'   2    1     INDEX (RANGE SCAN) OF 'MULTINDEX' (NON-UNIQUE)SQL> select * from  multiindexusage where indb = 1;Execution Plan----------------------------------------------------------   0      SELECT STATEMENT Optimizer=CHOOSE   1    0   TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE'

很明显, 当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引

  • 避免在索引列上使用函数

WHERE子句中,如果索引列是函数的一部分.优化器将不
使用索引而使用全表扫描.

低效

SELECTFROM DEPTWHERE SAL * 12 > 25000;

高效

SELECTFROM DEPTWHERE SAL  > 25000/12;
  • 避免使用前置通配符

WHERE子句中, 如果索引列所对应的值的第一个字符由通配符(WILDCARD)开始, 索引将不被采用.

SELECT USER_NO,USER_NAME,ADDRESSFROM USER_FILESWHERE USER_NO LIKE '%109204421';

在这种情况下,ORACLE将使用全表扫描.

  • 避免在索引列上使用NOT

通常,我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. 当ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.

   低效: (这里,不使用索引)   SELECTFROM DEPT   WHERE DEPT_CODE NOT = 0;   高效: (这里,使用了索引)   SELECTFROM DEPT   WHERE DEPT_CODE > 0;
  • 避免在索引列上使用 IS NULL和IS NOT NULL

避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引 .对于单列索引,如果列包含空值,索引中将不存在此记
录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.

如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null) , ORACLE将不接受下一条具有相同
A,B值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以
插入1000条具有相同键值的记录,当然它们都是空!

因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.

任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。

  • 避免出现索引列自动转换

当比较不同数据类型的数据时, ORACLE自动对列进行简单
的类型转换.
假设EMP_TYPE是一个字符类型的索引列.

SELECT USER_NO,USER_NAME,ADDRESSFROM USER_FILESWHERE USER_NO = 109204421这个语句被ORACLE转换为:SELECT USER_NO,USER_NAME,ADDRESSFROM USER_FILESWHERE TO_NUMBER(USER_NO) = 109204421

因为内部发生的类型转换, 这个索引将不会被用到!

  • 在查询时尽量少用格式转换

如用 WHERE a.order_no = b.order_no
不用:

WHERE TO_NUMBER (substr(a.order_no, instr(b.order_no, '.') - 1) = TO_NUMBER (substr(a.order_no, instr(b.order_no, '.') - 1)

3. 减少访问次数
太累了停一会- -,下次更新
4. 细节上的影响
太累了停一会- -,下次更新

0 0