分享一个前两天写的自动监控blocking 的脚本(基于12C)
Posted renfengjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分享一个前两天写的自动监控blocking 的脚本(基于12C)相关的知识,希望对你有一定的参考价值。
闲话不说直接上脚本。
用于再rac环境下监控本机所有非standby db的blocking 情况。11g应该也适用。
blocking2.sql
set serveroutput on
set lines 300
declare
v_msg varchar2(20000);
v_title varchar2(20000);
v_find_obj_sql varchar2(20000);
v_full_sql_txt varchar2(20000);
v_objname varchar2(30) ;
function send_mail(vc_subject in varchar2,vc_message in varchar2)
return pls_integer
as
mail_sendr constant varchar(32) := 'db@dex.com';
mail_recpt constant varchar(32) := 'db@dex.com';
BEGIN
UTL_MAIL.send(sender => mail_sendr,
recipients => mail_recpt,
subject => vc_subject,
message => vc_message,
mime_type => 'text; charset=us-ascii');
return 1;
exception when others then
return 0;
END;
function get_full_sqltext(vc_sqlid in varchar2)
return varchar2
as
v_find_sql_txt varchar2(20000) ;
v_sql_txt varchar2(20000) ;
begin
v_find_sql_txt := 'select max(dbms_lob.substr(sql_fulltext)) FULL_TEXT from v$sql where sql_id=:sqlid ';
execute immediate v_find_sql_txt into v_sql_txt using vc_sqlid;
return v_sql_txt ;
end;
begin
v_find_obj_sql := 'select max(o.owner) || ''.'' ||max(o.object_name) || nvl2 (max(subobject_name), ''.'' || max(subobject_name), null) obj_name from containers(dba_objects) o where o.object_id=:objid and o.con_id=:conid' ;
for rec in (select
'Container '||p.name||' Session '||a.sid||' is blokcing session '||b.sid||' duration: '|| lpad (to_char (trunc (w.ctime / 3600)), 3, '0') || ':' ||
lpad (to_char (mod (trunc (w.ctime / 60), 60)), 2, '0') || ':' ||
lpad (to_char (mod (w.ctime, 60)), 2, '0')||' Lock type ' ||h.type summary,
'Blocker SID :' || a.sid ||chr(10)||
'Blocker Username :' || a.username ||chr(10)||
'Blocker App Machine :' || a.machine ||chr(10)||
'Blocker Serial number :' || a.serial# ||chr(10)||
'Blocker Current Status :' || a.status ||chr(10)||
'Blocker SQL ID current :' || a.sql_id ||chr(10)||
'Blocker Previous SQL ID :' || a.prev_sql_id ||chr(10)||
'Blocker KCML Partition No :' || a.module ||chr(10)||
'Blocker Program name :' || a.program ||chr(10)||
'Blocker Client Information :' || a.client_info ||chr(10)||
'Blocker Application UUID :' || a.ecid ||chr(10)||
'Waiter SID :' || b.sid||chr(10)||
'Waiter Username :' || b.username ||chr(10)||
'Waiter App Machine :' || b.machine ||chr(10)||
'Waiter Serial number :' || b.serial# ||chr(10)||
'Waiter Current Status :' || b.status ||chr(10)||
'Waiter SQL ID current :' || b.sql_id ||chr(10)||
'Waiter Previous SQL ID :' || b.prev_sql_id ||chr(10)||
'Waiter KCML Partition No :' || b.module ||chr(10)||
'Waiter Program name :' || b.program ||chr(10)||
'Waiter Client Information :' || b.client_info ||chr(10)||
'Waiter Application UUID :' || b.ecid details,
a.sql_id b_sql_id,
a.prev_sql_id b_prev_sql_id,
b.sql_id w_sql_id,
b.prev_sql_id w_prev_sql_id,
p.name pdbname,
p.con_id,
decode (w.type, 'TX', b.row_wait_obj#,
'TM', w.id1) obj_id
from v$lock h, v$lock w, v$session b, v$session a , v$pdbs p
where h.block != 0
and h.lmode != 0
and h.lmode != 1
and w.request != 0
and w.id1 = h.id1
and w.id2 = h.id2
and h.sid = a.sid
and w.sid = b.sid
and w.con_id=p.con_id
and h.ctime > 901) loop
execute immediate v_find_obj_sql into v_objname using rec.obj_id,rec.con_id;
v_msg := rec.summary || chr(10) || 'Locked object :' || v_objname || chr(10) ||rec.details;
v_title := sys_context('USERENV','INSTANCE_NAME')||'_'||rec.pdbname||'_12c_oracle_15';
v_msg := v_msg || chr(10) || 'Additional sql text:'|| chr(10) ;
if rec.b_sql_id is not null then
v_msg := v_msg || chr(10) || rec.b_sql_id ||':'||chr(10) ||get_full_sqltext(rec.b_sql_id);
end if ;
if rec.w_sql_id is not null then
v_msg := v_msg || chr(10) || rec.w_sql_id ||':'||chr(10) ||get_full_sqltext(rec.w_sql_id);
end if ;
if rec.b_prev_sql_id is not null then
v_msg := v_msg || chr(10) || rec.b_prev_sql_id ||':'||chr(10) ||get_full_sqltext(rec.b_prev_sql_id);
end if ;
if rec.w_prev_sql_id is not null then
v_msg := v_msg || chr(10) || rec.w_prev_sql_id ||':'||chr(10) ||get_full_sqltext(rec.w_prev_sql_id);
end if ;
#dbms_output.put_line(v_msg) ;
#dbms_output.put_line(v_title) ;
#dbms_output.put_line(send_mail(v_title,v_msg)) ;
end loop ;
end;
/
exit;
这里单独取object name是因为再cdb里面不存储single pdb的 object 信息。
所以只能使用containers()函数获取。还需要注意的是,如果在plsql 块的sql里面使用containers函数会出现无法编译的情况,所以这里只能使用动态sql。
local_db_blocking_check_15.sh
#!/bin/bash
OLDPATH=$PATH
export PATH=$PATH:/usr/local/bin
SCRIPTDIR=/oracle/src/scripts/monitoring
SCANADDR=$(hostname | awk -F- 'print $1"-"$2"-"$3"-scan"')
QWERTY=QAZ2wsx3edc
PORT=1521
#echo date >> /tmp/blocking_monitoring.log
function Role_Check
CONNECTTO=$1
DB_ROLE=NONE
# Database role check
DB_ROLE=$(sqlplus -s system/"$QWERTY"@$SCANADDR:$PORT/$CONNECTTO <<EOF
set pagesize 0
set heading off
set feedback off
SELECT database_role FROM v\\$database;
exit;
EOF
)
ORACLE_SID=$(ps -eaf | grep -i smon | cut -d_ -f3 | grep +)
# Use ORAENV_ASK set to NO to prevent prompting, but instead use the SID value set above
ORAENV_ASK=NO
. oraenv
for db_uniq in $(srvctl config database)
do
Role_Check $db_uniq
if [ "$DB_ROLE" == "PRIMARY" ]; then
sqlplus -s sys/"$QWERTY"@$SCANADDR:$PORT/$db_uniq as sysdba @$SCRIPTDIR/BASE/blocking2.sql
fi
done
这个就没什么好说的了。
最后只要把
local_db_blocking_check_15.sh
放到corntab 里面就可以了,一般是15分钟检查一次。如果要修改频率,记得再sql 里面修改h.ctime > 901 的 时间间隔。
最后注意两点:
- UTL_MAIL 记得开启权限
- 我们的scan addr是有规律的,所以如果要使用你们自己的环境记得修改这部分shell代码。
SCANADDR=$(hostname | awk -F- ‘print $1"-"$2"-"$3"-scan"’)
附录:
检查blocking脚本是类似于这样的:
select /*+ rule */
'Container '||p.name||' Session '||a.sid||' is blokcing session '||b.sid||' by object '||o.owner || '.' || o.object_name ||
nvl2 (subobject_name, '.' || subobject_name, null)||' duration: '|| lpad (to_char (trunc (w.ctime / 3600)), 3, '0') || ':' ||
lpad (to_char (mod (trunc (w.ctime / 60), 60)), 2, '0') || ':' ||
lpad (to_char (mod (w.ctime, 60)), 2, '0')||' Lock type ' ||h.type summary,
'Blocker SID :' || a.sid ||chr(10)||
'Blocker Username :' || a.username ||chr(10)||
'Blocker App Machine :' || a.machine ||chr(10)||
'Blocker Serial number :' || a.serial# ||chr(10)||
'Blocker Current Status :' || a.status ||chr(10)||
'Blocker SQL ID current :' || a.sql_id ||chr(10)||
'Blocker Previous SQL ID :' || a.prev_sql_id ||chr(10)||
'Blocker KCML Partition No :' || a.module ||chr(10)||
'Blocker Program name :' || a.program ||chr(10)||
'Blocker Client Information :' || a.client_info ||chr(10)||
'Blocker Application UUID :' || a.ecid ||chr(10)||
'Waiter SID :' || b.sid||chr(10)||
'Waiter Username :' || b.username ||chr(10)||
'Waiter App Machine :' || b.machine ||chr(10)||
'Waiter Serial number :' || b.serial# ||chr(10)||
'Waiter Current Status :' || b.status ||chr(10)||
'Waiter SQL ID current :' || b.sql_id ||chr(10)||
'Waiter Previous SQL ID :' || b.prev_sql_id ||chr(10)||
'Waiter KCML Partition No :' || b.module ||chr(10)||
'Waiter Program name :' || b.program ||chr(10)||
'Waiter Client Information :' || b.client_info ||chr(10)||
'Waiter Application UUID :' || b.ecid details,
a.sql_id b_sql_id,
a.prev_sql_id b_pre_sql_id,
b.sql_id w_sql_id,
b.prev_sql_id w_prev_sql_id
from v$lock h, v$lock w, v$session b, v$session a, dba_objects o , v$pdbs p
where h.block != 0
and h.lmode != 0
and h.lmode != 1
and w.request != 0
and w.id1 = h.id1
and w.id2 = h.id2
and h.sid = a.sid
and w.sid = b.sid
and decode (w.type, 'TX', b.row_wait_obj#,
'TM', w.id1)
= o.object_id
and w.con_id=o.con_id
and w.con_id=p.con_id
order by w.ctime desc;
以上sql适用于11g,如果是12c记得把获取object_name的部分去掉。
最后的效果类似于这样:
email title:
xxx-xxx-xxx-0101_1_xxxDB39_12c_oracle_15
body:
Container DB125439 Session 32787 is blokcing session 35500 duration: 000:47:33 Lock type TX Locked object :DEXTER.TESTTABLE
Blocker SID :32787
Blocker Username :DEXTER
Blocker App Machine :xxx-xxx-xxx-01
Blocker Serial number :44996
Blocker Current Status :INACTIVE
Blocker SQL ID current :
Blocker Previous SQL ID :cdvppfnyngumd
Blocker KCML Partition No :SQL*Plus
Blocker Program name :sqlplus@xxx-xxx-xxx-01 (TNS V1-V3)
Blocker Client Information :
Blocker Application UUID :
Waiter SID :35500
Waiter Username :DEXTER
Waiter App Machine :xxx-xxx-xxx-01
Waiter Serial number :18786
Waiter Current Status :ACTIVE
Waiter SQL ID current :5z3w5m3z9yv6y
Waiter Previous SQL ID :cdvppfnyngumd
Waiter KCML Partition No :SQL*Plus
Waiter Program name :sqlplus@xxx-xxx-xxx-01 (TNS V1-V3)
Waiter Client Information :
Waiter Application UUID :
Additional sql text:
xxxxxx:
update testtable set id=333 where id=3
xxxxxx:
update testtable set id=5
xxxxxx:
update testtable set id=5
敏感信息我就用xxx代替了
以上是关于分享一个前两天写的自动监控blocking 的脚本(基于12C)的主要内容,如果未能解决你的问题,请参考以下文章