分享一个前两天写的自动监控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 的 时间间隔。

最后注意两点:

  1. UTL_MAIL 记得开启权限
  2. 我们的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)的主要内容,如果未能解决你的问题,请参考以下文章

反抗996!启舰肝了个监控老板人脸,自动切桌面程序

反抗996!启舰肝了个监控老板人脸,自动切桌面程序

免app下载笔趣阁小说

requests---自动写博客

淘宝+京东双十一活动自动化脚本

linux自动备份计划,我想备份var/www/html/的整个目录,每天2点备份一次,自动删除前两天的备份文件。