原始SQL:

  1. CREATE OR REPLACE PROCEDURE sp_upd_suppressed_emails
    (
      A_LIMIT_BULK IN PLS_INTEGER DEFAULT 2000,
      A_COMMIT_AFTER IN PLS_INTEGER DEFAULT 2000
    ) is
  2.  
  3.   v_operation Varchar2(20) := 'START';
      v_last         PLS_INTEGER;   
      v_start        PLS_INTEGER;   
      v_end          PLS_INTEGER;  
      l_row          PLS_INTEGER;
      
      CURSOR curs_contact IS SELECT id FROM contact
      WHERE active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y' 
      and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') ) 
      and  email is not null ORDER BY id; 
      
      TYPE contactId IS RECORD ( id contact.id%TYPE); 
     
      TYPE v_contactId_tbl IS TABLE OF contactId INDEX BY PLS_INTEGER;
      
      v_contact v_contactId_tbl;    
       
    BEGIN
        
        DBMS_OUTPUT.PUT_LINE ('start reading data..' );
        v_operation := 'BEFORE OPEN';
    OPEN curs_contact;
  4.  
  5. LOOP
  6.  
  7. v_operation := 'BEFORE FETCH';
    FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK;
    v_operation := 'AFTER FETCH';
  8.  
  9. EXIT WHEN v_contact.COUNT = 0;
  10.  
  11. v_start := 1;   
    v_last := v_contact.COUNT; 
    l_row := 0;
  12.  
  13. LOOP
    DBMS_OUTPUT.PUT_LINE ('LOOP 2 top ');
    EXIT WHEN v_start > v_last;
    v_end := LEAST (v_start + A_COMMIT_AFTER - 1, v_last);
                DBMS_OUTPUT.PUT_LINE ('LOOP 2 v_start ' || v_start || ' end ' || v_end );
    BEGIN
    v_operation := 'UPDATE_LOAD';
    FORALL i IN v_start .. v_end 
                    UPDATE contact SET active_ind = 1, suppress_flag = 'N', bounce_flag = 'N'  WHERE id = v_contact (i).id;
                END;
    DBMS_OUTPUT.PUT_LINE ('after forall start ' || v_start || ' end ' || v_end );
                COMMIT;
    v_start := v_end + 1;         
    END LOOP;
    DBMS_OUTPUT.PUT_LINE ('LOOP 2 bottom v_start ' || v_start || ' end ' || v_end );
            COMMIT;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE ('stop reading data..' );
        
        EXCEPTION 
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE ('Exception:Others-> v_operation = ' || v_operation || ', rowcount # ' || l_row || ' SQLCODE ' || SQLCODE || ' ERR_MSG = ' || SUBSTR(SQLERRM, 1, 500) );
  14.  
  15. END sp_upd_suppressed_emails;

原始SQL在执行过程中经过几小时未完成,查看sql统计信息:

Stat Name Statement Total Per Execution % Snap Total
Elapsed Time (ms) 2,997,435 187,339.68 53.56
CPU Time (ms) 2,896,748 181,046.72 65.48
Executions 16    
Buffer Gets 521,592,791 32,599,549.44 69.21
Disk Reads 10,974 685.88 1.12
Parse Calls 1 0.06 0.00
Rows 32,000 2,000.00  
User I/O Wait Time (ms) 2,525    
Cluster Wait Time (ms) 1,146    
Application Wait Time (ms) 4    
Concurrency Wait Time (ms) 1    
Invalidations 0    
Version Count 1    
Sharable Mem(KB) 51    

Back to Plan 1(PHV: 3689516641)

Execution Plan

Id Operation Name Rows Bytes Cost (%CPU) Time Pstart Pstop
0 UPDATE STATEMENT       16798 (100)      
1    UPDATE CONTACT            
2      PARTITION RANGE ALL   1 51 16798 (1) 00:00:01 1 1048575
3        PARTITION HASH SINGLE   1 51 16798 (1) 00:00:01 KEY KEY
4          TABLE ACCESS FULL CONTACT 1 51 16798 (1) 00:00:01    

