记一次全局分区索引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(全局分区索引) 下面就来详细解 ...
随机推荐
- P4868 Preprefix sum
传送门 挺显然的一题?单点修改,前缀和数组前缀查询 树状数组就可以维护了 考虑每个位置对应询问的贡献,设询问的位置为 $x$,对于原数组 $a[i]$ 的某个位置 $i$,它会贡献 $(x-i+1)* ...
- 简单CSS实现闪烁动画(+1白话讲解)
原文:简单CSS实现闪烁动画(+1白话讲解) 本文转载于:猿2048网站⇒https://www.mk2048.com/blog/blog.php?id=icj2chj2ab 背景 本文承接自上文&l ...
- grunt接触
grunt使用 以下内容均为已经安装好grunt,具体grunt的安装过程不述,可以参考grunt的相关资料. 1.项目初始化grunt 在项目文件夹的根目录下面,打开命令行grunt init,执行 ...
- shell统计mysql当前连接数
[root@push-- scripts]# mysql -S /var/lib/mysql//mysql.sock -uroot -phlsms_push_Zaq1xsw@ -e "sho ...
- mongodb,robomongo 数据查询
可视化管理工具:Robomongo 是开源,免费的MongoDB管理工具,下载地址:Robomongo下载 1. 基本查询: 构造查询数据. > db.test.findOne() ...
- nslookup 工具的使用方法记录
查询IP地址 nslookup最简单的用法就是查询域名对应的IP地址,包括A记录和CNAME记录,如果查到的是CNAME记录还会返回别名记录的设置情况.其用法是: nslookup 域名 定查询记录类 ...
- 如何代替set get方法
博主刚刚看其他人的博客的时候,发现好多人还在用 生成set get方法 虽然是自动生成的 但是看起来很复杂,影响代码的可读性 那么有什么办法能代替set get方法吗? 当然有啦!!! 只需要导入 ...
- bootstrap-table(2)问题集
参考;https://www.cnblogs.com/landeanfen/p/4993979.html 1.分页参数sidePagination 如果是服务端分页,返回的结果必须包含total.ro ...
- LNMP 多版本PHP同时运行
首先需要装好两个版本以上的PHP(例如:php5.6和php7两个版本).这里假设你已安装完成.1.配置并启动php默认版本: (设置 nginx 的 vhost 域名配置文件监听端口就好) 1).打 ...
- mysql:You can't specify target table 'sessions' for update in FROM clause
更新数据时,在where条件子句里面如果想使用子查询按条件更新部分数据,需要将查询的结果设为临时表.可以参考: https://blog.csdn.net/poetssociety/article/d ...