상세 컨텐츠

본문 제목

Maximum open cursor error에 관해

DataBase/Oracle

by 탑~! 2012. 8. 8. 17:51

본문

Maximum open cursor error에 관해
 
잡로 JDBC를 이용하여 프로그래밍 할 때 반복문(for, while)안에 Statement PreparedStatement등이 위치하는 경우엔 간혹 ORA-01000: 최대 열기 커서 수를 초과했습니다 라는 오류를 만날 수 있습니다.
 
==============================
오라클 서버에서 해야 할 일
==============================
 
이 경우엔 우선 오라클 서버의 initSID.ora 파일에서 open_cursors 파라미터 값(기본값은 50)을 늘여 줄 수도 있지만 제가 봤을 때는 근본적인 해결책은 아닙니다.
 
SQL문은 SQL문의 내용이 같아도 (host 변수를 사용해서 값만 바뀌고 SQL문은 그대로인 경우라도) 무조건 실행 될 때 마다 Oracle 서버의 Cursor를 묵시적으로 할당 합니다.
 
어떤 프로그램이 for, while 루프 안에서 5개의 SQL문을 실행한다고 가정하고, for 루프가 10000번을 돈다고 하면 프로그램은 총 50000 개의 Oracle Implicit Cursor를 사용하게 되는 것입니다.
 
이것은 OPEN_CURSORS 파라미터를 50000개 이상으로 설정하지 않으면 ORA-01000 에러를 만날 수 있다는 이야깁니다. 그러나 실제 SMON이 적정한 수 이상의 Cursor가 열려있으면 이를 정리해주므로 50000 개 정도로 크게 OPEN_CURSORS 파라미타를 설정할 필요는 없습니다.
 
SMON이 특성을 고려 했을 때 보통 1000 ~ 2000개 정도면 적당 합니다. 오라클의 Cursor1개당 25 byte 의 메모리를 사용하며 MTS에서는 SGA의 영역이 사용되므로 너무 크게 잡지 않도록 하고 SGA를 충분히 크게 잡아주는 것이 필요 합니다.
 
아래 SQL문으로 현재 커서를 많이 오픈 해 놓고 있는 프로세스를 찾을 수 있는 방법이 있으니 참고 바랍니다.
 
-------------------------------------------------------------
-- Open Cursor 수의 조회
-------------------------------------------------------------
select * from ( select sid, count(*)
from v$open_cursor
group by sid  
order by 2 desc )
where rownum <= 10;
 
select a.sid, s.process, count(*)
from V$OPEN_CURSOR a, V$SESSION s 
where s.sid = a.sid 
group by a.sid, s.process 
having count(*) > 100 
order by count(*) desc;
 
maximum open cursor 수를 파악하고자 하면, 다음과 같이 sqlplus svrmgrl 에서 sys유저로 접속해서 show parameter 명령을 사용하면 됩니다.
 
SQL> show parameter open_cursors

 
NAME                 TYPE      VALUE
------ ------- ------------------------------
open_cursors          nteger    2000

 
 
==============================
JDBC 프로그램에서 해야 할 일
==============================
 
Masimum Open Curdor  문제를 해결하기 위해서 다음과 같이 코딩 할 수도 있습니다.
 
for()
{
 Statement stmt = conn.preparedStatement();
 rs = stmt.executeQuery(sql);
 stmt.close();   //루프안에서 close 해 버림
}
 
이러한 경우엔 위 오류는 발생하지 않겠지만 성능상의 문제가 있을 수 있으므로 아래처럼 PreparedStatement를 사용하시는 것이 좋습니다.
 
 
PreparedStatement pstmt = conn.PreparedStatement(sql);
for()
{
 pstmt.setString(1, value);
 ………
 
 rs = pstmt.executeQuery();
}

관련글 더보기