반응형

10g에 추가된 Tuning Advisor


SQL ID 와 Begin SNAP 부분은 addm 을 통해 조회하여 입력하는 것이 좋음.(자동 생성 SH은 비밀글 참조...)


출처 : http://blog.daum.net/onjshop/175


★★ www.oraclejava3.co.kr 에서 더욱 유용한 정보를 확인하실 수 있습니다. ★★ 
(분당정자점은 양재, 강남에서 15분 거리에 있습니다. ^^)

Automatic SQL Tuning in Oracle Database 10g(SQL Tuning Advisor) 

이번 강좌에서는 오라클 10g의 새 특징인 자동 SQL 튜닝기능에 대해 알아 보도록 하겠습니다. 

Normal Mode에서 오라클 옵티마이저는 아주 짧은 시간에 최적의 실행 계획을 계산해 내야 합니다. 그러므로 항상 최선의 실행 계획을 만들어 낼 수는 없다 이겁니다~^^ 

Oracle 10g는 옵티마이저가 튜닝 모드에서 실행될 수 있도록 하여 추가적인 통계 정보를 모아 추후에는 튜닝된 최적의 실행 계획을 만들어 낼 수 있도록 지원 합니다. 물론 이러한 프로세스는 하나의 SQL문장에 대해 몇 분이 걸릴지도 모르므로 리소스를 많이 잡아 먹는 경향이 있습니다. 

튜닝모드에서 옵티마이저가 하는 일에 대해 정리해 볼까요? 

- 통계 분석(statistics Analysis) : 옵티마이저는 오래전에 만들어진 통계 정보나 또는 통계 정보가 없는 부분에 대해 통계 정보를 생산 하는 것을 권고 하며 SQL Profile안에 부가적인 객체에 대한 통계 정보를 저장 합니다. 

- SQL Profileing : CBO(Cost Base Optimizer)로 수행될 때 SQL문을 위해서는 부가 정보들이 필요 합니다. 이러한 SQL문의 정보들을 SQL 프로파일이라는 형태로 수집해 놓습니다. 이러한 SQL 프로파일이 필요할 때마다 SQL Tuning Advisor 에 의해 업데이트됩니다. 

- 실행 경로 분석(Access Path Analysis) : 어떤 인덱스를 통해 데이터를 접근하여 추출할지를 결정 합니다. 필요하다면 SQL Access Advisor를 호출해 인덱스에 대한 권고를 요구하기도 합니다. 

- SQL 구조 분석(SQL Structure Analysis) : SQL문이 비효율적인 실행 계획을 생성할 경우 같은 결과를 보여줄 수 있는 비슷한 SQL문을 생성해 권고하는 역할을 합니다. 

이러한 Automatic SQL Tuning 특징은 EM(Enterprise Manager)의 “Advisor Central” 을 이용해서도 사용 할 수 있으며 또한 PL/SQL의 DBMS_SQLTUNE 패키지를 이용해서도 사용 가능 합니다. 본 강좌에서는 PL/SQL에 초점을 맞추어서 진행토록 하겠습니다. 

SQL Tuning Advisor 

SQL Tuning API에 접근 하기 위해서는 ADVISOR라는 권한이 있어야 합니다. 

아래처럼 하면 됩니다. 

SQL>CONN sys/password AS SYSDBA 
SQL>GRANT ADVISOR TO scott; 
SQL>CONN scott/tiger 

SQL Tuning Advisor를 사용하기 위한 첫 번째 단계는 CREATE_TUNING_TASK를 이용하여 새로운 tuning task를 만드는 일입니다. 분석되고자 하는 SQL 문장은 AWR이나 CURSOR CACHE, SQL Tuning set 또는 매뉴얼하게 만들어져 검색 될 수 있습니다. 

SET SERVEROUTPUT ON 

-- Tuning task created for specific a statement from the AWR. 
DECLARE 
l_sql_tune_task_id VARCHAR2(100); 
BEGIN 
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( 
begin_snap => 764, 
end_snap => 938, 
sql_id => '19v5guvsgcd1v', 
scope => DBMS_SQLTUNE.scope_comprehensive, 
time_limit => 60, 
task_name => '19v5guvsgcd1v_AWR_tuning_task', 
description => 'Tuning task for statement 19v5guvsgcd1v in AWR.'); 
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); 
END; 


-- Tuning task created for specific a statement from the cursor cache. 
DECLARE 
l_sql_tune_task_id VARCHAR2(100); 
BEGIN 
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( 
sql_id => '19v5guvsgcd1v', 
scope => DBMS_SQLTUNE.scope_comprehensive, 
time_limit => 60, 
task_name => '19v5guvsgcd1v_tuning_task', 
description => 'Tuning task for statement 19v5guvsgcd1v.'); 
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); 
END; 


-- Tuning task created from an SQL tuning set. 
DECLARE 
l_sql_tune_task_id VARCHAR2(100); 
BEGIN 
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( 
sqlset_name => 'test_sql_tuning_set', 
scope => DBMS_SQLTUNE.scope_comprehensive, 
time_limit => 60, 
task_name => 'sqlset_tuning_task', 
description => 'Tuning task for an SQL tuning set.'); 
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); 
END; 


-- Tuning task created for a manually specified statement. 
DECLARE 
l_sql VARCHAR2(500); 
l_sql_tune_task_id VARCHAR2(100); 
BEGIN 
l_sql := 'SELECT e.*, d.* ' || 
'FROM emp e JOIN dept d ON e.deptno = d.deptno ' || 
'WHERE NVL(empno, ''0'') = :empno'; 

l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( 
sql_text => l_sql, 
bind_list => sql_binds(anydata.ConvertNumber(100)), 
user_name => 'scott', 
scope => DBMS_SQLTUNE.scope_comprehensive, 
time_limit => 60, 
task_name => 'emp_dept_tuning_task', 
description => 'Tuning task for an EMP to DEPT join query.'); 
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id); 
END; 



만약 TASK_NAME 파라미터에 값이 있다면 SQL tune task의 식별자로서 사용 되구요, 생략된다면 시스템에서 “TASK_1478” 등과 같이 만들어서 리턴 합니다. 

NVL이 SQL 문장에 사용되다면 옵티마이저로부터 반작용을 유발 하며 부가적으로 그러한 테이블에 관한 통계정보를 지우는 것도 가능 합니다. 

EXEC DBMS_STATS.delete_table_stats('SCOTT','EMP'); 

위에서 tuning task에 대해 정의를 했는데 그 다음으로 할 일은 EXECUTE_TUNING_TASK procedure를 이용하는 일 입니다. 

EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => 'emp_dept_tuning_task'); 

물론 아래처럼 task를 중단하거나 재시작 하거나 취소하거나 하는 것들이 가능 합니다. 

-- Interrupt and resume a tuning task. 
EXEC DBMS_SQLTUNE.interrupt_tuning_task (task_name => 'emp_dept_tuning_task'); 
EXEC DBMS_SQLTUNE.resume_tuning_task (task_name => 'emp_dept_tuning_task'); 

-- Cancel a tuning task. 
EXEC DBMS_SQLTUNE.cancel_tuning_task (task_name => 'emp_dept_tuning_task'); 

-- Reset a tuning task allowing it to be re-executed. 
EXEC DBMS_SQLTUNE.reset_tuning_task (task_name => 'emp_dept_tuning_task'); 
다음과 같이 tuning task는 DBA_ADVISOER_LOG라는 뷰를 통해서 확인 가능 합니다. 

SQL>SELECT task_name, status FROM dba_advisor_log WHERE owner = 'SCOTT'; 

TASK_NAME STATUS 
------------------------------ ----------- 
emp_dept_tuning_task COMPLETED 

tuning task가 성공적으로 수행 되면 REPORT_TUNING_TASK라는 함수를 통해 권고를 확인 할 수 있습니다. 

SET LONG 10000; 
SET PAGESIZE 1000 
SET LINESIZE 200 
SELECT DBMS_SQLTUNE.report_tuning_task('emp_dept_tuning_task') AS recommendations FROM dual; 
SET PAGESIZE 24 

결과는 아래와 같습니다. 

