原始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. php多域名单站点路由

    能够使多域名但是只有一个站点的小站,通过路由访问到各个指定目录 <?php //域名跳转路由 //默认跳转 $default = "http://www.stanwind.com/in ...

  2. 重写移动端滚动条[iScroll.js核心代码]

    最近写组件库的时后,发现这个滚动条是真的丑啊,决定重新撸一个滚动条: 首先咱们回顾一下移动端浏览器滚动条特性: 滚动条在开始滚动时渐显,滚动结束后渐隐 滚动条不占内容区宽度,悬浮固定 滚动条高度(深灰 ...

  3. RabbitMQ入门教程(三):Hello World

    原文:RabbitMQ入门教程(三):Hello World 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog. ...

  4. __main__ 变量

    1. 摘要 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明'):在你自己眼中,你是你自己(__name__ == '_ ...

  5. JVM常用虚拟机命令汇总

    title: JVM常用虚拟机命令汇总 comments: false date: 2019-07-22 11:45:33 description: 总结一下常用的JVM虚拟机启动命令. catego ...

  6. 修改文件夹的所有者为www

    切换到root用户:su - root 修改文件所属用户和用户组:chown 用户:用户组 文件名如果用户和用户组是www,那么需要执行命令如下:chown www:www filename -R ( ...

  7. linux ssh连接超时断连设置

    以下均针对redhat6.5系统进行说明. 一.设置ssh超时断连 使用root用户,编辑/etc/profile文件,在 HOSTNAME='/bin/hostname' HISTIZE=30 后增 ...

  8. python打印实心等边三角形和空心等边三角形

    #1 打印实心等边三角形 n = 5 for i in range(1, n+1): # 控制三角形的高,也就是层数 for k in range(2*(n-i)): # 控制每层第一个*的空格,从最 ...

  9. (转) Oracle SQL优化必要的全表扫描思路分析

    大多数情况下,我们需要避免SQL在查询时进行全表扫描(FTS),但是对于必须需要进行全表扫描的情况,也可以进行一些优化处理. 即使全表扫描是检索所需数据的唯一可行方法,仍然有多种方法来提升查询性能.优 ...

  10. Rsync实现负载均衡的数据同步

    使用三台服务器:系统:CentOS 6.8 192.168.8.169 开发服务器 192.168.8.167 线上服务器1192.168.8.168 线上服务器2 实现思路:在开发服务器上制定一个规 ...