OGG复制进程延迟高,优化方法二(存在索引),SQL选择不好的索引
https://www.cnblogs.com/lvcha001/p/13469500.html
接前序,本次场景中有索引,但是OGG复制进程使用了低效率的索引? 类似SQL使用低效索引,如何让Oracle使用好的索引,从而加快复制进程的效率呢?
疑问? Oracle为什么有好的索引,但是还是选择不好的索引,从而造成SQL效率低下,OGG复制进程缓慢呢?
本次DB版本11g,都是CBO,基于成本进行计算。
1.重新收集统计信息,让Oracle自动选择好的索引,走好的执行计划,从而让OGG复制进程同步速度加快;
2.可以使用绑定执行计划,因为生产环境中大表经常收集统计信息不靠谱,因此绑定执行计划的选择性更好。
根据基于Oracle的SQL优化一书中,绑定执行计划有三种情况:
1.使用SQL Profile手工进行绑定执行计划;
2.使用Oracle 11g后推出的SQL分析工具后,根据提示绑定执行计划;
3.使用Oracle 11g后推出的SQM 手工绑定执行计划。
一、收集统计信息,从而让SQL使用好的执行计划
1.1 OGG进程延迟,追踪定位慢SQL ,或者说定位OGG复制进程慢在什么地方。
查询进程延迟
ogg>info all
REPLICAT RUNNING R064 :: :: $ ps -ef|grep R064
oracle Jul31 ? :: /ogg/replicat PARAMFILE /ogg/dirprm/r064.prm REPORTFILE /ogg/dirrpt/R064.rpt PROCESSID R064
USESUBDIRS
$ ps -ef|grep
oracle Jul31 ? :: /ogg/replicat PARAMFILE /ogg/dirprm/r064.prm REPORTFILE /ogg/dirrpt/R064.rpt PROCESSID R064
USESUBDIRS
oracle Jul31 ? -:: oracxxx2 (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq))) select s.sid,s.serial#,sql_id,p.program from v$process p,v$session s where p.addr=s.paddr and p.spid=;
SID SERIAL#
---------- ----------
检查是否存在异常event,阻塞等异常情况,null,基本说明是SQL执行效率问题。
select sql_id,SQL_PLAN_HASH_VALUE,event,BLOCKING_SESSION,CURRENT_OBJ#,count(*) from v$active_session_history where SAMPLE_TIME>sysdate-1 and SESSION_ID=2521 and SESSION_SERIAL#=7
group by sql_id,SQL_PLAN_HASH_VALUE,event,BLOCKING_SESSION,CURRENT_OBJ# order by 6,5;
2mgbv3kv27j1u 122754776 -1 1016
9gwf6964729pb 122754776 -1 1565
f5wzbp6ukpgyb 122754776 -1 19809
35a1j6rvxxq25 122754776 -1 24694
7hqzr0xnw1dzn 122754776 -1 32829
select sql_id,SQL_PLAN_HASH_VALUE,count(*) from v$active_session_history where SAMPLE_TIME>sysdate-1 and SESSION_ID=2521 and SESSION_SERIAL#=7
group by sql_id,SQL_PLAN_HASH_VALUE order by 3,1,2;
SQL_ID SQL_PLAN_HASH_VALUE COUNT(*)
------------- ------------------- ----------
9r3gsjgu643vc 1485047805 1
dhhn34zjdswwm 1485047805 2
51rz0rnxn6h63 1485047805 10
dmddfppkdjm3j 122754776 30
9qmjbmy368dt6 122754776 32
gxt936qxcskus 122754776 80
13cyznw9s3k22 122754776 82
7yf333kq4tsug 122754776 188
8ag1chwapa6g5 1485047805 197
cc22d5nz8us4n 1485047805 281
4ryk8q58djv4k 122754776 812
2mgbv3kv27j1u 122754776 1068
9gwf6964729pb 122754776 1640
f5wzbp6ukpgyb 122754776 20649
35a1j6rvxxq25 122754776 26210
7hqzr0xnw1dzn 122754776 34301 基本上就是这三个SQL导致这个OGG复制进程延迟很高,缓慢的问题。
检查SQL对应的SQL文本对象,及执行计划
select * from table(dbms_xplan.display_cursor('7hqzr0xnw1dzn'));
Plan hash value: 122754776
------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | | | 4 (100)| | | |
| 1 | DELETE | S_OTHER | | | | | | |
|* 2 | COUNT STOPKEY | | | | | | | |
| 3 | PARTITION RANGE SINGLE | | 1 | 150 | 4 (0)| 00:00:01 | KEY | KEY |
|* 4 | TABLE ACCESS BY LOCAL INDEX ROWID| S_OTHER | 1 | 150 | 4 (0)| 00:00:01 | KEY | KEY |
|* 5 | INDEX RANGE SCAN | IDX_S_OTHER_DATE | 1 | | 3 (0)| 00:00:01 | KEY | KEY |
------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM=1)
4 - filter(("TIME" IS NULL AND "TIME1"=:B1 AND "DATA1"=:B38 and ······
5 - access("STAT_DATE"=:B0 AND "STATTYPE"=:B5)
三条SQL涉及的对象一致,只是update or delete 少量差异,基本上都是一样的。可以发现SQL已经走了索引
1.2 检查SQL统计信息,对象涉及的索引及索引列的选择性。
--最消耗时间的执行计划步骤
select
inst_id,sql_plan_hash_value,sql_plan_line_id,
sql_plan_operation,sql_plan_options,event,
count(*) cnt
from gv$active_session_history
where sql_id='7hqzr0xnw1dzn' and
sample_time >sysdate-/
group by
inst_id,sql_plan_hash_value,sql_plan_line_id,
sql_plan_operation,sql_plan_options,event
order by count(*) ;
INST_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID SQL_PLAN_OPERATION SQL_PLAN_OPTIONS EVENT CNT
---------- ------------------- ---------------- ------------------------------ ------------------------------ -------------------- ----------
INDEX RANGE SCAN
TABLE ACCESS BY LOCAL INDEX ROWID 10194
慢在回表,说明SQL通过索引获取到非常多的ROWID,但是我们都知道SQL 文本最后有ROWNUM=1,因此可以说明SQL实际涉及一行记录,但是SQL通过索引访问获取到N条>>1条记录,索引选择性很差。
select owner,object_name,object_type from dba_objects where object_name='S_OTHER';
OWNER OBJECT_NAME OBJECT_TYPE
------------------------------ ------------------------------------------
A S_OTHER TABLE PARTITION
select index_owner,index_name,table_name,column_name,column_position from dba_ind_columns where table_name='S_OTHER' order by index_name,column_position;
INDEX_OWNER INDEX_NAME COLUMN_NAME COLUMN_POSITION
------------------------------ ----------- -------
REP IDX_S_OTHER_DATE A_DATE 1
REP IDX_S_OTHER_DATE STYPE 2
REP IDX_S_OTHER_DATE S_DATE 1
REP IDX_S_OTHER_DATE STYPE1 2
可以发现,SQL选择的执行计划索引,对应有4个列
另一个索引是全列索引!!! 25个列,虽然有点。。。。不靠谱,但是根据rowunum=1的方式,我们可以认为这个索引等同于一个IOT表。因此实际的访问效率肯定是> 上面的慢索引。
select OWNER,TABLE_NAME,COLUMN_NAME,NUM_DISTINCT,NUM_NULLS,to_char(LAST_ANALYZED,'yyyy-mm-dd hh24') as "date" from dba_tab_col_statistics where table_name='S_ST_BUSI_OTHER' order by column_name;
可以发现统计信息都是19年2月份,慢索引的四个列,NUM_DISTINCT分别为 1200,700,2,3 因此组合索引效率并不高!!!
select segment_name,sum(bytes)/1024/1024/1024 from dba_segments where owner='REP' and segment_name='S_OTHER' group by segment_name;
SEGMENT_NAME SUM(BYTES)/1024/1024/1024
--------------------------------------------------------------------------------- -------------------------
S_OTHER 15.5256958
1.3 收集统计信息,观察执行计划
exec dbms_stats.gather_table_stats(ownname=>'R',tabname=>'S_OTHER',cascade=>true,degree=>,estimate_percent=>);
检查执行计划是否改变!!! 这里有个小细节,如果SQL执行效率很高,非常可能无法在cursor观察到。
select * from table(dbms_xplan.display_cursor('35a1j6rvxxq25'));
本次未看到执行计划改变!!!???? 没效果???
通过ASH视图查询 SQL_ID 的执行计划。
--最消耗时间的执行计划步骤
select
inst_id,sql_plan_hash_value,sql_plan_line_id,
sql_plan_operation,sql_plan_options,event,
count(*) cnt
from gv$active_session_history
where sql_id='7hqzr0xnw1dzn' and
sample_time >sysdate-2/24
group by
inst_id,sql_plan_hash_value,sql_plan_line_id,
sql_plan_operation,sql_plan_options,event
order by count(*) ;
INST_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID SQL_PLAN_OPERATION SQL_PLAN_OPTIONS EVENT CNT
---------- ------------------- ---------------- ------------------------------ ------------------------------ -------------------- ----------
2 122754776 5 INDEX RANGE SCAN 4013
2 122754776 4 TABLE ACCESS BY LOCAL INDEX ROWID 10194
收集统计信息后
INST_ID SQL_PLAN_HASH_VALUE SQL_PLAN_LINE_ID SQL_PLAN_OPERATION SQL_PLAN_OPTIONS EVENT CNT
---------- ------------------- ---------------- ------------------------------ -------------
2 122754776 1 DELETE log file sync 4
2 122754776 0 DELETE STATEMENT 5
2 11252613 1 DELETE 6 执行计划发生改变,并且cnt数量很低,说明效率很OK
2 122754776 1 DELETE 14
2 122754776 5 INDEX RANGE SCAN 3148
2 122754776 4 TABLE ACCESS BY LOCAL INDEX ROWID 8293
使用SQL脚本对比SQL执行效率,提升了4倍的访问效率。
二、绑定执行计划,从而让SQL使用好的执行计划
2.1 定位问题SQL,与上面套路一样
select sql_id,SQL_PLAN_HASH_VALUE,event,BLOCKING_SESSION,CURRENT_OBJ#,count(*) from v$active_session_history where SAMPLE_TIME>sysdate-
and SESSION_ID= and SESSION_SERIAL#=
group by sql_id,SQL_PLAN_HASH_VALUE,event,BLOCKING_SESSION,CURRENT_OBJ# order by ,;
1wcqwzmn1mw6b 3794392338
观察执行计划 走 TABLE ACCESS BY LOCAL INDEX ROWID| S_DAY 索引。 与上面的例子类似,唯一不同的就是换了个用户,换了一个表名称。
2.2 绑定执行计划
.获得好的执行计划
由于SQL只有一个执行计划,并没有我们希望的走全列索引的执行计划。
因此第一步骤需要制造一个好的执行计划,可以使用explan
EXPLAIN PLAN FOR SELECT /* test_sql_20200828 */ * FROM T_USER where id= status= ......选择了4个好的列,及distinct较多的列,作为where条件 and rownum=;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
可以得到希望得到的执行计划。 .查询好的执行计划 sql_id, hash_plan
可以通过v$sql SQL_ID SQL_TEXT PLAN_HASH_VALUE 定位获得需要的信息。 这里有一个疑问???
假设我们explain plan for 的SQL条件是WHERE 4个列?
那么绑定执行计划后,走全列索引20个列,那么绑定后的执行计划中access 是4个列?filter 是其它条件20个列? 还是 access 是索引20个列,filter 是表中不包含索引列的信息。 这个疑问代表如果假设Oracle绑定后,access 选择4个列,说明Oracle是一个错误的执行计划,那样filter 需要排除16个列,甚至20个列,SQL效率低下;
如果假设access 选择4个列,filter rownum= 没有其它条件,严格与绑定的模板或者说好的执行计划步骤走,甚至得到的结果都可以理解为错误的??? 条件变少了!!!
有兴趣的朋友可以测试下,不在啰嗦。 测试结果为access索引全列+ filter rownum=,因此oracle 还是很聪明的。
2.3 固定执行计划
--绑定执行计划 declare
m_clob clob;
begin
select sql_fullteXt
into m_clob
from v$sql
where sql_id = '6up8w69qu5y98' --慢SQL需要优化的SQL_id
and child_number = ;
dbms_output.put_line(m_clob);
dbms_output.put_line(dbms_spm.load_plans_from_cursor_cache(sql_id => '6up8w69qu5666', --选择好的执行计划对应的SQL_ID,可以不一样
plan_hash_value => , --选择好的执行计划对应的plan_value
sql_text => m_clob,
fixed => 'YES',
enabled => 'YES')); end;
/
==如下可以查询绑定执行计划后的信息,如果有问题可以参考如下删除。
SELECT SQL_HANDLE,PLAN_NAME,ORIGIN FROM DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE '%WF_H_WorkItem%';
SQL_HANDLE PLAN_NAME ORIGIN
------------------------------------------------------------
SQL_6e591e5940320852 SQL_PLAN_6wq8yb503422k0e58574a MANUAL-LOAD
VAR TEMP NUMBER;
BEGIN
:TEMP:=DBMS_SPM.DROP_SQL_PLAN_BASELINE(SQL_HANDLE=>'SQL_6e591e5940320852',PLAN_NAME=>NULL);
END;
/
SQL> SELECT SQL_HANDLE,PLAN_NAME,ORIGIN FROM DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE '%WF_H_WorkItem%';
no rows selected
2.4 如何让SQL重新硬解析我们经常可以发现,绑定执行计划或者收集统计信息后。 SQL执行计划不变???
.Oracle默认收集统计信息,是oracle自行判断,什么时候让SQL原有的执行计划失效,从而后续涉及的对象下一次SQL执行硬解析;
.那我们如何手工让SQL 硬解析呢??? 前提条件,执行慢的SQL需要暂停执行,我们能改变的是新的SQL,而非现有正在执行慢的SQL;
OGG需要stop 涉及的进程。 .对对象进行DDL操作
举例说明
alter table a modify status varchar2(); 表字段长度更新(慎重)
表别名,列别名修改。 可以使用plsql修改建议 -- 设置表别名
COMMENT ON TABLE EMPLOYEE is '雇员';
--设置字段别名
COMMENT ON COLUMN PRODUCT.PRODUCT_CLASS_ID IS '产品分类代码';
参考http://blog.itpub.net/106943/viewspace-1005783/ 别名修改,比较好用,plsql改下就行,业务高峰期不要操作。 .清空sql涉及的共享池 参考
https://zm.sm-tc.cn/?src=l4uLj4zF0NCIiIjRk5aRioeWm5zRnJCS0LOWkYqH0M3PzsjSz8zQzsvOysbH0ZeLkg%3D%3D&uid=06b807ecd1b8ae1f4a368a691fabd3eb&hid=
305572c2dd05de2fc54a7211940a4021&pos=1&cid=9&time=1597929982090&from=click&restype=1&pagetype=0000804000000402&bu=ss_doc&query=Oracle%E6%B8%85%E7
%A9%BAsql+%E5%AF%B9%E5%BA%94%E7%9A%84shared+pool.%E5%9C%B0%E5%9D%80&mode=&v=1&province=%E5%A4%A9%E6%B4%A5%E5%B8%82&city=%E5%A4%A9%E6%B4%A5%E5%B8%8
2&uc_param_str=dnntnwvepffrgibijbprsvdsdichei zx@MYDB>select sql_text,sql_id,version_count,executions,OBJECT_STATUS,address,hash_value from v$sqlarea where sql_text like 'select object_name
from s%';
SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS OBJECT_STATUS ADDRESS HASH_VALUE
------------------------------------------------------------ --------------------------------------- ------------- ---------- ---------------
select object_name from s1 where object_id= 1s45nwjtws2tj VALID 00000000B4F85A18
select object_name from s1 where object_id= 1hdyqyxhtavqs VALID 00000000BE7E56C8 现在要删除object_id=20对应的SQL缓存的执行计划和解析树。 zx@MYDB>exec sys.dbms_shared_pool.purge('00000000B4F85A18,1942752049','C');
PL/SQL procedure successfully completed.
zx@MYDB>select sql_text,sql_id,version_count,executions,OBJECT_STATUS,address,hash_value from v$sqlarea where sql_text
like 'select object_name from s%';
SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS OBJECT_STATUS ADDRESS HASH_VALUE
------------------------------------------------------------ --------------------------------------- ------------- ---------- ------
select object_name from s1 where object_id= 1hdyqyxhtavqs VALID 00000000BE7E56C8 从输出可以看出object_id=20对应的SQL缓存的执行计划和解析树被删除了,而object_id=30对应的SQL的执行计划没有受影响。 需要注意的是,如果在10.2.0.4中使用dbms_shared_pool.purge,则在使用之前必须特工设置event (alter session set events '5614566 trace
name context forever'),否则dbms_shared_pool.purge将不起作用,这个限制在10.2.0.4以上的版本中已经不存在了。
如果默认没有安装dbms_shared_pool包的可以执行@?/rdbms/admin/dbmspool.sql .收集统计信息的时候使用参数
exec dbms_stats.gather_index_stats(ownname=>'R',indname=>'IDX_DATE',degree=>,estimate_percent=>,no_invalidate=>false);
由于收集表及索引统计信息时间太长,因此可以选择收集你想要的的索引单个统计信息。使用参数也是可以的。 如果只是为了加快时间,可以考虑,estimate_percent 采样比例使用0. 之类很小的值,应该是秒级别。 目的可以快速让对象涉及的SQL都硬解析,但是不好的地方在于,
oracle收集统计信息后会更新对象统计信息值,使用过低的比例,值不准确,可能影响其他的SQL。 但是如果SQL基本都是绑定执行计划可以忽略。
OGG复制进程延迟高,优化方法二(存在索引),SQL选择不好的索引的更多相关文章
- OGG复制进程延迟高,优化方法一(使用索引)
日常运维过程中,可能发现OGG同步进程延迟很高: 本篇介绍其中的一种方式. OGG复制进程,或者说同步进程及通过解析ogg trail文件,输出dml语句,在目标库执行dml操作,那么延迟高可能性其一 ...
- OGG复制进程延迟不断增长
1.注意通过进程查找sql_id时,进程号要查询两次 2.杀进程的连接 https://www.cnblogs.com/kerrycode/p/4034231.html 参考资料 1.https:// ...
- MySQL性能优化方法二:表结构优化
原文链接:http://isky000.com/database/mysql-perfornamce-tuning-schema 很多人都将 数据库设计范式 作为数据库表结构设计“圣经”,认为只要按照 ...
- 【译】索引进阶(十二):SQL SERVER中的索引碎片【中篇】
原文链接:传送门. 为了讨论碎片产生的原因,以及避免和移除索引碎片的技术,我们必须从本进阶系列后续将介绍的两个章节借用一些知识点:创建/更新索引的知识,以及向一个索引表插入数据行的相关知识. 当我们讲 ...
- Java Web 前端高性能优化(二)
一.上文回顾 上回我们主要从图片的合并.压缩等方面介绍前端性能优化问题(详见Java Web 前端高性能优化(一)) 本次我们主要从图像BASE64 编码.GZIP压缩.懒加载与预加载以及 OneAP ...
- OGG复制同步,提示字段长度不够ORA-01704
日常运维OGG的环境中,如果遇到复制进程报错,提示字段长度不足如何处理??? 正常情况下,字段长度不足,但是未达到Oracle的限制时,可以对字段进行扩大限制满足目的. 实际环境中,遇到源端GBK,目 ...
- OGG投递进程报错无法open文件,无法正常投递
1.1现象 之前有个客户遇到一个问题,OGG同步数据链路,突然有一天网络出现问题,导致OGG投递进程无法正常投递,无法写入目标端的该文件. 猜测是由于网络丢包等原因导致文件损坏,无法正常open,re ...
- Oracle SQL语句性能优化方法大全
Oracle SQL语句性能优化方法大全 下面列举一些工作中常常会碰到的Oracle的SQL语句优化方法: 1.SQL语句尽量用大写的: 因为oracle总是先解析SQL语句,把小写的字母转换成大写的 ...
- SQL语句优化方法30例
1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化. 例如: SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_I ...
随机推荐
- PHP 是什么?简介下
PHP 是服务器端脚本语言. 您应当具备的基础知识 在继续学习之前,您需要对以下知识有基本的了解: HTML CSS PHP 是什么? PHP(全称:PHP:Hypertext Preprocesso ...
- PHP end() 函数
实例 输出数组中的当前元素和最后一个元素的值: <?php$people = array("Peter", "Joe", "Glenn" ...
- PHP xml_set_external_entity_ref_handler() 函数
定义和用法 xml_set_external_entity_ref_handler() 函数规定当解析器在 XML 文档中找到外部实体时被调用的函数. 如果成功,该函数则返回 TRUE.如果失败,则返 ...
- Python datetime 转 JSON
Python datetime 转 JSON Python 中将 datetime 转换为 JSON 类型,在使用 Django 时遇到的问题. 环境: Python2.7 代码: import js ...
- three.js 着色器材质之变量(三)
这篇郭先生在练习一下着色器变量,在度娘上面或者官网上经常看到类似水波一样的效果,这篇就试着做一个这样的效果,顺便巩固一下顶点着色器和片元着色器,毕竟多多练习才能更好地掌握.效果如下图,在线案例请点击博 ...
- 综合CSS3 transition、transform、animation写的一个动画导航
打算好好写博客开始,就想把博客给装修下,近几个月一直处在准备找工作疯狂学习前端的状态.感觉博客装修要等到工作稳定下来才有时间和经历去想想要搞成什么样的了.也看过一些博主的博客导航有这种样式的,趁着回顾 ...
- MySQL数据库安装,MySQL数据库库的增删改查,表的增删改查,表数据的基本数据类型
一 MySQL的安装 MySQL现在属于甲骨文公司,所以和java语言匹配度较高,同时甲骨文公司的另一种数据库为Oracle,两者同为关系型数据库,即采用关系模型来组织数据,以行和列的方法来存储数据的 ...
- 5招详解linux之openEuler /centos7防火墙基本使用指南
防火墙是一种防火墙管理解决方案,可用于许多 Linux 发行版,它充当 Linux 内核提供的 iptables 数据包筛选系统的前端.在本指南中,将介绍如何为服务器设置防火墙,并向你展示使用管理工具 ...
- 关于Hexo,Next主题的‘下一页’、‘上一页’按钮错误显示为html代码 的解决方法
关于Next主题的'下一页'.'上一页'按钮错误显示为html代码的解决方法 我在建立自己的博客过程中遇到了页面'下一页'和'上一页'按钮显示为html代码<i class="fa f ...
- matlab使用libsvm入门教程——使用matlab安装配置libsvm以及一个svm分类实例
前言 此教程专注于刚入门的小白, 且博客拥有时效性, 发布于2019年3月份, 可能后面的读者会发现一些问题, 欢迎底下评论出现的问题,我将尽可能更新解决方案. 我开始也在如何安装libsvm上出现了 ...