RECOMMENDATIONS 
-------------------------------------------------------------------------------- 
GENERAL INFORMATION SECTION 
------------------------------------------------------------------------------- 
Tuning Task Name : emp_dept_tuning_task 
Scope : COMPREHENSIVE 
Time Limit(seconds): 60 
Completion Status : COMPLETED 
Started at : 05/06/2004 09:29:13 
Completed at : 05/06/2004 09:29:15 

------------------------------------------------------------------------------- 
SQL ID : 0wrmfv2yvswx1 
SQL Text: SELECT e.*, d.* FROM emp e JOIN dept d ON e.deptno = d.deptno 
WHERE NVL(empno, '0') = :empno 

------------------------------------------------------------------------------- 
FINDINGS SECTION (2 findings) 
------------------------------------------------------------------------------- 

1- Statistics Finding 
--------------------- 
Table "SCOTT"."EMP" and its indices were not analyzed. 

Recommendation 
-------------- 
Consider collecting optimizer statistics for this table and its indices. 
execute dbms_stats.gather_table_stats(ownname => 'SCOTT', tabname => 
'EMP', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, 
method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE) 

Rationale 
--------- 
The optimizer requires up-to-date statistics for the table and its indices 
in order to select a good execution plan. 

2- Restructure SQL finding (see plan 1 in explain plans section) 
---------------------------------------------------------------- 
The predicate NVL("E"."EMPNO",0)=:B1 used at line ID 2 of the execution plan 
contains an __EXPRESSION!__ on indexed column "EMPNO". This __EXPRESSION!__ prevents 
the optimizer from selecting indices on table "SCOTT"."EMP". 

Recommendation 
-------------- 
Rewrite the predicate into an equivalent form to take advantage of 
indices. Alternatively, create a function-based index on the __EXPRESSION!__. 

Rationale 
--------- 
The optimizer is unable to use an index if the predicate is an inequality 
condition or if there is an __EXPRESSION!__ or an implicit data type conversion 
on the indexed column. 

------------------------------------------------------------------------------- 
EXPLAIN PLANS SECTION 
------------------------------------------------------------------------------- 

1- Original 
----------- 
Plan hash value: 1863486531 

---------------------------------------------------------------------------------------- 
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | 
---------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT | | 1 | 107 | 4 (0)| 00:00:01 | 
| 1 | NESTED LOOPS | | 1 | 107 | 4 (0)| 00:00:01 | 
| 2 | TABLE ACCESS FULL | EMP | 1 | 87 | 3 (0)| 00:00:01 | 
| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:01 | 
| 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 | 
---------------------------------------------------------------------------------------- 

Note 
----- 
- dynamic sampling used for this statement 

------------------------------------------------------------------------------- 


1 row selected. 

Tuning task는 다음처럼 DROP 합니다. 

BEGIN 
DBMS_SQLTUNE.drop_tuning_task (task_name => '19v5guvsgcd1v_AWR_tuning_task'); 
DBMS_SQLTUNE.drop_tuning_task (task_name => '19v5guvsgcd1v_tuning_task'); 
DBMS_SQLTUNE.drop_tuning_task (task_name => 'sqlset_tuning_task'); 
DBMS_SQLTUNE.drop_tuning_task (task_name => 'emp_dept_tuning_task'); 
END; 

 

반응형

'Database > ORACLE' 카테고리의 다른 글

one port multi listener 설정 하기  (0) 2012.12.24
DBMS_XPLAN 정보 조회  (0) 2012.09.07
10G OCP 자격증 관련  (2) 2012.07.08
오라클 패키지 CURSOR(커서) 출력 값 조회  (0) 2012.02.23
일정 시간 별로 쿼리 정보 조회  (0) 2012.02.20
반응형

개발자의 실수를 줄여주는 java.sql.Connection 만들기







흔히 close()를 하지 않아서 발생하는 자원 누수 현상을 줄여주는 Connection 클래스를 만들어본다.

JDBC API 사용시 흔히 하는 개발자의 실수

JDBC API를 사용하여 데이터베이스 프로그래밍을 할 때 가장 많이 사용되는 코드는 아마도 다음과 같은 형태일 것이다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        conn = DBPool.getConnection(); //
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        if (rs != null) try { rs.close(); } catch(SQLException ex) {}
        if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
        if (conn != null) try { conn.close(); } catch(SQLException ex) {}
    }

그런데 위와 같은 프로그래밍을 할 때 흔히 하는 실수가 close()를 제대로 해 주지 않는 것이다. 특히, 하나의 메소드에서 5-10개의 (PreparedStatement를 포함한)Statement와 ResultSet을 사용하는 경우에는 개발자의 실수로 같은 Statement를 두번 close() 하고 한두개의 Statement나 ResultSet은 닫지 않는 실수를 하곤 한다. 이처럼 close() 메소드를 알맞게 호출해주지 않을 경우에는 다음과 같은 문제가 발생한다.

  1. Statement를 닫지 않을 경우, 생성된 Statement의 개수가 증가하여 더 이상 Statement를 생성할 수 없게 된다.
  2. close() 하지 않으므로 불필요한 자원(네트워크 및 메모리)을 낭비하게 된다.
  3. 커넥션 풀을 사용하지 않는 상황에서 Connection을 닫지 않으면 결국엔 DBMS에 연결된 새로운 Connection을 생성할 수 없게 된다.
위의 문제중 첫번째와 두번째 문제는 시간이 지나면 가비지 콜렉터에 의해서 해결될 수도 있지만, 만약 커넥션 풀을 사용하고 있다면 그나마 가비지 콜렉션도 되지 않는다. 따라서 커넥션 풀을 사용하는 경우 Statement와 ResultSet은 반드시 닫아주어야만 한다. 하지만, 제아무리 실력이 뛰어난 개발자라 할지라도 각각 수십에서 수백줄로 구성된 수십여개의 .java 파일을 모두 완벽하게 코딩할 수는 없으며, 따라서 한두군데는 close()를 안 하기 마련이다. 운이 좋으면 빨리 찾을 수 있겠지만, 그렇지 않다면 close() 안한 부분을 찾는 데 몇십분, 몇시간, 심한 경우 1-2일 정도가 걸리기도 한다.

Statement를 자동으로 닫아주는 MVConnection 클래스 구현

실제로 필자도 앞에서 언근했던 문제들 때문에 고생하는 사람들을 종종 봐 왔었으며, 그때마다 그 버그를 고치기 위해서 소스 코드를 일일이 찾아보는 노가다를 하는 개발자들을 보기도 했다. 그래서 만든 클래스가 있는데, 그 클래스의 이름을 MVConnection이라고 붙였다. 이름이야 여러분의 입맛에 맛게 수정하면 되는 것이므로, 여기서는 원리만 간단하게 설명하도록 하겠다.

먼저, MVConnection을 구현하기 전에 우리가 알고 있어야 하는 기본 사항이 있다. JDBC API를 유심히 읽어본 사람이라면 다음과 같은 내용을 본 적이 있을 것이다.

  • Statement를 close() 하면 Statement의 현재(즉, 가장 최근에 생성한) ResultSet도 close() 된다.
  • ResultSet은 그 ResultSet을 생성한 Statement가 닫히거나, 또는 executeQuery 메소드를 실행하는 경우 close() 된다.
MVConnection은 바로 이 두가지 특성을 사용한다. 위의 두 가지 특징을 정리하면 결국 Statement만 알맞게 닫아주면 그와 관련된 ResultSet은 자동으로 닫힌다는 것을 알 수 있다. 따라서 ConnectionWrapper 클래스는 Connection이 생성한 Statement들만 잘 보관해두었다가 각 Statement를 닫아주기만 하면 되는 것이다. PreparedStatement나 CallableStatement는 Statement를 상속하고 있으므로 따로 처리할 필요 없이 Statement 타입으로 모두 처리할 수 있으므로, PreparedStatement와 CallableStatement를 위한 별도의 코드는 필요하지 않다.