表数据量非常大,根据created_date时间字段分区,ID字段进行子hash分区,上面建立了基于ID字段的global hash分区索引。

从上面情况看出,原始SQL分批2000个ID进行批量update,但执行计划走的是TABLE ACCESS FULL, 并且进行了分区的PRATITION RANGE ALL操作,可以看出2000条记录的批量更新由于不能利用global hash分区索引进行检索,主要原因是由于hash分区适用于等值操作,对于范围或者批量操作,可能遍历很多hash分区,导致结果不如TABLE ACCESS FULL。

针对这种情况,根据业务逻辑,将批量条件从ID改成其他非global hash索引列,执行时间降低为5分钟。

  1. CREATE OR REPLACE PROCEDURE sp_upd_suppressed_emails
    (
    A_LIMIT_BULK IN PLS_INTEGER DEFAULT 2000,
    A_COMMIT_AFTER IN PLS_INTEGER DEFAULT 2000
    ) is
  2.  
  3. v_operation Varchar2(20) := 'START';
    v_last PLS_INTEGER;
    v_start PLS_INTEGER;
    v_end PLS_INTEGER;
    l_row PLS_INTEGER;
  4.  
  5. CURSOR curs_contact IS SELECT distinct email FROM contact
    WHERE active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y'
    and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') )
    and email is not null ORDER BY email;
  6.  
  7. TYPE contactId IS RECORD ( email contact.email%TYPE);
  8.  
  9. TYPE v_contactId_tbl IS TABLE OF contactId INDEX BY PLS_INTEGER;
  10.  
  11. v_contact v_contactId_tbl;
  12.  
  13. v_upd_date date ;
  14.  
  15. BEGIN
  16.  
  17. DBMS_OUTPUT.PUT_LINE ('start reading data..' );
    v_operation := 'BEFORE OPEN';
  18.  
  19. select sysdate into v_upd_date from dual;
  20.  
  21. OPEN curs_contact;
  22.  
  23. LOOP
  24.  
  25. v_operation := 'BEFORE FETCH';
    FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK;
    v_operation := 'AFTER FETCH';
  26.  
  27. EXIT WHEN v_contact.COUNT = 0;
  28.  
  29. v_start := 1;
    v_last := v_contact.COUNT;
    l_row := 0;
  30.  
  31. LOOP
    DBMS_OUTPUT.PUT_LINE ('LOOP 2 top ');
    EXIT WHEN v_start > v_last;
    v_end := LEAST (v_start + A_COMMIT_AFTER - 1, v_last);
    DBMS_OUTPUT.PUT_LINE ('LOOP 2 v_start ' || v_start || ' end ' || v_end );
    BEGIN
    v_operation := 'UPDATE_LOAD';
    FORALL i IN v_start .. v_end
    UPDATE contact SET active_ind = 1, suppress_flag = 'N', bounce_flag = 'N' , modified_date = v_upd_date
    WHERE email = v_contact (i).email
    and active_ind = 2 and suppress_flag = 'Y' and bounce_flag = 'Y'
    and consumer_id in (select id from consumers where login_name IN ('ASPIRAFOCUS', 'CDFW', 'PSACSFSUSR') ) ;
    END;
    DBMS_OUTPUT.PUT_LINE ('after forall start ' || v_start || ' end ' || v_end );
    COMMIT;
    v_start := v_end + 1;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE ('LOOP 2 bottom v_start ' || v_start || ' end ' || v_end );
    COMMIT;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE ('stop reading data..' );
  32.  
  33. EXCEPTION
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE ('Exception:Others-> v_operation = ' || v_operation || ', rowcount # ' || l_row || ' SQLCODE ' || SQLCODE || ' ERR_MSG = ' || SUBSTR(SQLERRM, 1, 500) );
  34.  
  35. END sp_upd_suppressed_emails;

