白鳝的洞穴 ( 白鳝与Oracle的亲密接触 ) 给他(她)留言   |  相册  |  回到专栏  |  管理  |   登录  博客首页
白鳝在工作中的点滴积累,不仅仅包括技术的
白鳝
  •    我的栏目
  •   我的文章
      Oracle杂谈
      内部分析
      优化
      案例
      小技巧
      BUG与故障
      SQL与PL/SQL开发
      DBA日记
      IT长篇小说第一部:IT的I
  •    最新文章
  •   DBA日记第三部 像Oracle一样
      DBA日记第三部 像Oracle一样
      DBA日记第三部 像Oracle一样
      DBA日记第三部 像Oracle一样
      DBA日记第三部 像Oracle一样
      CPU_COUNT对共享池的影响
      DBA日记 第三部 像Oracle一样
      DBA日记 第三部 像Oracle一样
      3月24日 简单任务 (1)令人
      3月23日 理解表的存储结构 (
  •    最新评论
  •   [HadaVopsesoto]   Would you like to play solitaire against real persons?
      [飞帆]   回复:DBA日记第三部 像Oracle一样思考 3月28日 理解索引(1)
      [xhh]   回复:健康性检查
      [jimlist]   回复:Oracle常用EVENT参考(3)
      [edwards6309]   回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(3)效果不错
      [eagle_fan]   回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(3)效果不错
      [白鳝]   回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(3)效果不错
      [白鳝]   回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(3)效果不错
      [killkill]   Re:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(3)效果不错
      [sir.liang]   回复:健康性检查
  •    博客统计
  •   文章 - 166
      评论 -772
      访问 - 57817
  •    友情链接
  • 主题:DBA日记 第三部 像Oracle一样思考 3月26日 简单任务 (3)令人惊讶的结果 发表时间:2010-4-12 9:41:37 
    作者:白鳝  离线 回复:6   浏览:1005

    DBA日记 第三部 像Oracle一样思考 326 简单任务 3)令人惊讶的结果

    最近系统的业务量不大,所以客户也同意我们白天就做测试。为了防止误操作,客户把SCOTT账号提供给我做测试。今天我准备做几个测试:

    l         SEQUENCE缓冲区测试

    l         表的FREELISTSINITRANS参数调整的测试

    l         HASH分区测试

    l         提交批量测试:测试批量大小对插入性能的影响,分别测试批量为800150030005000条记录的响应时间

    l         BULK INSERT操作测试

    做这种单条SQL执行时间很短的测试,最好的办法是使用profiler工具,将要测试的内容写在一个存储过程里,通过profiler工具来计算平均执行一次所消耗的时间。我首先为每个测试项目都谢了一个小的PL/SQL过程,然后开了7个终端,运行这个存储过程,在第八个终端上的测试过程与其他不同,增加了PROFILER的脚本,这一就能够很方便的采集到每条SQL的执行情况了。

    首先测试SEQUENCE,我分别对各种CACHE值进行了测试。首先编写了一个测试用的存储过程:

    create or replace procedure testSeq(N integer)

    is

     i integer;

     b integer;

     v varchar2(20);

    begin

      i:=0;

      v:=to_char(sysdate,'yyyy-mm-dd:hh24:mi:ss');

      dbms_output.put_line(v);

      loop

        exit when i>N;

        i:=i+1;

        select sm_idseq.nextval into b from dual;

      end loop;

      v:=to_char(sysdate,'yyyy-mm-dd:hh24:mi:ss');

      dbms_output.put_line(v);

    end;

    /

     

    在第八个终端上,执行下面的脚本:

    declare

        err number;

    begin

       err:=DBMS_PROFILER.START_PROFILER (‘test seq 1000’);

       testseq(200000);

       err:=DBMS_PROFILER.STOP_PROFILER ;

    end;

    /

    脚本执行结束后,可以通过下列脚本查看存储过程中每一行执行的情况:

     

    column RUN_COMMENT format a40 truncate;

    select runid, run_date, RUN_COMMENT from plsql_profiler_runs order by runid;

    column unit_name format a15 truncate;

    column occured format 999999 ;

    column line# format 99999 ;

    column tot_time format 999999.999999 ;

     

    select p.unit_name, p.occured, p.tot_time, p.line# line, 

           substr(s.text, 1,75) text

      from 

           (select u.unit_name, d.TOTAL_OCCUR occured, 

                   (d.TOTAL_TIME/1000000000) tot_time, d.line#

              from plsql_profiler_units u, plsql_profiler_data d

             where d.RUNID=u.runid and d.UNIT_NUMBER = u.unit_number

               and d.TOTAL_OCCUR >0

               and  u.runid= &RUN_ID) p,  

           user_source s

     where p.unit_name = s.name(+) and  p.line# = s.line (+) 

     order by p.unit_name, p.line#;

     

    其中的参数,run_id来自于plsql_profiler_units,可以通过我们执行PROFILER的时候使用的名称来查找刚才的测试对应的run_id,一般来说还有个更简单的查找方法,就是找最后一个run_id,因为run_id是通过sequence产生的,我们刚刚做过的测试肯定是最后一个。

    上面的查询的结果如下:

    UNIT_NAME       OCCURED       TOT_TIME       LINE TEXT                                                                                                                                                  

    --------------- ------- -------------- ----------

    <anonymous>           1        .000781          4                                                                                                                                                       

    <anonymous>           1        .009996          5                                                                                                                                                       

    <anonymous>           1        .002121          6                                                                                                                                                       

    TESTLOG               1        .001145          6   i:=0;                                                                                                                                              

    TESTLOG           50001      40.602085          8     exit when i>=N;                                                                                                                                  

    TESTLOG           50000      59.097742          9     i:=i+1;                                                                                                                                           

    TESTLOG           50000    2948.819922         10     select sm_idseq.nextval into v from dual;                                                                                                         

     

    PROFILER可以计算出每一行执行的次数,以及总共消耗的时间。从而可以为我们提供准确的测试数据。SEQUENCE的测试结果如下:

    CACHE

    并发数量

    执行次数

    测试时间(毫秒)

    平均每次执行时间

    2

    8

    200001

    942122

    4.7

    100

    8

    200001

    73282

    0.366

    1000

    8

    200001

    48250

    0.241

    5000

    8

    200001

    47129

    0.236

    20000

    8

    200001

    43299

    0.216

    从测试结果来看,sequence缓冲区的增加可以提高sequence的访问性能,不过超过1000后,加大cache参数,性能提升幅度不大。目前sequencecache已经达到了1000,再加大cache,对性能影响不大。看样子sequencecache是不需要再加大了。

    第一项测试虽然也在预料之中,不过测试结果还是让我感到有点失望。哪怕能提升23%也是好的啊,看样子只能寄希望于后面的测试项目了。第二项测试的是sm_histable表的核心参数,测试比对的是完全按照目前的参数创建的一张测试表,和修改了freelists,initrans,initial,next这几个参数的测试表。表的分区方式,以及存储的表空间等属性都没有修改,索引也完全按照生产环境创建。这次测试的结果让人感到十分惊诧:

    项目

    相关业务

    调整前(秒)

    调整后(秒)

    对比说明

    整体时间

    短信历史记录应用:

    DB_DaeMon程序

    128.67

    112.35

    速度提升:14.53%

    平均每条记录的插入时间

     

    0.002573

    0.002247

    速度提升:14.53%

    调整这几个参数后,并发插入的性能居然提升了14.5%,这有点出乎我的预料。基本上达到了我预期的最高值。兴奋之余,我马上进行了HASH分区的测试,我修改了这张表的定义,将表分区从10个修改为8个,分别存储在4个表空间上,这4个表空间分别属于不同的RAID组,我并没有将5RAID组全部使用,因为另外一个RAID组上,存放了REDO LOG文件,这么设计是为了达到REDO LOG和数据文件互相不干扰的目的。

    PARTITION BY HASH (ID_HINT)

     PARTITIONS 8

     STORE IN (CQYDSMSC_CENTER1,CQYDSMSC_CENTER2,CQYDSMSC_CENTER3,CQYDSMSC_CENTER4)

    测试的结果如下:

    项目

    相关业务

    调整前(秒)

    调整后(秒)

    对比说明

    整体时间

    短信历史记录应用:

    DB_DaeMon程序

    90.397

    78.793

    在存储参数提升14.53%的基础上,再提升14.73%

    平均每条记录的插入时间

     

    0.00181

    0.00158

    在存储参数提升14.53%的基础上,再提升14.73%

    仅这两项优化,性能总体的提升就已经达到了27%,这大大出乎了我的意料。按照这个测试结果,仅依靠这两项调整,这个项目就可以交差了。刚刚这两项测试都是在南坪系统上进行的,我又把这两项测试在人和的系统上再次进行了测试,测试结果也令人满意,在人和系统上,表核心参数的调整后性能提升了15.5%,不过第二项HASH分区的性能提升没有南坪高,只有10.27%,不过总体性能提升也接近了24%

    上午的实验时间过得很快,不知不觉已经快1点钟了,突然感觉周围静悄悄的,抬眼一看,刚才还坐了30多人的办公室里除了我就没有别人了。这个时候才感觉肚子有点饿了。为了填饱肚子,只能放下现在正在进行的实验,出去吃饭。在路上,我还在回味着刚才的实验,心情十分兴奋。突然看到路边有个麻辣烫的摊子,想想吃饭的地方离这里还挺远,不如就随便在小摊上吃点,回去继续完成实验。说实在的,我对重庆的麻辣风味还是不太习惯,吃了一小盘麻辣烫,觉得舌头都已经彻底麻木了。

    回到办公室,我碰到了华为的现场工程师,我问他上午系统是否有异常,他说上午他也经常到监控台边上去看看,没有发现什么异常。听到这样的消息,我的心就更踏实了,按照我上午的测试,每次测试的时间都持续近20分钟,对主生产系统产生的影响不大,说明整个系统的处理能力是足够的。

    下午的测试没有取得太多的成果,对于一个插入任务的记录数的测试,从800条一直提升到5000条,性能提升微乎其微,原本以为插入任务的记录数在这套系统中是通过参数控制的,可以不修改程序就进行调整。根据我以往的经验,一次提交的记录总数有一个最优值,一般在这个最优值之下,加大记录数,总体插入性能会有所提高,超过这个最优值,反而会逐渐下降。这个最优值是和数据库的整体情况已经参数配置、REDO LOG的性能等相关的。不过在一般情况下,这个值应该是超过1000的。看样子华为的技术人员在系统上线前已经做了充分的测试,选择了一个相对合理的值,在这一点上,我们确实没有多大的优化余地了。

    于是我接着做了BULK INSERT操作的测试,根据以往的经验,BULK INSERT对于性能的提升是十分大的,由于BULK INSERT只是作为今后改进的建议,不作为本次优化的重点,因此原本考虑仅仅通过BULK INSERT的调整就达到优化目标的想法就只能作罢了。我写了一个BULK INSERT的测试脚本:

    CREATE OR REPLACE PROCEDURE TESTFORALL (N INTEGER)

    IS

      TYPE T_SM_ID    IS TABLE OF          NUMBER(10)   INDEX BY BINARY_INTEGER;

      TYPE T_SM_SUBID IS TABLE OF          NUMBER(3)    INDEX BY BINARY_INTEGER;

      TYPE T_ORGADDR    IS TABLE OF        VARCHAR2(21) INDEX BY BINARY_INTEGER;

      TYPE T_DESTADDR   IS TABLE OF        VARCHAR2(21) INDEX BY BINARY_INTEGER;

      TYPE T_ID_HINT    IS TABLE OF        NUMBER(10)   INDEX BY BINARY_INTEGER;

      V_SM_ID         T_SM_ID;

      V_SM_SUBID      T_SM_SUBID;

      V_ORGADDR       T_ORGADDR;

      V_DESTADDR      T_DESTADDR;

      V_ID_HINT       T_ID_HINT;

      I INTEGER;

    BEGIN

       FOR I IN 1.. N

       LOOP

          V_SM_ID(I):=I;

          V_SM_SUBID(I):=12;

          V_ORGADDR(I):='444555565';

          V_DESTADDR(I):='555555';

          SELECT SM_IDSEQ.NEXTVAL INTO V_ID_HINT(I) FROM DUAL;

       END LOOP; 

       FOR I IN 1..N LOOP

         INSERT INTO SM_HISTABLE0101 (SM_ID,SM_SUBID,ORGADDR,DESTADDR,ID_HINT) VALUES

           (V_SM_ID(I),V_SM_SUBID(I),V_ORGADDR(I),V_DESTADDR(I),V_ID_HINT(I));

       END LOOP;

       COMMIT;

       FORALL I IN 1..N

         INSERT INTO SM_HISTABLE0101 (SM_ID,SM_SUBID,ORGADDR,DESTADDR,ID_HINT) VALUES

           (V_SM_ID(I),V_SM_SUBID(I),V_ORGADDR(I),V_DESTADDR(I),V_ID_HINT(I));

       COMMIT;

    END;

    /

    测试结果不出我的所料,性能提升了数倍:

     

    项目

    相关业务

    调整前(秒)

    调整后(秒)

    对比说明

    整体时间

    短信历史记录应用:

    DB_DaeMon程序

    (南坪)

    0.149

    0.0389

    速度提升3.83

    平均每条记录的插入时间

    0.000186

    0.000048

    速度提升3.83

     

    整体时间

    短信历史记录应用:

    DB_DaeMon程序

    (人和)

    0.0911

    0.0247

    速度提升3.68

     

    平均每条记录的插入时间

     

    0.0001138

    0.000031

    速度提升3.68

     

    做完实验的时候,看看时间刚刚下午3点多钟。于是我联系了一下余经理,把实验的结果告诉了她。她一听十分高兴,建议马上开个会,如果测试的结果得到确认,明天就可以调整一下表结构,测试一下性能。

    我马上把刚才的测试数据做了一个简单的PPT,赶到会议室的时候已经快4点了,余经理和华为的工程师正在会议室里等着我。看到我演示的结果,余经理和华为的工程师都感到十分兴奋。由于这套系统使用了日表,因此只要重建明天使用的表就可以完成优化动作了。为了确保安全,后天和以后的表暂时不做调整,等明天使用结果出来后再决定是否统一修改日表创建的脚本。

    本文链接:http://www.oraclefans.cn/blog/showblog.jsp?rootid=18190
     
           网友评论
    ─ 评论人 sky_heaven    10-04-12 10:15
     

    老白学会说评书了。到了精彩的地方嘎然而止!
    ─ 评论人 chjlu    10-04-12 12:20
      谢谢。老师。
    ─ 评论人 chjlu    10-04-12 12:24
      如果能跟白老师学习。就好了。
    ─ 评论人 corey    10-04-12 14:22
      精彩
    问题1: 为什么要用5个raid组?数据在raid 10上应该已经打散了吧,其实用两个raid组,一个raid存数据,另一个存redo log,理论上是不是能达到一样的效果?
    问题2: 存储过程TESTFORALL的参数N,太大了对内存要求高,太小了效果不明显,而且要频繁commit,怎么确定此参数的最佳值?
    ─ 评论人 白鳝    10-04-12 15:59
      问题1:用户的环境就是这样的,可以看上一节。对于不是底层打散的存储,实际上对于高手来说,可能更灵活一些,不够调整起来比较麻烦,打散的存储适合于一般用户使用。
    问题2:本节也说了,批量的大小和应用及系统有关,最好的办法是通过测试来确定。不过随着你的系统的改变,最佳值可能会变化,不过你通过严格的测试得到的结果就算不是最优的,也基本上和最优值的效果相差不大
    ─ 评论人 tomzzy    10-07-30 08:50
      老白继续,顶一个
     
    1
     
    >> 请登录以后评论!您还没有注册?   

    Powered by CWBBS 2.1  © 2005-2006 Cloud Web Soft
      Email:webmaster@justdb.cn