다음은 MVConnection 클래스의 핵심 코드이다.

    public class MVConnection implements Connection {
        
        private Connection conn; // 실제 커넥션
        
        private java.util.List statementList; // statement를 저장
        
        public MVConnection(Connection conn) {
            this.conn = conn;
            statementList = new java.util.ArrayList();
        }
        
        public void closeAll() {
            for (int i = 0 ; i < statementList.size() ; i++) {
                Statement stmt = (Statement)statementList.get(i);
                try {
                    stmt.close();
                } catch(SQLException ex) {}
            }
        }
        
        public void close() throws SQLException {
            this.closeAll();            conn.close();
        }
        
        public Statement createStatement() throws SQLException {
            Statement stmt = conn.createStatement();
            statementList.add(stmt);
            return stmt;
        }
        
        public CallableStatement prepareCall(String sql) throws SQLException {
            CallableStatement cstmt = conn.prepareCall(sql);
            statementList.add(cstmt);
            return cstmt;
        }
        
        public PreparedStatement prepareStatement(String sql) throws SQLException {
            PreparedStatement pstmt = conn.prepareStatement(sql);
            statementList.add(pstmt);
            return pstmt;
        }
        
        ...
    }

위 코드를 보면 Statement를 저장하기 위한 List와 그 List에 저장된 Statement 객체를 모두 닫아주는 closeAll() 이라는 메소드가 정의되어 있다. 바로 이 List와 closeAll() 메소드가 이 MVConnection 클래스의 핵심이다. Statement를 생성해주는 메소드(createStatement, prepareCall, prepareStatement)를 보면 생성된 Statement를 statemetList에 추가해주는 것을 알 수 있다. 이렇게 저장된 Statement는 실제로 Connection을 닫을 때, 즉 Connection의 close() 메소드를 호출할 때 닫힌다. (코드를 보면 close() 메소드에서 closeAll() 메소드를 먼저 호출하고 있다.) 따라서, close() 메소드만 호출하면 그와 관련된 모든 Statement와 ResultSet은 자동으로 닫히게 된다.

위 코드에서 다른 메소드들은 모두 다음과 같이 간단하게 구현된다.

    public boolean getAutoCommit() throws SQLException {
        return conn.getAutoCommit();
    }

MVConnection은 java.sql.Connection을 implements 하기 때문에, 그 자체가 Connection으로 사용될 수 있다. 따라서 MVConnection을 사용한다고 해서 특별히 코드가 많이 변경되지는 않으며 다음과 같이 전체적으로 코드가 단순하게 바뀐다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        // MV Connection 생성
        conn = new MVConnection(DBPool.getConnection());
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        // conn 만 close() 해준다.
        if (conn != null) try { conn.close(); } catch(SQLException ex) {}
    }

때에 따라서는 Connection을 close() 하지 않고 커넥션 풀에 되돌려 놔야 할 때가 있다. 그런 경우에는 다음과 같은 형태의 코드를 사용하면 된다.

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    
    try {
        // MV Connection 생성
        conn = new MVConnection(DBPool.getConnection());
        stmt = conn.createStatement();
        rs = stmt.executeQuery(..);
        ...
    } catch(SQLException ex) {
        // 예외 처리
    } finally {
        if (conn != null) try { 
            ((MVConnection)conn).closeAll();
            DBPool.returnConnection(conn);
        } catch(SQLException ex) {}
    }

즉, Connection을 닫지 않는 경우에는 위와 같이 커넥션 풀에 반환하기 전에 closeAll() 메소드 하나만을 호출해주면 된다. 그러면 Connection과 관련된 모든 Statement, ResultSet 등이 닫히게 된다.

결론

필자의 경우는 이 글에서 작성한 MVConnection을 실제 프로젝트에 응용하여 코드 작성의 편리함 뿐만 아니라 실수로 인해서 발생하는 시스템의 버그 문제를 어느 정도 해결할 수 있었다. 특히, Statement를 생성하거나 ResultSet을 생성할 때 발생하는 커서부족 문제를 획기적으로 줄일 수 있었다. 여러분도 이 클래스를 응용하여 보다 나은 방법으로 코딩의 실수 및 자원의 낭비를 줄일 수 있는 클래스를 작성해보기 바란다.

반응형
반응형


형태

오라클 계정 -> 5분 단위로 해서 -> 아래의 테이블 생성후 -> Crontab 으로 조회하여 입력하는 형태

자세한 것은 Shell, Crontab 정보를 찾으면서 하면됨

-- 임의로 실행하는 쿼리목록 조회하기
select      to_char(sysdate,'yyyymmdd'),
            to_char(sysdate, 'HH24'),
            to_char(sysdate, 'MI'),
            A.inst_id,
            A.SID,
            A.SERIAL#,
            A.USERNAME,
            A.TYPE,
            A.STATUS,
            A.STATE,
            A.EVENT,
            A.OSUSER,
            A.PROGRAM,
            A.MACHINE,
            A.SQL_ADDRESS,
            B.SQL_ID,
            B.sharable_mem,
            B.persistent_mem,
            B.runtime_mem,
            B.first_load_time,
            B.OPTIMIZER_MODE,
            B.OPTIMIZER_COST,
            B.MODULE,
            B.SQL_FULLTEXT
   from     GV$SESSION a, GV$SQL B
  WHERE     A.STATUS = 'ACTIVE'                       -- 현재 활성화된
    AND     B.ADDRESS=A.SQL_ADDRESS                   -- FULL SQL TEXT 를 얻기 위해
    AND     A.MACHINE NOT IN ('NewWas1','NewWas2')    -- 접속 Machine 이름이 NewWas1, NewWas2 는 아님
    AND     UPPER(B.SQL_FULLTEXT) NOT LIKE '%V$%';    -- V$ 로 시작하는 뷰를 보는 경우는 제외
   
   
CREATE TABLE MStorage.USER_SQL_LOG
(
      VIEW_YMD   VARCHAR2(8) DEFAULT to_char(sysdate,'yyyymmdd'),
      VIEW_HH    VARCHAR2(2) DEFAULT to_char(sysdate, 'HH24'),
      VIEW_MI    VARCHAR2(2) DEFAULT to_char(sysdate, 'MI'),
      INST_ID    NUMBER,
      SID      NUMBER,
      SERIAL#    NUMBER,
      USERNAME   VARCHAR2(30),
      TYPE     VARCHAR2(10),
      STATUS    VARCHAR2(8),
      STATE     VARCHAR2(19),
      EVENT     VARCHAR2(64),
      OSUSER    VARCHAR2(30),
      PROGRAM    VARCHAR2(48),
      MACHINE    VARCHAR2(64),
      SQL_ADDRESS RAW(8),
      SQL_ID   VARCHAR2(13),
      SHARABLE_MEM NUMBER,
      PERSISTENT_MEM NUMBER,
      RUNTIME_MEM NUMBER,
      FIRST_LOAD_TIME VARCHAR2(38),
      OPTIMIZER_MODE VARCHAR2(10),
      OPTIMIZER_COST NUMBER,
      MODULE     VARCHAR2(64),
      SQL_FULLTEXT  CLOB
) TABLESPACE MStorage;

COMMENT ON TABLE MStorage.USER_SQL_LOG IS '로그 모니터링 테이블(GV$SESSION) 참조';

 


-- 인덱스 생성
CREATE INDEX MStorage.IX_USER_SQL_LOG_01 ON MStorage.USER_SQL_LOG
(
  VIEW_YMD,VIEW_HH, VIEW_MI
)
TABLESPACE MStorage;

 


-- 실제 입력 구문

INSERT INTO MStorage.USER_SQL_LOG
       (
       inst_id,
            SID,
            SERIAL#,
            USERNAME,
            TYPE,
            STATUS,
            STATE,
            EVENT,
            OSUSER,
            PROGRAM,
            MACHINE,
            SQL_ADDRESS,
            SQL_ID,
            sharable_mem,
            persistent_mem,
            runtime_mem,
            first_load_time,
            OPTIMIZER_MODE,
            OPTIMIZER_COST,
            MODULE,
            SQL_FULLTEXT               
            )
