记一次全局分区索引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(全局分区索引) 下面就来详细解 ...
随机推荐
- python 绘制对象检测框及中文信息标注
# 坐标顺序: 上->左->下->右 def draw_bounding_box_on_image(image, ymin, xmin, ymax, xmax, color='red ...
- 2019-11-29-dotnet-使用-Qpush-快速从电脑到手机推送文字
title author date CreateTime categories dotnet 使用 Qpush 快速从电脑到手机推送文字 lindexi 2019-11-29 08:58:57 +08 ...
- Django的MTV模型
MTV模型 Django框架的设计模式借鉴了MVC框架的思想,也是分成三部分,来降低各个部分之间的耦合性. MTV框架是Django的框架,三部分为: Model Template(模板) View ...
- Python控制语句执行流程
if语句: if<条件>:#条件之后必须有“:”. <语句> if语句的三元运算符: <表达式1>if<条件>else<表达式2>:其语义 ...
- 从安装 centos 到运行 laravel 的配置
# 安装 centos cd /etc/sysconfig/network-scripts/ vi ifcfg-xxx # 修改 ONBOOT="no" 为 "yes&q ...
- Ubuntu换阿里云源
sudo -s cd /etc/apt gedit source.list deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted u ...
- linux 走三层内网添加静态路由
/etc/sysconfig/network-scripts/ifcfg-eth1 #机器1ip route add 10.24.4.0/24 via 10.90.203.1 dev ens33/et ...
- CSS3 transform 属性 旋转 div 元素
div { transform:rotate(7deg); -ms-transform:rotate(7deg); /* IE 9 */ -moz-transform:rotate(7deg); /* ...
- Codeforces 967 贪心服务器分配资源 线性基XOR递增序列构造
A #include<bits/stdc++.h> using namespace std; ][] = {{, -}, {, }, { -, }, {, }}; typedef long ...
- Python核心编程正则表达式练习题1-1 识别后续的字符串:“bat”、“bit”、“but”、“hat”、“hit”或者“hut”
# 1-1 识别后续的字符串:“bat”.“bit”.“but”.“hat”.“hit”或者“hut”. import re # 正则表达式,|元字符表示选择“或” # character = 'ba ...