oracle数据库优化

一、数据库级的优化

1.  nccm_chargedetail 表分区   1499万 半年数据量 (解决百万级,千万级数据量)
   partition by list (BURYEAR)
   (
     partition P_2013  values ('2013')
     tablespace T_2013
     pctfree 10
     initrans 1
     maxtrans 255
     storage (
              initial 3114M
              next 1M
              minextents 1
              maxextents unlimited
              )
    );
    
 2. 索引 (index)
    假设表中有100000行,而sql要读取表中20%的行,也就是20000;再做个假设,如果行大小
    约80字节,那么块大小为8kb的块则大约100行,这说明表大约1000个块。那么通过索引读取
    的话, 大约20000个TABLE ACCESS BY ROWID
    操作来执行查询,那么需要处理200000个块,但整个表才1000个块。
    在这种情况下,全表扫描要比用索引高效。
  
    索引使用规则:通常对于小表,Oracle建议通过全表扫描进行数据访问,对于大表则应该
    通过索引以加快数据查询,当然如果查询要求返回表中大部分或者全部数据,那么全表扫
    描可能仍然是最好的选择。
    像查询nccm_clinicsub 门诊报销表中某个家庭的所有报销单据,有什么理由不用索引呢 ?
    select * from nccm_clinicsub h where h.famid='4115252521010313' and h.buryear='2013';
  
    索引需要空间来存储,也需要定期维护,
    每当有记录在表中增减或索引列被修改时, 索引本身也会被修改.
    这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O .
    因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。

3. 连接池 (Connection Pool机制)
   连接会话的三种状态 active inactive killed
   合理的配置连接池: 最小连接数、最大连接数、闲置连接数、回收连接时间
  
 
4. 视图 (view)  nccm_mtp
   视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对
   表里面的数据进行查询和修改。视图基于的表称为基表。视图是存储在数据字
   典里的一条select语句。 通过创建视图可以提取数据的逻辑上的集合或组合。
  
   视图的优点:
  
   ① 对数据库的访问,因为视图可以有选择性的选取数据库里的一部分。
   ② 用户通过简单的查询可以从复杂查询中得到结果。
   ③ 维护数据的独立性,试图可从多个表检索数据。
   ④ 对于相同的数据可产生不同的视图。
  
   dic_code_medical   dic_code_treat  dic_code_ops
   create or replace view nccm_mtp as  sql;
  
5. 临时表  
    create global temporary table 临时表名 on commit preserve|delete rows ;
    用preserve时就是SESSION级的临时表,用delete就是TRANSACTION级的临时表;
  
   ① 循环SQL:系统中有很多类似的sql循环执行,效率很低
   ② 多表关联:  利用临时表简化有太多表关联的复杂SQL
   ③ 如果某个数据集会重复多次使用的情况下建议使用临时表
   ④ 临时表作为复杂查询条件的中间结果用于主查询
  
   nccm_pro_prov_report_03


6. 控制碎片
   碎片(fragmentation)是对一组非邻接的数据库对象的描述。碎片意味着在执行数据库
   的功能时要耗费额外的资源(磁盘I/O,磁盘驱动的循环延迟,动态扩展,链接的块等)
   ,并浪费大量磁盘空间。当两个或多个数据对象在相同的表空间中,会发生区间交叉。
   在动态增长中,对象的区间之间不再相互邻接。为了消除区间交叉将静态的或只有小增
   长的表放置在一个表空间中,而把动态增长的对象分别放在各自的表空间中。
   在create table、、create index、create tablespace、create cluster时,
   在storage(指定对象的存储参数)子句中的参数的合理设置,可以减少碎片的产生。
  
      ① 字典表、变动少的表   用表空间1;
      ②每天都动态增长的表用 表空间2、3、4等;
      ③storage参数的意义;
     
     
二、sql级优化
 
1.  oralce优化器
    执行计划:   在执行sql语句时,Oracle需要执行很多步骤。在每一步中,Oracle或者从
    数据库中读取数据,或者为用户提交sql语句准备数据。这些Oracle在执行sql语句时使用
    的步骤的集合叫做执行计划。
   
    oracle优化器:在执行sql语句时,oracle优化器都要对sql语句进行解析,得到一个执行计划。
    因为解析操作比较浪费系统资源,导致系统性能下降。所以解析完sql语句后,都要将解析得到
    的执行计划保存在内存中。如果再次执行该sql,就不需要解析了,直接从内存中获取其执行计划。
    所以再次提醒尽量减少访问数据库的次数以及sql语句的执行次数,不要在客户机器上开开pl/sql
    不关,一直占用资源。更甚着有用for update锁表的(导致程序短时间挂掉)。查看表的时候不要用
    编辑表,而是用查看表。
   
    Hints(提示):基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻
    了DBA的负担。但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇
    慢无比。此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成
    执行计划,从而使语句高效的运行。
    例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就
    可以指示优化器使用全表扫描。在Oracle中,是通过为语句添加 Hints(提示)来实现干预优化
    器优化的目的。
   
    创建执行计划表:sqlplus nccm/nccm@nccm
     sql> @D:appAdministratorproduct11.1.0db_2RDBMSADMINutlxplan.sql
   
    查看执行计划表的结构:desc plan_table; 
    id  步骤编号 operation 所执行内部操作名称 optimizer 优化器当前的模式 cost 操作成本
     cardinality 访问行数 bytes 访问的字节数 
   
    查看执行计划: explain plan for select * from nccm_hossubsidy;
   
    查看执行计划表的数据:    select * from plan_table;
   
    查看格式化的数据:
    select lpad('', 2 * (level - 1)) || operation || '' || options || '' ||
       object_name || '' || decode(id, 0, 'Cost=' || position) "Query Plan"
    from plan_table  connect by prior id = parent_id;
    删除表中的数据:delete from plan_table;
    最优的查询plan_table方式:select * from table(DBMS_XPLAN.display);
    最最优的查询方式:用pl/sql的F5
   
   
   