select      A.inst_id,
            A.SID,
            A.SERIAL#,
            A.USERNAME,
            A.TYPE,
            A.STATUS,
            A.STATE,
            A.EVENT,
            A.OSUSER,
            A.PROGRAM,
            A.MACHINE,
            A.SQL_ADDRESS,
            B.SQL_ID,
            B.sharable_mem,
            B.persistent_mem,
            B.runtime_mem,
            B.first_load_time,
            B.OPTIMIZER_MODE,
            B.OPTIMIZER_COST,
            B.MODULE,
            B.SQL_FULLTEXT
   from     GV$SESSION a, GV$SQL B
  WHERE     1=1-- A.STATUS = 'ACTIVE'                       -- 현재 활성화된
    AND     B.ADDRESS=A.SQL_ADDRESS                   -- FULL SQL TEXT 를 얻기 위해
    AND     A.MACHINE NOT IN ('NewWas1','NewWas2')    -- 접속 Machine 이름이 NewWas1, NewWas2 는 아님
    AND     UPPER(B.SQL_FULLTEXT) NOT LIKE '%V$%';    -- V$ 로 시작하는 뷰를 보는 경우는 제외

반응형
반응형

관련 오류 및 해결 방법

1. VM 구동시 heap 사이즈 부족

   Error occurred during initialization of VM
   Could not reserve enough space for object heap 

기본적으로 할당되는 힙 사이즈가 VM에서 사용할 사이즈보다 작아서 생기는 문제

해결 방법

명시적으로 해결함

첫번째 방법

 sqldeveloper\bin\sqldeveloper.conf 파일안에   아래의 한줄을 추가함.

    AddVMOption -Xmx256M 
 

   (최대 256M로 할당함.)   
 

두번째 방법

 환경 변수를 설정함

On Linux
setenv EXTRA_JAVA_PROPERTIES "-Xms512m -Xmx512m"

On Windows
set EXTRA_JAVA_PROPERTIES="-Xms512m -Xmx512m"

출처 : http://itknowledgeexchange.techtarget.com/itanswers/vm-could-not-reserve-enough-space-for-object-heap-from-oracle-jdeveloper11g/

위와 같이 BAT 파일을 반들어 위 줄을 추가하는 방식 또는

사실 환경변수 설정(JAVA_HOME 설정하듯이)을 통해 가능하게 함.
 


 2. Java 찾는 중 에러

    Unable to create an instance of the java virtual machine located at path

위의 1번 방법을 통해 대부분 해결되나

혹,

sqldeveloper\bin\sqldeveloper.conf   파일안에

SetJavaHome 환경 변수에

../../jdk 라고 되어 있는 값 때문에 안될 수 있음(윈도우 환경)

즉,

 SetJavaHome ../../jdk  ====>  SetJavaHome ..\..\jdk

로 변경 해주면 됨...
   
반응형
반응형

cooxietoolbar : cooxie 송수신 정보를 수정 프로그램
burp suite : 웹페이지 송수신 데이터 조작 프로그램
sql-gate : DB 관련 프로그램
반응형
반응형

출처 : http://westzero.net/40

이 글을 클릭하셨다면 log4sql 이 뭔지는 다들 알고 들어 오셨을겁니다.
만약 모르신다면 제가 일전에 소개한 포스트 'System.out.println()은 잊어라 log4sql이 온다.'를 보고오시면 됩니다.

※ 이 글은 제우스에서 DataSource를 사용할 경우에만 해당되는 사항입니다.

log4sql은 직접적으로 DataSource를 지원하지 않습니다. 그리고 제우스에서도 직접적으로 드라이버 클래스를 지정할 수 없습니다.
따라서 제우스에서는 원하는 드라이버 클래스를 지정하려면 BlackboxConnectionPoolDataSource를 사용해야 합니다.

지정하는 방법은 다음 순서대로 따라하시면 됩니다.
  1. 먼저 log4sql.jar를 $JEUS_HOME/lib/application 경로에 넣어 주세요.
  2. $JEUS_HOME/호스트명/JEUSMain.xml 파일을 열어 다음과 같이 수정하세요
    [code]
    <database>
        <vendor>oracle</vendor>
        <export-name>oracledb</export-name>
        <data-source-class-name>jeus.jdbc.driver.blackbox.BlackboxConnectionPoolDataSource</data-source-class-name>
        <data-source-type>ConnectionPoolDataSource</data-source-type>
        <property>
            <name>DriverClassName</name>
            <type>java.lang.String</type>
            <value>core.log.jdbc.driver.OracleDriver</value>
        </property>
        <property>
            <name>URL</name>
            <type>java.lang.String</type>
            <value>jdbc:oracle:thin:@192.169.30.244:1521:ora9i</value>
        </property>
        <property>
            <name>User</name>
            <type>java.lang.String</type>
            <value>scott</value>
        </property>
        <property>
            <name>Password</name>
            <type>java.lang.String</type>
            <value>tiger</value>
        </property>
    </database>
    [/code]
  3. 이제 제우스를 실행시켜서 적용이 되었는지 확인하면 됩니다.
생각보다 간단하게 끝났습니다.^^

저는 BlackboxConnectionPoolDataSource을 몰라서 약 3일간 삽질을 하다가 티맥스 테크넷의 'Spy를 사용하여 SQL 로그 보기' 를 보고 알았습니다. 그리고 나중에 찾아보니 테크넷에 저보다 먼저 log4sql 적용 방법을 문의하신 분도 계시더군요.

테크넷은 회원가입을 해야하고 쉽게 찾기가 어려워 이렇게 따로 포스팅을 올립니다.
이렇게 포스트로 작성하면 구글링으로 쉽게 찾을 수 있을꺼에요.^^
반응형

'WAS > JEUS' 카테고리의 다른 글

JAVA Melody Jeus 추가  (0) 2019.12.02
JEUS 5 세션 공유  (0) 2011.03.09
JEUSMain.xml Datasource 암호 설정  (0) 2011.01.13
IBM JVM 튜닝 - 3  (0) 2009.08.24
제우스 환경 설정 부분  (0) 2009.03.05
반응형

log4sql은 많이 알려지진 않았지만 상당히 유용한 sql 로거입니다. 만든 분은 송인섭이라는분인데 한국분이신것 같습니다.

 기존에 우리는 sql을 디버깅 하기 위해서 대부분 System.out.println()을 사용했습니다. log4j를 이용해서 sql을 콘솔에 찍기도 하고 jdbc관련 클래스를 만들어서 사용하는 경우에도 결국엔 System.out.println()을 사용하게 됩니다. 하지만 sql을 이렇게 콘솔로 표현하게 되면 여러가지 불편한 점들이 생깁니다.
 가장 큰 문제점이 바로 소스는 소스대로, 콘솔은 콘솔대로 가독성이 떨어지게 됩니다. 소스상에서 System.out을 사용하게되면 개발이 끝나도 운영에 들어가게되면 이 부분을 주석처리하거나 다른 설정을 하게됩니다.
 또한 콘솔에서 보여질때 sql을 소스상에서 들여쓰기를 해주지 않았다면 단순한 sql은 괜찮지만 복잡한 sql은 볼때마다 매번 들여쓰기를 해주어야 한다는 단점이 있습니다. log4sql은 이러한 문제를 해결하기 위해서 간단히 드라이버 설정만 바꿔주면 System.out.println()을 사용하지 않아도, 소스상에서 들여쓰기를 해주지 않아도 콘솔에 예쁘게 들여쓰기가 된 sql을 보여줍니다.

log4sql이 뭔가요?

간단하게 log4sql이 무엇인지 백번 설명을 하기보다는 한번 보는게 확실히 이해하기 쉬울꺼 같습니다.
사용자 삽입 이미지
저 노란색 박스안에 나타난 내용이 log4sql에서 자동으로 찍어준 내용입니다. sql이 실행된 시간과 실행된 메소드, sql이 실행되는데 소요된 시간, 실행된 sql을 자동으로 들여쓰기를 해서 보여주고 있습니다.

log4sql의 장점

