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 ... 
随机推荐
- 基于 JavaEmail 简单的发送邮件点到点,一对多(图片和附件)之多收件人,多少送人
			if(!StringUtil.isEmpty(message_type_to)){ if (message_type_to.contains(",")) { String[] sp ... 
- 2017面向对象程序设计(Java)第十七周助教工作总结
			本学期已接近尾声,java课程也即将结束.经过一学期的java学习,相信大家已经从最初的懵懂.困惑渐渐的走向了柳暗花明,并对java的体系结构有了更加清晰的认识.但一学期的学习是远远不 ... 
- spring oauth2获取token时WARN:Could not decode JSON for additional information: BaseClientDetails解决办法
			错误描述 简述:oauth_client_details表中additional_information字段默认为null,ClientDetails实体类中类型为Map<String,Obje ... 
- spring data jpa 之 通用接口
			园主这一阵子接到一个需求,就是将spring data jpa再进行封装,实现通过调用一个baseRepository,来实现每个类的增删改查操作,结合spring data jpa 原有的便捷操作, ... 
- 【API进阶之路】无法想象!大龄码农的硬盘里有这么多宝藏
			摘要:通过把所需建立的工具库做成云容器化应用,用CCE引擎,通过API网关调用云容器引擎中的容器应用.不仅顺应了云原生的发展趋势,还能随时弹性扩容,满足公司规模化发展的需求. 公司开完年中会后,大家的 ... 
- Go 语言中,有时 nil 并不是一个 nil
			今天,我遇到了一个 Go FAQ.首先,作为一个小小的 Go 语言测验,看看您是否在 Go playground 中运行该程序之前就能推断出它应该打印出的内容(我已经将程序放在侧边栏中,以防它在 Go ... 
- .Net微服务实战之Kubernetes的搭建与使用
			系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) .Net微服务实战之CI/CD 前言 说到微服务就 ... 
- 炼技术(9): 简约而不简单,永不停歇的测试 -- always_run
			最强战力,永不停歇的测试:always_run 许多工程师写完程序后,都不愿意对自己的程序做仔细测试. 很多测试说会做自动化测试,可能工作好几年都没真做过多少自动化测试. 我们的解决方案是,在系统的测 ... 
- AMD 5700 XT显卡装ubuntu18.04.* 驱动的问题解决(全)
			公司开发需要测试新的 AMD显卡,由于测试服务器上的显卡是英伟达的显卡所以换完后要安装相应的驱动.由于之前装机的同事装的ubuntu是18.04.5 恰巧18.04.5在amd官网上没有相匹配的驱动( ... 
- redis读写分离及可用性设计
			Redis缓存架构设计 对于下面两个架构图,有如下想法: 1)redis主从复制模式,为了解决master读写压力,对master进行写操作,对slave进行读操作. 2)而在分片集群中,如果对部分分 ... 
