记一次全局分区索引update调优
原始SQL:
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 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; LOOP v_operation := 'BEFORE FETCH';
FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK;
v_operation := 'AFTER FETCH'; EXIT WHEN v_contact.COUNT = 0; v_start := 1;
v_last := v_contact.COUNT;
l_row := 0; 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) ); 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分钟。
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 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 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; TYPE contactId IS RECORD ( email contact.email%TYPE); TYPE v_contactId_tbl IS TABLE OF contactId INDEX BY PLS_INTEGER; v_contact v_contactId_tbl; v_upd_date date ; BEGIN DBMS_OUTPUT.PUT_LINE ('start reading data..' );
v_operation := 'BEFORE OPEN'; select sysdate into v_upd_date from dual; OPEN curs_contact; LOOP v_operation := 'BEFORE FETCH';
FETCH curs_contact BULK COLLECT INTO v_contact LIMIT A_LIMIT_BULK;
v_operation := 'AFTER FETCH'; EXIT WHEN v_contact.COUNT = 0; v_start := 1;
v_last := v_contact.COUNT;
l_row := 0; 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..' ); 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) ); END sp_upd_suppressed_emails;
记一次全局分区索引update调优的更多相关文章
- Oracle非分区索引,全局分区索引和本地分区索引。
1.如果按照索引是否分区作为划分依据,Oracle 的索引类型可以分为非分区索引,全局分区索引和本地分区索引. 2.创建演示实例 --创建非分区表create table test_partition ...
- 【Kafka】Kafka-副本-分区设置-性能调优
Kafka-副本-分区设置-性能调优 SparkKafkaDemo - Executors kafka replication 负载均衡_百度搜索 Kafka 高性能吞吐揭秘 - 友盟博客 - Seg ...
- Day 18: 记filebeat内存泄漏问题分析及调优
ELK 从发布5.0之后加入了beats套件之后,就改名叫做elastic stack了.beats是一组轻量级的软件,给我们提供了简便,快捷的方式来实时收集.丰富更多的数据用以支撑我们的分析.但由于 ...
- Spark踩坑记:Spark Streaming+kafka应用及调优
前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从k ...
- 记Oracle中regexp_substr的一次调优(速度提高95.5%)
项目中需要做一个船舶代理费的功能,针对代理的船进行收费,那么该功能的第一步便是选择进行代理费用信息的录入,在进行船舶选择的时候,发现加载相关船舶信息十分的慢,其主要在sql语句的执行,因为测试的时候数 ...
- 记一次Web服务的性能调优
前言 一个项目在经历开发.测试.上线后,当时的用户规模还比较小,所以刚刚上线的项目一般会表现稳定.但是随着时间的推移,用户数量的增加,qps的增加等因素会造成项目慢慢表现出网页半天无响应的状况.在之前 ...
- 记一次tomcat线程创建异常调优:unable to create new native thread
测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...
- Atitit.分区对索引的影响 分区索引和全局索引 attilax总结
Atitit.分区对索引的影响 分区索引和全局索引 attilax总结 1. 分区的好处1 2. 分区键:2 3. 分区的建议:2 4. 分区索引和全局索引:2 5. 全局索引就是在全表上创建索引, ...
- Oracle分区索引
索引与表类似,也可以分区: 分区索引分为两类: Locally partitioned index(局部分区索引) Globally partitioned index(全局分区索引) 下面就来详细解 ...
随机推荐
- layer.prompt绑定确认键
case 'eventkc': top.layer.prompt({ formType: , title: '修改<span style="color:red">' + ...
- Mac中如何高亮显示当前git分支以及相关切换系统默认shell操作
前言 在开发中对于使用git的同学,肯定会需要高亮显示当前分支,我们今天就来说一种最简单的办法,先来看一下效果图 实现 1.安装item2 https://www.iterm2.com 2.安装oh- ...
- wex5 如何在js中给data添加数据
var options = { defaultValues :[ {'xuetang' : xuetang,'time' : time} ] }; this.comp("xuetangDat ...
- vue - helloVue
开始学习vue了 1.数据绑定:{{data}} 2.el属性(挂载对象): el:标签任意(例如:#app,.app,app) 3.data:{} :存放数据. <!DOCTYPE html& ...
- 错误代码errno值的含义
错误代码errno值的含义 查看错误代码errno是调试程序的一个重要方法.当C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义, ...
- SourceTree报错
1.SourceTree 拉取报错 Your local changes to the following files would be overwritten by merge:XXX 原因: 本 ...
- python接口测试中—Requests模块的使用
Requests模块的使用 中文文档API:http://2.python-requests.org/en/master/ 1.发送get.post请求 import requests reponse ...
- Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )
链接:https://ac.nowcoder.com/acm/contest/160/B 来源:牛客网 题目描述 给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符 ...
- 常用命令之------tcpdump
语法: tcpdump [options] [not] proto dir type 案例 tcpdump -i eth0 host 192.168.1.1 and icmp -n -w /tmp/t ...
- MyEclipse使用教程:使用DevStyle增强型启动
[MyEclipse CI 2019.4.0安装包下载] DevStyle不仅仅是一组新的主题,它还包含了一个完全改进的启动体验,拥有更直观的UI,帮助开发人员快速启动IDE.DevStyle作为Ec ...