1. 자동 들여쓰기
일반적으로 콘솔에 들여쓰기가 된 sql을 보려면 다음과 같은 코드를 작성해야 했습니다.
1
2
3
4
StringBuffer  var11 = new StringBuffer();<BR>
var11.append("SELECT * \n");<BR>
var11.append(" FROM   emp \n");<BR>
var11.append(" WHERE  deptno = '30' \n");<BR>
하지만 더이상 이런 부분은 신경 쓰지않아도 됩니다. log4sql을 사용한다면 말이죠.

2. 페이지 반응속도가 느리다구요?
log4sql은 쿼리가 실행되는데 걸린 시간을 표시해줍니다. 어느 부분이 느린지 어느 쿼리가 느린지 콘솔을 보기만 하면 알 수 있습니다.

3. 이 쿼리가 어디서 날린 쿼리지?
log4sql은 쿼리가 실행된 메소드도 표시해 줍니다. 하지만 쿼리를 날리는 클래스를 별도로 두고 해당 클래스를 이용해서 쿼리를 날리게 되면 log4sql도 어쩔수 없답니다.^^;;

어떻게 사용하나요?

간단합니다. JDBC 관련 설정에서 드라이버 설정만 바꿔주면 됩니다. 예를 들어 오라클을 사용하는 경우 기존에 'oracle.jdbc.drirver.OracleDriver' 드라이버를 사용했다면 'core.log.jdbc.driver.OracleDriver'로 바꿔주기만 하면 됩니다. 이제 log4sql을 사용할 준비가 된겁니다. 이제 WAS를 올리고 콘솔을 한번 보세요. sql이 깔끔하게 정리되어서 나타날꺼에요.^^
다른 디비를 사용하시는 경우에는 log4sql 홈페이지에서 확인하시면 됩니다.

다음에는 log4sql의 상세 설정에 대해서도 알아보도록 하겠습니다.

반응형
반응형

개발환경에서 JAVA + ORACLE + JSP 일반적인 환경에서

ORACLE은 일반적으로 PL/SQL을 사용한다

그런데,,,

이 PL/SQL을 사용하다보면 JAVA + JSP를 통한 debugging 을 하기가 굉장히 어렵고

제대로 변수가 입력되었는지... 잘 동작하는지 찾기 어렵다.

그래서... 인터넷 검색을 하다보니

log4j 처럼

log4sql이라는 lib가 있다는 것을 알았다...

프로젝트 홈 : http://log4sql.sourceforge.net/index_kr.html

  Download log4sql-7.0.8



홈페이지에서 보면,

개발을 할경우 우리는 무수히 많은 프레임웍과 도구들을 사용 합니다.
View계층, Model계층 그리고 Controller또는 DataAcess계층에서 많은 도구들과 프레임웍은
현재 거의 모든 layer들에 걸쳐서 사용되고 개발되어지고 있습니다.
이런경우 개발자에게 중요한것중의 하나는 비즈니스 로직인 PL/SQL작업을 하는 것 입니다.
모든 PL/SQL작업은 SQL을 작성하고 실행한 후에 버그가 존재하가나 원하는 결과가 나오지 않을경우 수정하는 것이며
이런작업은 반복적으로 수행됩니다.
이런 경우에 우리는 jdbc또는 Connection Pooling(Apache DBCP) 또는 support 2PC (JTA,JOTM)등을 사용합니다.
또한 우리는 데이터 접근계층의 프레임웍으로 IBATIS나 SpringFramework을 사용할 경우 springJDBC또는 HIBERNATE등을 사용합니다.
이런 상황에서 우리는 의문을 갖게 됩니다. '내가 작성한 SQL이 정상적으로 작동한 것인가?', '내가 입력값으로 넣어준 값들이 제대로 등록된 SQL인가?'
SQL을 확인하고자 개발 소스의 구석구석에 System.out.println(...)으로 확인을 할 것입니다.
개발이 종료된 시점에 주석으로 가려진 가독성이 떨어지는 소스는 유지보수담당자에게 머리아픈 소스가 될 것이고
운영상에 문제가 발생할 경우 해당 SQL을 다시 확인하는 복잡한 작업이 반복될 것입니다.
이런경우를 경험한 개발자라면 log4sql은 간단한 설정으로 많은 편리함을, 개발의 즐거움을 당신에게 드릴것 입니다.

기본 apache common lang lib를 의존한다. : http://commons.apache.org/lang/

오픈 소스이며 apache 라이센스를 따른다 : http://www.apache.org/licenses/LICENSE-2.0





특징들

1.쉬운 설정.
log4sql은 굉장히 간단한 설정을 지원합니다.
개발자들이 할 일은 log4sql-xxx.jar파일을 클래스패스에 복사한 후에
사용하고 있는 driver-class 이름을 log4sql에서 지원하는 driver-class명으로만 바꿔주시면 됩니다.

 2.개발성 향상.
 log4sql은 SQL파라미터 매치된 로그뿐 아니라, 로그의 위치와 걸린시간 그리고 수행결과(INSERT,UPDATE,DELETE)를 보여드립니다.

 3. SQL실행시간을 가장 정확히 파악합니다.
log4sql은 실제 서비스와 동일한 시점의 순수한 SQL실행 시간만을 나타냅니다.
즉 이것은 Connection을 얻어오거나, Connection Pooling기법을 사용하더라도, 실제 작성된 SQL이 DBMS에 전달된 후 결과 값을 받아오기까지의 걸린 시간만을 측정하여
성능에 이상이 있는 SQL등을 쉽게 확인 할 수 있습니다.
 
 4. Application의 성능과 실행에 영향을 주지 않습니다.
 log4sql은 내부적인 문제가 존재하더라도 실제 Application에 영향을 주지는 않습니다.
내부적인 문제가 발생할 경우 해당로그는 설정변경으로 확인이 가능하며, 동시접속사용자가 많은경우 log4sql은 비동기 모드로의 전환이 실행환경에서 가능하도록 설계되었습니다.

5.어떤 유형의 프로젝트라도 적용이 가능합니다.
 JDK1.4이상의 아래의 JDBC드라이버 리스트를 사용하는 어떤 프로젝트라도 사용이 가능합니다.

[ORACLE DRIVER CLASS] 'oracle.jdbc.drirver.OracleDriver'
[MYSQL DRIVER CLASS] 'com.mysql.jdbc.Driver' or 'org.gjt.mm.mysql.Driver'
[SYBASE DRIVER CLASS] 'com.sybase.jdbc2.jdbc.SybDriver'
[DB2 DRIVER CLASS] 'com.ibm.db2.jcc.DB2Driver'
[INFOMIX DRIVER CLASS] 'com.informix.jdbc.IfxDriver'
[POSTGRESQL DRIVER CLASS] 'org.postgresql.Driver'
[MAXDB DRIVER CLASS] 'com.sap.dbtech.jdbc.DriverSapDB'
[FRONTBASE DRIVER CLASS] 'com.frontbase.jdbc.FBJDriver'
[HSQL DRIVER CLASS] 'org.hsqldb.jdbcDriver'
[POINTBASE DRIVER CLASS] 'com.pointbase.jdbc.jdbcUniversalDriver'
[MIMER DRIVER CLASS] 'com.mimer.jdbc.Driver'
[PERVASIVE DRIVER CLASS] 'com.pervasive.jdbc.v2.Driver'
[DAFFODILDB DRIVER CLASS] 'in.co.daffodil.db.jdbc.DaffodilDBDriver'
[JDATASTORE DRIVER CLASS] 'com.borland.datastore.jdbc.DataStoreDriver'
[CACHE DRIVER CLASS] 'com.intersys.jdbc.CacheDriver'
[DERBY DRIVER CLASS] 'org.apache.derby.jdbc.ClientDriver'
[ALTIBASE DRIVER CLASS] 'Altibase.jdbc.driver.AltibaseDriver'
[MCKOI DRIVER CLASS] 'com.mckoi.JDBCDriver'
[JSQL DRIVER CLASS] 'com.jnetdirect.jsql.JSQLDriver'
[JTURBO DRIVER CLASS] 'com.newatlanta.jturbo.driver.Driver'
[JTDS DRIVER CLASS] 'net.sourceforge.jtds.jdbc.Driver'
[INTERCLIENT DRIVER CLASS] 'interbase.interclient.Driver'
[PURE JAVA DRIVER CLASS] 'org.firebirdsql.jdbc.FBDriver'
[JDBC-ODBC DRIVER CLASS] 'sun.jdbc.odbc.JdbcOdbcDriver'
[MSSQL 2000 DRIVER CLASS] 'com.microsoft.jdbc.sqlserver.SQLServerDriver'
[MSSQL 2005 DRIVER CLASS] 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
[CUBRID DRIVER CLASS] 'cubrid.jdbc.driver.CUBRIDDriver'