2.  FROM/WHERE子句中的连接顺序
    经测试只在基于规则的优化器中有效;而oracle默认的是ebo模式;
    查看当前优化器模式:
    select name,value from v$parameter where name ='optimizer_mode';
    alter system set optimizer_mode=Rule scope=spfile;
    关闭实例 卸载数据库: shutdown或者shut immediate;
    开启实例 打开数据库: connect /as sysdba; startup;
    Rule:          不用多说,即走基于规则的方式。
    Choolse:       这是我们应观注的,默认的情况下Oracle用的便是这种方式。指的是当一个
    表或或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且
    相应的列有索引时,那么就走索引,走RBO的方式。
    First Rows:    它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快
    的方式返回查询的最先的几行,从总体上减少了响应时间。
    All Rows:      也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返
    回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走基于规则的方式。
   
    select * from nccm_hossubsidy h ,nccm_joinperson j where h.personid=j.personid;
    select * from nccm_joinperson j ,nccm_hossubsidy h where h.personid=j.personid;
    select * from nccm_clinicsub c where c.famid='4115250528010234' 
    and c.birthday='19000101';
    select * from nccm_clinicsub c where c.birthday='19000101' and
    c.famid='4115250528010234' ;
    自从oracle添加优化器功能后,已经没有效果了; 虽然加载条件与表的顺序依然是从右到左。
   
   
   
3.  索引的恰当使用
    where子句中对索引字段计算运用函数、类型转换等会导致索引的失效!
    select * from nccm_clinicsub c where substr(c.famid,1,16)='4115250528010234'
     and c.birthday='19000101';
    select * from nccm_clinicsub c where c.famid||'01'='411525052801023401'
    and c.birthday='19000101';
   
4.  在程序中尽量多使用COMMIT
    nccm_savePayfeeinfo  农合缴费过程  没有及时的commit
   
5.  见过最奇葩的sql语句:
    select c,name,c.orgcode,c.diagdate from nccm_clinicsub c
    where c.famid='4115250528010234' and c.buryear='2013';
    循环遍历:
    select p.pointegername from nccm_pointegerorg p where p.pointegercode=orgcode;
         

6.  in、exists、group by的正确使用
    group by的having和where
    select orgcode, h.orglevel, sum(h.factsub)
     from nccm_hossubsidy h
    where h.orglevel > 3
    group by h.orgcode, h.orglevel
   
    select orgcode, h.orglevel, sum(h.factsub)
    from nccm_hossubsidy h
    group by h.orgcode, h.orglevel
    having h.orglevel > 3
   
    经测试not in/exists 无效
    select *
    from nccm_hossubsidy h
    where h.villcode in (select t.villcode
                        from nccm_hossubsidy t
                       where t.villcode = '4115252521');
    select *
    from nccm_hossubsidy h
    where exists (select 1
          from nccm_hossubsidy t
         where t.villcode = h.villcode
           and t.villcode = '4115252521');
    select *
    from nccm_chargedetail c
    where c.billcode not in
       (select h.billcode
          from nccm_hossubsidy h
         where h.billcode = 'Z0000000000000000011');

    select *
    from nccm_chargedetail c
    where not exists (select 1
          from nccm_hossubsidy h
         where h.billcode = c.billcode
           and h.billcode = 'Z0000000000000000011');
          
     为什么exists与in的效果一样呢???   
    在oracle 9i中,默认提供是基于选择的优化器,即当有分析数据时,采用基于成本的优化方式,
    没有则仍采用基于规则的查询方式,这样优化模式下基本等同于基于规则或者基于成本。在10g之
    后的版本,默认都是以基于成本的方式进行,这时候,oracle会先找出可能的执行方式,然后计算
    出每个执行计划的成本,再选择以较低成本的方式进行计算,这样子在对in和exists的分析中,这
    两种写法会相互转换,那个统计的成本信息低则会选择那种方式。当然由于oracle的成本信息并不
    是全量统计得出来的结果,也会有一定的误差,再统计信息是需要人工(或定时)去执行统计的,
    如果操作大量数据后,没有进行统计,偏差也会很大。
   
    批量插入数据优化:
    常规的插入方法:
       循环loop 10000:
           insert into table (a,b,c,d);
       end;
    批量插入的方法:
       循环loop 100:
          v_sql:='insert into table select a,b,c,d from dual';
            循环loop 100:
                v_sql:=v_sql||'union all select a,b,c,d from dual';
            end;
          execute immediate v_sql;
       end;
    批量插入仅仅完成100次插入,效率要远远高于10000次的常规插入。
   
   
   
    尽量不要使用‘*’以及用select max(clicode) from nccm_clinicsub c            
   

  


   
   
   
   
  


  

原文地址:https://www.cnblogs.com/kaka-bing/p/3213611.html