zoukankan      html  css  js  c++  java
  • 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            
       

      


       
       
       
       
      


      

  • 相关阅读:
    thinkphp使用ajax程序报500错误
    非隐藏转发和隐藏转发的区别及选择
    表单文件(图片)上传到服务器,权限自动变成363,无法访问
    我收到了互联网应急中心的通报!记sqlmap的正确打开方式。
    css字体可以小于12px!被小米官网打脸
    阿里云CDN添加域名80端口和443端口什么区别?
    网站使用海外服务器,国内访问很慢的解决方案
    linux下设置php文件不区分大小写
    国际化
    Spring boot2.0学习笔记(一)
  • 原文地址:https://www.cnblogs.com/kaka-bing/p/3213611.html
Copyright © 2011-2022 走看看