사용법

 1.log4sql-xxx.jar파일을 클래스패스에 복사하십시요.
log4sql-xxx.zip파일은 sourceforge에서 다운로드한 후 압축을 해제합니다.
그리고나서 압축을 해제한 폴도에 가서 log4sql-xxx.jar을 복사한후 SQL로그를 보고자하는 어플리케이션을 lib디렉토리에 복사합니다.

 2.Driver Class이름을 변경합니다.
만약 Oracle Driver를 사용하신다면 driver-class의 설정은 아마도 아래와 같을 것입니다. <driver class='oracle.jdbc.driver.OracleDriver'>와 같다면 <driver class='core.log.jdbc.driver.OracleDriver'>로 변경하면 됩니다.
아래의 리스트는 log4sql에서 지원하고 있는 driver의 리스트 입니다.



JDBC TYPE Origin Your Driver Class -> log4sql Driver Class
[ORACLE DRIVER CLASS] oracle.jdbc.drirver.OracleDriver -> core.log.jdbc.driver.OracleDriver
[MYSQL DRIVER CLASS] com.mysql.jdbc.Driver' or'org.gjt.mm.mysql.Driver -> core.log.jdbc.driver.MysqlDriver
[SYBASE DRIVER CLASS] com.sybase.jdbc2.jdbc.SybDriver -> core.log.jdbc.driver.SybaseDriver
[DB2 DRIVER CLASS] com.ibm.db2.jcc.DB2Driver -> core.log.jdbc.driver.DB2Driver
[INFOMIX DRIVER CLASS] com.informix.jdbc.IfxDriver -> core.log.jdbc.driver.InfomixDriver
[POSTGRESQL DRIVER CLASS] org.postgresql.Driver -> core.log.jdbc.driver.PostgresqlDriver
[MAXDB DRIVER CLASS] com.sap.dbtech.jdbc.DriverSapDB -> core.log.jdbc.driver.MaxDBDriver
[FRONTBASE DRIVER CLASS] com.frontbase.jdbc.FBJDriver -> core.log.jdbc.driver.FrontBaseDriver
[HSQL DRIVER CLASS] org.hsqldb.jdbcDriver -> core.log.jdbc.driver.HSQLDriver
[POINTBASE DRIVER CLASS] com.pointbase.jdbc.jdbcUniversalDriver -> core.log.jdbc.driver.PointBaseDriver
[MIMER DRIVER CLASS] com.mimer.jdbc.Driver -> core.log.jdbc.driver.MimerDriver
[PERVASIVE DRIVER CLASS] com.pervasive.jdbc.v2.Driver -> core.log.jdbc.driver.PervasiveDriver
[DAFFODILDB DRIVER CLASS] in.co.daffodil.db.jdbc.DaffodilDBDriver -> core.log.jdbc.driver.DaffodiLDBDriver
[JDATASTORE DRIVER CLASS] com.borland.datastore.jdbc.DataStoreDriver -> core.log.jdbc.driver.JdataStoreDriver
[CACHE DRIVER CLASS] com.intersys.jdbc.CacheDriver -> core.log.jdbc.driver.CacheDriver
[DERBY DRIVER CLASS] org.apache.derby.jdbc.ClientDriver -> core.log.jdbc.driver.DerbyDriver
[ALTIBASE DRIVER CLASS] Altibase.jdbc.driver.AltibaseDriver -> core.log.jdbc.driver.AltibaseDriver
[MCKOI DRIVER CLASS] com.mckoi.JDBCDriver -> core.log.jdbc.driver.MckoiDriver
[JSQL DRIVER CLASS] com.jnetdirect.jsql.JSQLDriver -> core.log.jdbc.driver.JsqlDriver
[JTURBO DRIVER CLASS] com.newatlanta.jturbo.driver.Driver -> core.log.jdbc.driver.JturboDriver
[JTDS DRIVER CLASS] net.sourceforge.jtds.jdbc.Driver -> core.log.jdbc.driver.JTdsDriver
[INTERCLIENT DRIVER CLASS] interbase.interclient.Driver -> core.log.jdbc.driver.InterClientDriver
[PURE JAVA DRIVER CLASS] org.firebirdsql.jdbc.FBDriver -> core.log.jdbc.driver.PureJavaDriver
[JDBC-ODBC DRIVER CLASS] sun.jdbc.odbc.JdbcOdbcDriver -> core.log.jdbc.driver.JdbcOdbcDriver
[MSSQL 2000 DRIVER CLASS] com.microsoft.jdbc.sqlserver.SQLServerDriver -> core.log.jdbc.driver.MssqlDriver
[MSSQL 2005 DRIVER CLASS] com.microsoft.sqlserver.jdbc.SQLServerDriver -> core.log.jdbc.driver.Mssql2005Driver
[CUBRID DRIVER CLASS] cubrid.jdbc.driver.CUBRIDDriver -> core.log.jdbc.driver.CUBRIDDriver






설정하기

 우리는 log4sql_conf.jsp페이지를 통해서 보다 쉬운 운영상의 설정페이지를 제공합니다.
 
log4sql-xxx.zip파일을 sourceforge싸이트에서 다운로드한 후에 압축을 풀게되면 log4jsq_conf.jsp파일을 [log4sql-xxx.zip]/log4sql_conf.jsp에서 볼 수 있습니다.
log4sql_conf.jsp파일을 개발하고 있는 어플리케이션의 context-root에 복사하세요
(만약 개발중인 어플리케이션 서버의 context_root이름이 'site-root'이고 context_root까지의 디렉토리 구조가 'c://application/domain/site_root'와 같다면 log4sql_conf.jsp를 'c://application/domain/site_root/log4sql_conf.jsp'처럼 복사하세요)
그런 후에 log4sql_conf.jsp을 브라우져로 열기 위해서 'http://개발ip:개발port/site_root/log4sql_conf.jsp'처럼 접근합니다.

log4sql_sql.jsp의 형태는 아래와 같은 그림이 보여질것 입니다.


l환경설정에 사용되어지는 속성값들은 log4sql_configuration.properties에 위치하고 있으며,
항상 같은 설정이 적용되어지길 원할경우 [log4sql-xxx.jar]/core/log/log4sql_configuration.properties의 위치에서 해당항목의 값을 변경하시면 됩니다.


 1.Log Level(log4sql_configuration.properties 파일에서 'log.level'항목을 참조함).
Log Level은 로그를 남길경우의 우선 순위를 얘기하며, Log4j를 알고계신다면 쉽게 이해가 되실겁니다.
log4sql의 로그는 기본적으로 모두 DEBUG의 형태로 되어있으므로 DEBUG값 이상으로 로그레벨을 변경하게 되면 정상적인 로그를 남기지 않게 됩니다.
로그레벨의 종류는 DEBUG=0,INFO=1,WARNING=2,FATAL=3, ERROR=4, LOGGING_OFF=5와 같으며,
SQL수행도중에 구문문제 또는 잘못된 파라미터 INDEX에러가 발생하게 되면 자동으로 해당 SQL과 원인(Root cause Exception trace)를
ERROR 로그레벨로 남기게 되며, 모든 로그(Error 로그포함)를 남기지 않으려면 로그레벨을 LOGGING_OFF로 변경하시면 됩니다.

 2.Select Fix(log4sql_configuration.properties 파일에서 'query.logging.position.fixed.select'항목을 참조함).
 SELECT SQL에만 해당됩니다.
