[转帖]对造成数据库压力翻倍的bad sql的解决方案_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3968 | 回复: 0   主题: [转帖]对造成数据库压力翻倍的bad sql的解决方案        下一篇 
derek
注册用户
等级:中校
经验:1550
发帖:209
精华:0
注册:2011-7-21
状态:离线
发送短消息息给derek 加好友    发送短消息息给derek 发消息
发表于: IP:您无权察看 2011-8-1 21:37:16 | [全部帖] [楼主帖] 楼主

早上看到数据库一个节点的load比昨天翻倍,细查之下,发现主要是由新上线的一条sql引起的,查询语句如下

select b.sid,substr(b.username,1,10) username,decode(program, null, machine,replace(program,' (TNS V1-V3)','')||decode(machine,null,'@'||terminal)) machine,
substr(
(case
when a.event like 'enq%' then a.event|| ':' || chr(bitand(a.p1,-16777216)/16777215)||chr(bitand(a.p1, 16711680)/65535)||'-'||bitand(a.p1, 65535)||':'||ROW_WAIT_FILE#||':
'||ROW_WAIT_BLOCK#||':'|| ROW_WAIT_ROW#
else a.event
end),1,30) event,
a.p1||'/'||a.p2||'/'||a.p3 param,a.wait_time w,a.SECONDS_IN_WAIT WT,b.sql_id||'/'||b.PREV_SQL_ID SQL, decode(b.status,'ACTIVE','A','INACTIVE','I','KILLED','K',STATUS) status,last_call_et LT,
(sysdate -logon_time )*24*3600 LOGON_TIME
from v$session_wait a,v$session b
where ((a.event not like 'SQL*Net message%' and a.event not like 'rdbms%') or b.status='ACTIVE') and a.sid=b.sid
and b.type='USER'
and b.sid <>(SELECT SID FROM V$MYSTAT WHERE ROWNUM=1)
order by sql_hash_value;


捕获的Sql语句结构如下

select a.col1,
b.col2,
...
from a
left join b
on a.b_id = b.id
WHERE sub_id in (:1, :2)
and a.parent_id = 0
order by .id desc;


其中表a有800多万条记录,其上的字段sub_id和parent_id均有索引;而表b只有20条;

结果发现该sql执行计划的cost很低,只有6,但是buffer gets却很高,有6位数。
刚开始感觉是统计信息陈旧,查看后发现表A是昨天收集的,而表B也是最近收集的,因此排除这个可能。
仔细查看执行计划,发现其选择了parent_id上的索引,而非sub_id,这点比较可疑。
经查看parent_id=0的记录占了全表记录的80%,而且该列上没有直方图,导致CBO选择执行计划的时候误用了基于parent_id列的索引。

原因找到了,接下来是如何解决。
首先,重新收集表a的统计信息并收集parent_id上的直方图,考虑表a的访问十分繁忙,如果现在就让该游标失效会导致大量硬解析DB有可能因此而hang住,如果不让其失效load又一直居高不下,因此在调用
Dbms_stats.gather_table_stats的时候指定了no_invalidate为auto(也可以不标注,因为默认就是auto),决定让oracle自动决定何时去invalidate该游标。

之后观察了一段时间,发现该sql还是使用原来的错误执行计划,load还是居高不下。
我们的系统是10.2.0.5的,而oracle好像是10.2以后就可以调用dbms_shared_pool.purge了。
Support.oracle.com查了一下,发现调用该功能之前还必须要设定事件 alter session set events '5614566 trace name context forever';
由于不能判定其造成的影响,决定暂不使用该功能。

此刻,既不能对表做grant select on a to dba操作,也不能使用dbms_shared_pool.purge,而bad sql仍在运行。

忽然,我们组长想到了一个方案,对表b做grant select on b to dba操作(表b访问热度相对就少了很多)。
执行过后,sql立即选择了sub_id上的索引,buffer gets下降到了两位数,数据库压力不到1分钟就下降到了正常状态。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论