空閒表上的聯機ddl操作有風險嗎

redhouser發表於2013-03-13
一張表上幾乎沒有dml操作,在系統聯機情況下ddl操作(增加varchar2列的長度)有風險嗎?

初步分析,此DDL操作需要獲取表上的獨佔鎖,之需要修改資料字典,會很快完成,看起來沒什麼風險.
進一步分析,此DDL操作會導致存在依賴關係的儲存過程狀態無效,而重新編譯儲存過程需要獲取library cache pin,如果儲存過程執行時間較長或比較頻繁,將導致大量會話被阻塞。
測試如下:
--測試環境準備:
create table test(x int,y varchar2(10));
insert into test values(1,'1');
insert into test values(2,'2');
commit;
set serveroutput on
create or replace procedure prc
as
l_cnt int;
begin
   select count(*) into l_cnt from test;
   dbms_lock.sleep(300);
   dbms_output.put_line('rows:'||l_cnt);
end;
/
--session 1:sid=816
--session 2:sid=850
--session 3:sid=680
1,如果某個儲存過程引用該表,而該儲存過程執行時間較長或很頻繁,是否會對系統造成較大影響?
--session 1:
exec prc;
--沒返回
--session x:
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- ------------------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”

--session 2:
SQL> set timing on
SQL> alter table test modify(y varchar2(50));
Table altered.
Elapsed: 00:00:00.04
==>很快返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- ----------------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
--session 3:
exec prc;
--沒返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 library cache pin                                816 Concurrency
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
==>會話3被會話1阻塞:由於會話2修改表結構,會話3執行儲存過程時需重新編譯儲存過程,
   而會話1執行狀態導致無法對儲存過程重新編譯,從而阻塞了會話3;等待時間會持續到會話1結束。

--等待事件變化:
  1* select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680)
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 library cache pin                                816 Concurrency
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle

SQL> r
  1* select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680)
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 PL/SQL lock timer                                    Idle
       816 SQL*Net message from client                          Idle
       850 SQL*Net message from client                          Idle
SQL> r
  1* select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680)
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 SQL*Net message from client                          Idle
       816 SQL*Net message from client                          Idle
       850 SQL*Net message from client                          Idle
2,作為對比測試,如果儲存過程不引用該表,情況相同嗎?
==>不會出現重新編譯導致的library cache pin等待了。
儲存過程修改為:
set serveroutput on
create or replace procedure prc
as
l_cnt int;
begin
   dbms_lock.sleep(300);
   dbms_output.put_line('rows:'||l_cnt);
end;
/

--session 1:
exec prc;
--沒返回
--session x:
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- --------------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”

--session 2:
SQL> set timing on
SQL> alter table test modify(y varchar2(80));
Table altered.
Elapsed: 00:00:00.04
==>很快返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
      SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- ---------------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
--session 3:
exec prc;
--沒返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
      SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 PL/SQL lock timer                                    Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
==>會話3在執行,event:“PL/SQL lock timer”

--等待事件變化:
15:43:58 SQL> r
  1* select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680)
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- ----------------------------
       680 PL/SQL lock timer                                    Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
15:46:12 SQL> r
  1* select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680)
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------------
       680 SQL*Net message from client                          Idle
       816 SQL*Net message from client                          Idle
       850 SQL*Net message from client                          Idle

3,作為對比測試,如果DDL操作變為表上增加欄位,情況相同嗎?
==>
儲存過程恢復為:
set serveroutput on
create or replace procedure prc
as
l_cnt int;
begin
   select count(*) into l_cnt from test;
   dbms_lock.sleep(300);
   dbms_output.put_line('rows:'||l_cnt);
end;
/

--session 1:
exec prc;
--沒返回
--session x:
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -------------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”

--session 2:
SQL> set timing on
SQL> alter table test add (z varchar2(80));
Table altered.
Elapsed: 00:00:00.04
==>很快返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- -----------------------
       680 SQL*Net message from client                          Idle
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
--session 3:
exec prc;
--沒返回
--session x:
select * from v$lock where sid in(816,850,680);
no rows selected
select sid,event,blocking_session,wait_class from v$session where sid in(816,850,680);
       SID EVENT                               BLOCKING_SESSION WAIT_CLASS
---------- ----------------------------------- ---------------- ---------------------------
       680 library cache pin                                816 Concurrency
       816 PL/SQL lock timer                                    Idle
       850 SQL*Net message from client                          Idle
==>會話1在執行,event:“PL/SQL lock timer”
==>會話3被會話1阻塞

--等待事件變化:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/18922393/viewspace-756069/,如需轉載,請註明出處,否則將追究法律責任。

相關文章