log4sql은 많은경우에 사용되어질 수 있도록 만들어 졌습니다.
따라서 우리는 log4sql을 사용하는 어플리케이션에서 어떠한 프레임웍을 사용하는지, 어떤 서버에서 실행되는지 알수가 없습니다.
문제가 있는 SQL일경우 사용자는 DEBUGING을 해야 할 것입니다. 그러기 위해선 어떤 클래서에서, 어떤 메소드에서 실행이 되었는지 알아야합니다.
log4sql은 SQL을 실행시킨 패키지와 클래스 그리고 어떤 메소드의 몇번째 라인에서 실행이 되었는지 실행된 시간과 함께 나타내 줍니다.
하지만, 위와같은 이유로 적합한 위치가 아닐수도 있으므로 log4sql은 적합한 위치를 사용자가 선택할 수 있도록 모든 실행에 참여한 클래스와 메소드들의 항목을 모두 보여줍니다.

 3.Select Position(log4sql_configuration.properties파일에서 'query.logging.position.select'항목을 참조함).
 2번 항목에서 적합하다고 생각되는 항목의 번호를 Select Position에 입력한 후 확인 버튼을 클릭하거나, 영구적으로 변경을 원하는 경우는 log4sql_configuration.properties에서 query.logging.position.select항목의 값으로 변경하시면 됩니다

 4.None Select Fix(log4sql_configuration.properties파일에서 'query.logging.position.fixed.none_select'항목을 참조함).
 INSERT, UPDATE, DELETE SQL에만 해당됩니다.
log4sql은 많은경우에 사용되어질 수 있도록 만들어 졌습니다.
따라서 우리는 log4sql을 사용하는 어플리케이션에서 어떠한 프레임웍을 사용하는지, 어떤 서버에서 실행되는지 알수가 없습니다.
문제가 있는 SQL일경우 사용자는 DEBUGING을 해야 할 것입니다. 그러기 위해선 어떤 클래서에서, 어떤 메소드에서 실행이 되었는지 알아야합니다.
log4sql은 SQL을 실행시킨 패키지와 클래스 그리고 어떤 메소드의 몇번째 라인에서 실행이 되었는지 실행된 시간과 함께 나타내 줍니다.
하지만, 위와같은 이유로 적합한 위치가 아닐수도 있으므로 log4sql은 적합한 위치를 사용자가 선택할 수 있도록 모든 실행에 참여한 클래스와 메소드들의 항목을 모두 보여줍니다

 5.None Select Position(log4sql_configuration.properties파일에서 'query.logging.position.none_select'항목을 참조함).
4번 항목에서 적합하다고 생각되는 항목의 번호를 Select Position에 입력한 후 확인 버튼을 클릭하거나, 영구적으로 변경을 원하는 경우는 log4sql_configuration.properties에서 query.logging.position.select항목의 값으로 변경하시면 됩니다.

 6.View Parameter Position(log4sql_configuration.properties파일에서 'query.logging.view.position'항목을 참조함).
 PreparedStatement를 사용할 경우 원하는 결과가 나오지 않을경우 해당 파리미터의 값이 적당하게 메치되었는지 궁금하게 됩니다.
이럴경우 개발자들은 난감한 상황에 접하게 됩니다. log4sql은 모든 파라미터가 결합된 SQL로그를 보여줍니다.
하지만, SQL문자열에 직접 입력된 값이 존재할 경우 개발자는 어떤값이 입력된 값인지, 어떤값이 문자열에 존재하는 값인지 혼동을 할 수 있습니다.
View Parameter Position값을 'true'로 변경할 경우 SQL log에서 입력된 값의 좌측에 '/**P*/'와 같은 표시를 보여줍니다. .

 7.View Internal Error(log4sql_configuration.properties파일에서 'query.logging.view.internal.exception'항목을 참조함).
 log4sql은 내부적인 문제가 있더라도 실제 SQL의 실행에는 영향을 미치지 않습니다.
log가 출력되지 않는 비정상적인 경우에 View Internal Error의 값을 'true'로 변경할 경우 내부적인 오류라면 오류의 내용을 출력할 것입니다.
이 내용은 사용자에게 고맙지 않은 경우일 것이나, 해당 내용을 log4sql개발팀에게 보내준다면 보다 견고한 버젼으로의 변경이 용이할 것입니다.

 8.Log To Asynchronous(log4sql_configuration.properties파일에서 'query.logging.asynchronous'항목을 참조함).
 log4sql은 SQL로그의 출력에 있어서 두가지 방법을 사용합니다. 동기적인 경우(Log To Asynchronous의 값을 'false'로 변경할 경우)모든 SQL로그는 순차적으로 실행이 될 것입니다.
이경우 log4sql에서의 모든 작업이 수행된 후에 다음 작업을 수행 할 것입니다.(많은 동시접속자가 존재하는 많은 로그가 출력되고 있는 상황에서 성능에 영향을 줄 수가 있습니다.
하지만 개발시 소수의 개발자에 의해서 디버그 용도로 실행되고 있을경우는 거의 영향을 주지 않습니다.) 비동기적인 경우(Log To Asynchronous의 값을 'true'로 변경할 경우)모든 SQL로그는 항상 순차적으로 실행되지 않습니다.
이경우 log4sql에서의 모든 작업과 SQL로그를 남기는 작업은 별도의 Thread로 동작할 것입니다.(많은 동시접속자가 존재(300tps)하는 많은 로그가 출력되고 있는 상황에서 성능을
보장하여 줄 것이나 이경우 로그는 순차적으로 남기지 않습니다.)

 9.View Appointed Package(log4sql_configuration.properties파일에서 'query.logging.view.appoint'항목을 참조함).
 아마도 개발자 혼자서 모든 개발을 진행하는 일은 흔치 않을것입니다.
따라서 log4sql은 개발자가 개발하고 있는 패키지 혹은 클래스 혹은 메소드에 한해서만 로그를 남길수 있습니다.
설정의 방법은 아래의 내용을 참조하세요.