记一次全局分区索引update调优的更多相关文章

  1. Oracle非分区索引,全局分区索引和本地分区索引。

    1.如果按照索引是否分区作为划分依据,Oracle 的索引类型可以分为非分区索引,全局分区索引和本地分区索引. 2.创建演示实例 --创建非分区表create table test_partition ...

  2. 【Kafka】Kafka-副本-分区设置-性能调优

    Kafka-副本-分区设置-性能调优 SparkKafkaDemo - Executors kafka replication 负载均衡_百度搜索 Kafka 高性能吞吐揭秘 - 友盟博客 - Seg ...

  3. Day 18: 记filebeat内存泄漏问题分析及调优

    ELK 从发布5.0之后加入了beats套件之后,就改名叫做elastic stack了.beats是一组轻量级的软件,给我们提供了简便,快捷的方式来实时收集.丰富更多的数据用以支撑我们的分析.但由于 ...

  4. Spark踩坑记:Spark Streaming+kafka应用及调优

    前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从k ...

  5. 记Oracle中regexp_substr的一次调优(速度提高95.5%)

    项目中需要做一个船舶代理费的功能,针对代理的船进行收费,那么该功能的第一步便是选择进行代理费用信息的录入,在进行船舶选择的时候,发现加载相关船舶信息十分的慢,其主要在sql语句的执行,因为测试的时候数 ...

  6. 记一次Web服务的性能调优

    前言 一个项目在经历开发.测试.上线后,当时的用户规模还比较小,所以刚刚上线的项目一般会表现稳定.但是随着时间的推移,用户数量的增加,qps的增加等因素会造成项目慢慢表现出网页半天无响应的状况.在之前 ...

  7. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  8. Atitit.分区对索引的影响 分区索引和全局索引 attilax总结

    Atitit.分区对索引的影响 分区索引和全局索引 attilax总结 1. 分区的好处1 2. 分区键:2 3. 分区的建议:2 4. 分区索引和全局索引:2 5. 全局索引就是在全表上创建索引, ...

  9. Oracle分区索引

    索引与表类似,也可以分区: 分区索引分为两类: Locally partitioned index(局部分区索引) Globally partitioned index(全局分区索引) 下面就来详细解 ...

随机推荐

  1. py3 base64加密

    import base64 #字符串编码: encodestr = base64.b64encode('abcr34r344r'.encode('utf-8')) print(str(encodest ...

  2. 元素定位--firebug安装

    1.火狐浏览器调试工具firebug插件的安装 打开浏览器---添加组件---搜索firebug

  3. RocketMQ吐血总结

    RocketMQ吐血总结 架构 概念模型 最基本的概念模型与扩展后段概念模型 存储模型 RocketMQ吐血总结 User Guide RocketMQ是一款分布式消息中间件,最初是由阿里巴巴消息中间 ...

  4. 解决jenkins的Console Output中文乱码

    1.本地机器设置环境变量(设置后需要注销计算机才能生效) key: JAVA_TOOL_OPTIONS value:-Dfile.encoding=UTF- 2. 通过Jenkins全局设置的方式   ...

  5. wex5 如何在js中给data添加数据

    var options = { defaultValues :[ {'xuetang' : xuetang,'time' : time} ] }; this.comp("xuetangDat ...

  6. css练习小总结

    1.div水平居中:/*设置div宽度后,margin:0 auto:*/2.div显示在一行:/*float:left:*/ 3.text-align:/*后面标签里的内容水平居中:*/4.alig ...

  7. chrome插件2

    转自:http://www.codeceo.com/article/15-chrome-extension.html 1. Web Developer 支持Chrome的Web Developer扩展 ...

  8. vue.js(2)--v-cloak v-text v-html

    v-cloak v-text  v-html的使用 (1)实例 <!DOCTYPE html> <html lang="en"> <head> ...

  9. MySQL第三讲 一一一一 视图、触发器、函数、存储过程

    1. 视图 1.1 视图前戏 我们之前讲有,临时表的概念. 现在我们创建一个临时表:select * from (select * from tb1 where id between 10 and 1 ...

  10. 日语能力测试N1、N2级听力必备核心词汇—头发篇

    日语能力测试N1.N2级听力必备核心词汇—头发篇 要想在短时间内迅速提高日语听力能力的水平,除了每天练习(用2倍的速度)真题之外,掌握听力的核心词汇也是一个必要的好方法. 髪(かみ)--头发髪型(かみ ...