Oracle釋放無用連線
給甲方做了一個數據統計分析系統,上百號人在用這個系統,資料庫採用的是oracle9i ,遇到了一個問題: 客戶們經常連線不上伺服器,查看了日誌檔案才發現,連線數量預設最大設定是150,實際上這個連線數是滿足不了要求的,而且不排除這些連線裡面有廢掉的。所以通過網路查找了一些相關資料,可以按照下面的方法解決ORACLE自動刪除廢掉的連線:
通過profile可以對使用者會話進行一定的限制,比如IDLE時間。
將IDLE超過一定時間的會話斷開,可以減少資料庫端的會話數量,減少資源耗用。
使用這些資源限制特性,需要設定resource_limit為TRUE:
[oracle@test126 udump]$ sqlplus "/ as sysdba"
SQL> show parameter resource
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
resource_limit boolean TRUE
resource_manager_plan string
該引數可以動態修改:
SQL> alter system set resource_limit=true;
資料庫預設的PROFILE設定為:
SQL> SELECT * FROM DBA_PROFILES;
PROFILE RESOURCE_NAME RESOURCE LIMIT
-------------------- -------------------------------- -------- ---------------
DEFAULT COMPOSITE_LIMIT KERNEL UNLIMITED
DEFAULT SESSIONS_PER_USER KERNEL UNLIMITED
DEFAULT CPU_PER_SESSION KERNEL UNLIMITED
DEFAULT CPU_PER_CALL KERNEL UNLIMITED
DEFAULT LOGICAL_READS_PER_SESSION KERNEL UNLIMITED
DEFAULT LOGICAL_READS_PER_CALL KERNEL UNLIMITED
DEFAULT IDLE_TIME KERNEL UNLIMITED
DEFAULT CONNECT_TIME KERNEL UNLIMITED
DEFAULT PRIVATE_SGA KERNEL UNLIMITED
DEFAULT FAILED_LOGIN_ATTEMPTS PASSWORD 10
DEFAULT PASSWORD_LIFE_TIME PASSWORD UNLIMITED
PROFILE RESOURCE_NAME RESOURCE LIMIT
-------------------- -------------------------------- -------- ---------------
DEFAULT PASSWORD_REUSE_TIME PASSWORD UNLIMITED
DEFAULT PASSWORD_REUSE_MAX PASSWORD UNLIMITED
DEFAULT PASSWORD_VERIFY_FUNCTION PASSWORD NULL
DEFAULT PASSWORD_LOCK_TIME PASSWORD UNLIMITED
DEFAULT PASSWORD_GRACE_TIME PASSWORD UNLIMITED
16 rows selected.
建立一個允許3分鐘IDLE時間的PROFILE:
SQL> CREATE PROFILE KILLIDLE LIMIT IDLE_TIME 3;
Profile created.
新建立PROFILE的內容:
SQL> col limit for a10
SQL> select * from dba_profiles where profile='KILLIDLE';
PROFILE RESOURCE_NAME RESOURCE LIMIT
------------------------------ -------------------------------- -------- ----------
KILLIDLE COMPOSITE_LIMIT KERNEL DEFAULT
KILLIDLE SESSIONS_PER_USER KERNEL DEFAULT
KILLIDLE CPU_PER_SESSION KERNEL DEFAULT
KILLIDLE CPU_PER_CALL KERNEL DEFAULT
KILLIDLE LOGICAL_READS_PER_SESSION KERNEL DEFAULT
KILLIDLE LOGICAL_READS_PER_CALL KERNEL DEFAULT
KILLIDLE IDLE_TIME KERNEL 3
KILLIDLE CONNECT_TIME KERNEL DEFAULT
KILLIDLE PRIVATE_SGA KERNEL DEFAULT
KILLIDLE FAILED_LOGIN_ATTEMPTS PASSWORD DEFAULT
KILLIDLE PASSWORD_LIFE_TIME PASSWORD DEFAULT
PROFILE RESOURCE_NAME RESOURCE LIMIT
------------------------------ -------------------------------- -------- ----------
KILLIDLE PASSWORD_REUSE_TIME PASSWORD DEFAULT
KILLIDLE PASSWORD_REUSE_MAX PASSWORD DEFAULT
KILLIDLE PASSWORD_VERIFY_FUNCTION PASSWORD DEFAULT
KILLIDLE PASSWORD_LOCK_TIME PASSWORD DEFAULT
KILLIDLE PASSWORD_GRACE_TIME PASSWORD DEFAULT
16 rows selected.
測試使用者:
SQL> select username,profile from dba_users where username='EYGLE';
USERNAME PROFILE
------------------------------ --------------------
EYGLE DEFAULT
修改eygle使用者的PROFILE使用新建的PROFILE:
SQL> alter user eygle profile killidle;
User altered.
SQL> select username,profile from dba_users where username='EYGLE';
USERNAME PROFILE
------------------------------ --------------------
EYGLE KILLIDLE
進行連線測試:
[oracle@test126 admin]$ sqlplus eygle/eygle@eygle
SQL> select username,profile from dba_users where username='EYGLE';
USERNAME PROFILE
------------------------------ ------------------------------
EYGLE KILLIDLE
當IDLE超過限制時間時,連線會被斷開:
SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
TO_CHAR(SYSDATE,'YY
-------------------
2006-10-13 08:08:41
SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual
*
ERROR at line 1:
ORA-02396: exceeded maximum idle time, please connect again
1.sqlplus /nolog
2.開啟sqlplus
3.
4.
5.connect system/bianqiwei@orcltns as sysdba
6.使用具有dba許可權得使用者登陸oracle
7.
8.
9.show parameter resource_limit
10.顯示資源限定是否開啟,value為true是開啟,為false是關閉
11.
12.
13.alter system set resource_limit=true
14.如果未開啟,則使用此命令開啟資源限定功能
15.
16.
17.create profile profileName limit connect_time 60 idle_time 30
18.建立profile檔案,profileName任意起,connect_time設定連線超過多少分鐘後強制釋放,idle_time設定連續不活動的會話超過多少分鐘後強制釋放
19.
20.alter user oracleUser profile profileName
21.將profile檔案作用於指定使用者
從上週起,伺服器Oracle資料庫出現問題,用不到半天,就會報maxsession(150)的問題,肯定是資料庫的會話超過最大數了。
由於伺服器跑的是檔案傳輸應用,佔用的請求和會話肯定很大,因此使用者數不大就已經讓oracle的會話數達到最大值。
處理方式不外乎兩種:擴大oracle最大session數以及清除inactive會話,當然還有,就是從資料庫連線池和程式bug上面下手。
從各處收集了一些檢視當前會話的語句,記錄一下:
1.select count(*) from v$session;
select count(*) from v$process;
檢視當前總會話數和程序數,這兩個檢視就是跟會話及程序有關的重要檢視啦,資訊都是從這裡面取的。
2.查詢那些應用的連線數此時是多少
select b.MACHINE, b.PROGRAM , count(*) from v$process a, v$session b where a.ADDR = b.PADDR and b.USERNAME is not null group by b.MACHINE , b.PROGRAM order by count(*) desc;
3.查詢是否有死鎖
select * from v$locked_object;
如果查詢結果為no rows selected,說明資料庫中沒有死鎖。否則說明資料庫中存在死鎖。
接下來說明一下會話的狀態:
1.active 處於此狀態的會話,表示正在執行,處於活動狀態。
2.killed 處於此狀態的會話,表示出現了錯誤,正在回滾,當然,也是佔用系統資源的。還有一點就是,killed的狀態一般會持續較長時間,而且用windows下的工具pl/sql developer來kill掉,是不管用的,要用命令:alter system kill session 'sid,serial#' ;
3.inactive 處於此狀態的會話表示不是正在執行的,比如select語句已經完成。我一開始以為,只要是inactive狀態的會話,就是該殺,為什麼不釋放呢。其實,inactive對資料庫本身沒有什麼影響,但是如果程式沒有及時commit,那麼就會造成佔用過多會話。解決inactive的方法最好的就是在oracle中直接設定超時時間,也是有兩種方法,區別暫時還不清楚:
1.修改sqlnet.ora檔案,新增expire_time=x(單位是分鐘)
我的sqlnet.ora位置在D:/oracle/ora92/network/admin
2.通過ALTER PROFILE DEFAULT LIMIT IDLE_TIME 10; 命令修改,記得重啟下oracle。
修改ORACLE 中的SESSION和PROCESS
會話sessions和程序pocesses的關係
一個process可以有0個、1個或者多個session,一個session也可以存在若干個process中,並行同樣是一個session對應一個process,主session是coordinator session,每個parallel process同樣會對應資料庫裡一個單獨的session。可以從v$px_session和v$session中驗證這點。
連線connects,會話sessions和程序pocesses的關係
每個sql login稱為一個連線(connection),而每個連線,可以產生一個或多個會話,如果資料庫執行在專用伺服器方式,一個會話對應一個伺服器程序(process),如果資料庫執行在共享伺服器方式,一個伺服器程序可以為多個會話服務。
Oracle的sessions和processes的數量關係是:sessions=1.1 * processes + 5
下面我們用兩種方法修改PROCESS的最大值
一、通過Oracle Enterprise Manager Console在圖形化管理器中修改
以系統管理員的身份登入,進入介面 資料庫的例程 - 配置 - 一般資訊 - 所有初始化引數,修改processes的值
二、在SQLPLUS中修改
以DBA許可權登入,修改PROCESS的值(SESSION的值會跟著改);建立pfile;重新啟動資料庫。輸入的SQL命令如下,回顯資訊省略了
SQL> connect sys/sys as sysdba
SQL> alter system set processes=400 scope = spfile;
SQL> create pfile from spfile;
SQL> shutdown immediate;
SQL> startup
Oracle中Kill session的研究
我們知道,在Oracle資料庫中,可以通過kill session的方式來終止一個程序,其基本語法結構為:
alter system kill session 'sid,serial#' ;
被kill掉的session,狀態會被標記為killed,Oracle會在該使用者下一次touch時清除該程序.
我們發現當一個session被kill掉以後,該session的paddr被修改,如果有多個session被kill,那麼多個session
的paddr都被更改為相同的程序地址:
SQL> select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SID SERIAL# PADDR USERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11 314 542B70E8 EYGLE INACTIVE
542E5044 18 662 542B6D38 SYS ACTIVE
SQL> alter system kill session '11,314';
System altered.
SQL> select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SID SERIAL# PADDR USERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11 314 542D6BD4 EYGLE KILLED
542E5044 18 662 542B6D38 SYS ACTIVE
SQL> select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SID SERIAL# PADDR USERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11 314 542D6BD4 EYGLE KILLED
542E2AA4 14 397 542B7498 EQSP INACTIVE
542E5044 18 662 542B6D38 SYS ACTIVE
SQL> alter system kill session '14,397';
System altered.
SQL> select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SID SERIAL# PADDR USERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11 314 542D6BD4 EYGLE KILLED
542E2AA4 14 397 542D6BD4 EQSP KILLED
542E5044 18 662 542B6D38 SYS ACTIVE
在這種情況下,很多時候,資源是無法釋放的,我們需要查詢spid,在作業系統級來kill這些程序.
但是由於此時v$session.paddr已經改變,我們無法通過v$session和v$process關聯來獲得spid
那還可以怎麼辦呢?
我們來看一下下面的查詢:
SQL> SELECT s.username,s.status,
2 x.ADDR,x.KSLLAPSC,x.KSLLAPSN,x.KSLLASPO,x.KSLLID1R,x.KSLLRTYP,
3 decode(bitand (x.ksuprflg,2),0,null,1)
4 FROM x$ksupr x,v$session s
5 WHERE s.paddr(+)=x.addr
6 and bitand(ksspaflg,1)!=0;
USERNAME STATUS ADDR KSLLAPSC KSLLAPSN KSLLASPO KSLLID1R KS D
------------------------------ -------- -------- ---------- ---------- ------------ ---------- -- -
542B44A8 0 0 0
ACTIVE 542B4858 1 14 24069 0 1
ACTIVE 542B4C08 26 16 15901 0 1
ACTIVE 542B4FB8 7 46 24083 0 1
ACTIVE 542B5368 12 15 24081 0 1
ACTIVE 542B5718 15 46 24083 0 1
ACTIVE 542B5AC8 79 4 15923 0 1
ACTIVE 542B5E78 50 16 24085 0 1
ACTIVE 542B6228 754 15 24081 0 1
ACTIVE 542B65D8 1 14 24069 0 1
ACTIVE 542B6988 2 30 14571 0 1
USERNAME STATUS ADDR KSLLAPSC KSLLAPSN KSLLASPO KSLLID1R KS D
------------------------------ -------- -------- ---------- ---------- ------------ ---------- -- -
SYS ACTIVE 542B6D38 2 8 24071 0
542B70E8 1 15 24081 195 EV
542B7498 1 15 24081 195 EV
SYS INACTIVE 542B7848 0 0 0
SYS INACTIVE 542B7BF8 1 15 24081 195 EV
16 rows selected.
我們注意,紅字標出的部分就是被Kill掉的程序的程序地址.
簡化一點,其實就是如下概念:
SQL> select p.addr from v$process p where pid <> 1 2 minus 3 select s.paddr from v$session s;ADDR
--------
542B70E8
542B7498
Ok,現在我們獲得了程序地址,就可以在v$process中找到spid,然後可以使用Kill或者orakill在系統級來殺掉這些程序.
實際上,我猜測:
當在Oracle中kill session以後, Oracle只是簡單的把相關session的paddr 指向同一個虛擬地址.
此時v$process和v$session失去關聯,程序就此中斷.
然後Oracle就等待PMON去清除這些Session.所以通常等待一個被標記為Killed的Session退出需要花費很長的時間.
如果此時被Kill的process,重新嘗試執行任務,那麼馬上會收到程序中斷的提示,process退出,此時Oracle會立即啟動PMON
來清除該session.這被作為一次異常中斷處理
轉載於:https://my.oschina.net/sunchenbin/blog/632978