[예약된 기호들]*..* : 모든 패키지를 의미합니다, * : 모든 클래스를 의미합니다, (..) : 모든 메소드들을 의미합니다
View Appointed Package의 값을 *..*.*.(..)로 입력한다면 실행 되고있는 모든 SQL로그가 보여질 것 입니다.
parttern 1 : *..*.*.(..) (모든 로그가 보여집니다.)
parttern 2 : net.*..*.*.(..) ('net'으로 시작되는 패키지 하위의 SQL모든 클래스의 로그가 출력됩니다.)
parttern 3 : *..*.Package_name.*..*.*.(..) ('Package_name'이 중간에 포함된 패키지의 로그가 보여집니다.)
parttern 4 : *..*.Package_name.*.(..)('Package_name'으로끝나는 모든 패키지의 로그가 보여집니다.)
parttern 5 : *..*.Class_name.(..) (클래스 이름이 'Class_name'인 곳의 로그가 보여집니다.)
parttern 6 : *..*.Package_name.Class_name.(..) (패지지가 'Package_name'로 종료되고 클래스 이름이 'Class_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 7 : *..*.Package_name.*..*.Class_name.(..) (패키지가 'Package_name'을 포함하고 있고 클래스 이름이 'Class_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 8 : *..*.Package_name.Class_name.Method_name (패키지의 이름이 'Package_name'로 종료되며, 클래스의 이름이 'Class_name'이고 메소드의 이름이 'Method_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 9 : *..*.Package_name.*..*.Class_name.Method_name (패키지의 이름이 'Package_name'을 포함하고 있고 클래스 이름이 'Class_name'이고 메소드 이름이 'Method_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 10 : *..*.Class_name.Method_name (모든 패키지에서 클래스 이름이 'Class_name'이고 메소드 이름이 'Method_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 11 : *..*.Package_name.*.Method_name (패키지 이름이 'Package_name'로 종료되고 메소드 이름이 'Method_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 12 : *..*.Package_name.*..*.*.Method_name (패키지 이름에서 'Package_name'를 포함하고 있고 메소드 이름이 'Method_name'인 곳의 SQL 로그가 출력됩니다.)
parttern 13 : *..*.*.Method_name (모든 패키지와 모든 클래스 중에서 메소드 이름이 'Method_name'인 곳의 SQL모든 로그가 출력됩니다.)
parttern 14 : net.sourceforge.log4sql.Class_name.Method_name (패키지가 'net.sourceforge.log4sql'이고 클래스 이름이 'Class_name'이고 메소드 이름이 'Method_name'인 곳의 SQL로그가 출력됩니다.)


p.$. : 아직 사용해 보진 않았다... 사용해야 하는데... 우선 간략하게 정리해본다... 쿠쿠... 시간나면 더 추가 ㄱ ~



반응형
반응형

  SELECT   ROUND (BITAND (s.ownerid, 65535)) parent_session_sid,
           ROUND (BITAND (s.ownerid, 16711680) / 65536) parent_session_instid,
           s.INST_ID,
           s.SADDR,
           s.SID,
           s.SERIAL#,
           s.AUDSID,
           s.PADDR,
           s.USER#,
           s.USERNAME,
           s.COMMAND,
           s.OWNERID,
           s.TADDR,
           s.LOCKWAIT,
           s.STATUS,
           s.SERVER,
           s.SCHEMA#,
           s.SCHEMANAME,
           s.OSUSER,
           s.PROCESS,
           s.MACHINE,
           s.PORT,
           s.TERMINAL,
           UPPER (s.PROGRAM) PROGRAM,
           s.TYPE,
           s.SQL_ADDRESS,
           s.SQL_HASH_VALUE,
           s.SQL_ID,
           s.SQL_CHILD_NUMBER,
           s.PREV_SQL_ADDR,
           s.PREV_HASH_VALUE,
           s.PREV_SQL_ID,
           s.PREV_CHILD_NUMBER,
           s.PLSQL_ENTRY_OBJECT_ID,
           s.PLSQL_ENTRY_SUBPROGRAM_ID,
           s.PLSQL_OBJECT_ID,
           s.PLSQL_SUBPROGRAM_ID,
           s.MODULE,
           s.MODULE_HASH,
           s.ACTION,
           s.ACTION_HASH,
           s.CLIENT_INFO,
           s.FIXED_TABLE_SEQUENCE,
           s.ROW_WAIT_OBJ#,
           s.ROW_WAIT_FILE#,
           s.ROW_WAIT_BLOCK#,
           s.ROW_WAIT_ROW#,
           s.LOGON_TIME,
           s.LAST_CALL_ET,
           s.PDML_ENABLED,
           s.FAILOVER_TYPE,
           s.FAILOVER_METHOD,
           s.FAILED_OVER,
           s.RESOURCE_CONSUMER_GROUP,
           s.PDML_STATUS,
           s.PDDL_STATUS,
           s.PQ_STATUS,
           s.CURRENT_QUEUE_DURATION,
           s.CLIENT_IDENTIFIER,
           s.BLOCKING_SESSION_STATUS,
           s.BLOCKING_INSTANCE,
           s.BLOCKING_SESSION,
           s.SEQ#,
           s.EVENT#,
           s.EVENT,
           s.P1TEXT,
           s.P1,
           s.P1RAW,
           s.P2TEXT,
           s.P2,
           s.P2RAW,
           s.P3TEXT,
           s.P3,
           s.P3RAW,
           s.WAIT_CLASS_ID,
           s.WAIT_CLASS#,
           s.WAIT_CLASS,
           s.WAIT_TIME,
           s.SECONDS_IN_WAIT,
           s.STATE,
           s.SERVICE_NAME,
           s.SQL_TRACE,
           s.SQL_TRACE_WAITS,
           s.SQL_TRACE_BINDS,
           s.ECID,
           stat.cpu - stat.CPU_this_call_start cpu_this_call,
           stat.CPU,
           stat.UGA_memory,
           stat.PGA_memory,
           stat.Commits,
           stat.Rollbacks
    FROM   GV$SESSION S,
           (  SELECT   ss.inst_id stat_inst_id,
                       ss.sid stat_sid,
                       SUM(DECODE (sn.name,
                                   'CPU used when call started', ss.VALUE,
                                   0))
                          CPU_this_call_start,
                       SUM(DECODE (sn.name,
                                   'CPU used by this session', ss.VALUE,
                                   0))
                          CPU,
                       SUM (DECODE (sn.name, 'session uga memory', ss.VALUE, 0))
                          uga_memory,
                       SUM (DECODE (sn.name, 'session pga memory', ss.VALUE, 0))
                          pga_memory,
                       SUM (DECODE (sn.name, 'user commits', ss.VALUE, 0))
                          commits,
                       SUM (DECODE (sn.name, 'user rollbacks', ss.VALUE, 0))
                          rollbacks
                FROM   GV$sesstat ss, GV$statname sn
               WHERE   ss.STATISTIC# = sn.STATISTIC# AND ss.inst_id = sn.inst_id
                       AND (   sn.name = 'CPU used when call started'
                            OR sn.name = 'CPU used by this session'
                            OR sn.name = 'session uga memory'
                            OR sn.name = 'session pga memory'
                            OR sn.name = 'user commits'
                            OR sn.name = 'user rollbacks')
            GROUP BY   ss.inst_id, ss.sid) stat
   WHERE   (    (s.USERNAME IS NOT NULL)
            AND (NVL (s.osuser, 'x') <> 'SYSTEM')
            AND (s.TYPE <> 'BACKGROUND'))
           AND ( (stat.stat_inst_id = s.inst_id) AND (stat.stat_sid = s.sid))
ORDER BY   "PROGRAM", OWNERID
반응형
반응형

SQL Plus 명령어 모음

 명령어  설명
 L[IST]  SQL PLUS 버퍼상에 있는 내용을 출력
 L[IST] m   SQL PLUS 버퍼상에 있는 m번째 라인만 출력
 L[IST] m n  SQL PLUS 버퍼상에 있는 m번째 라인부터 n번째라인까지 출력
 R[UN]  SQL PLUS 버퍼상에 있는 SQL문을 실행 
 n 내용  SQL PLUS 버퍼상에 있는 n 번째 라인의 값을 "내용"으로 채워짐  
 I[NSERT]  SQL PLUS 버퍼상에 있는 제일 마지막 라인 다음에 추가됨. 
 DEL  SQL PLUS 버퍼상에 있는 제일 마지막 라인을 삭제함.
 DEL m  SQL PLUS 버퍼상에 있는 m 번째 라인을 삭제함.
 DEL m n  SQL PLUS 버퍼상에 있는 m 번째 라인부터 n번째 라인까지 삭제함.
 A[PPEND] "내용"  SQL PLUS 버퍼상에 있는 제일 마지막 라인에 "내용"을 추가함.
 C[hange]/old_str/new_str/  SQL PLUS 버퍼상에 있는 old_str 문자열을 new_str 문자열로 변경처리함.
 CL[EAR] BUFF[ER]  SQL PLUS 버퍼상에 있는 내용을 모두 삭제 
 CL[EAR] SCR[EEN]  SQL PLUS 화면을 깨끗하게 함


 List 예제

SQL> list
     1  select
     2  *
     3  from
     4  tab
     5*

 n 내용 예제

SQL> 2 tname
SQL> list
     1  select
     2  tname
     3  from
     4  tab
     5*

 I[nsert] 예제


SQL> list
     1  select
     2  tname
     3  from
     4  tab
     5*
SQL> i
     6  where tname='KKK';

TNAME
------------------------------
KKK


 DEL 예제

SQL> list
     1  select
     2  tname
     3  from
     4  tab
     5*
SQL> i
     6  where tname='KKK';

TNAME
------------------------------
KKK

SQL> del
SQL> list
     1  select
     2  tname
     3  from
     4  tab
     5*


 A[ppend] 예제


SQL> list
     1  select
     2  tname
     3  from
     4  tab
     5* where tname='KKK'4
SQL> del 5
SQL> a where tname='KKK'
     4* tabwhere tname='KKK'
SQL> list
     1  select
     2  tname
     3  from
     4* tabwhere tname='KKK'

 C[hange] 예제

SQL> list
     1  select
     2  tname
     3  from
     4* where  ='KKK'
SQL> c /where/where tname/
     4* where tname  ='KKK'
SQL> list
     1  select
     2  tname
     3  from
     4* where tname  ='KKK'

반응형

+ Recent posts