반응형

본 이미지는 글과 관련없습니다. 그냥 허전해서 넣은거에요....ㅋ

나름 프로그램 만들다보면, 성능에 신경쓰지 못하고 그냥 넘어가는 경우가 있다.

그리고 나중에, 어느부분에서 느린지 프로그램도 프로그램이지만 DB에서 찾아야 하는 경우도 있다.

그럴때 아래 쿼리를 이용해서 많은 블록에 접근하여 성능에 영향을 주는 SQL을 찾아낼수 있다.

SELECT /*+ NO_MERGE(v) */
       s.HASH_VALUE
     , s.MODULE
     ,s.last_active_time
     , 
     ( SELECT username 
         FROM DBA_USERS 
        WHERE user_id =s.parsing_user_id
      ) username
      , executions
      , ROUND(elapsed_time/(DECODE(executions,0,1,NULL,1,executions)*1000000),1) elapsed_t
      , ROUND(buffer_gets/DECODE(executions,0,1,NULL,1,executions),1) buffer_gets_per_exec
      , rows_processed
      , sql_text
  FROM
     ( SELECT /*+ NO_MERGE(V1) */
              MAX(HASH_VALUE) HASH_VALUE
         FROM
            (
              SELECT HASH_VALUE, SQL_TEXT
                FROM V$SQL S
               WHERE 1=1
                 AND ( ROUND(buffer_gets/DECODE(executions,0,1,NULL,1,executions),1) > 10000
                       OR elapsed_time/(DECODE(executions,0,1,NULL,1,executions)*1000000) >10 )
                 AND (module IS NULL
                      OR (module NOT LIKE 'TOAD%'
                     AND module NOT LIKE 'Orange%'
                     AND module NOT LIKE 'Golden32.exe%'
                     AND module NOT LIKE 'PL/SQL Developer%'
                     AND module NOT LIKE 'T.O.A.D%'
                     AND UPPER(module) NOT LIKE 'SQL*PLUS%')
                     )
                 AND PARSING_USER_ID IN
                ( SELECT user_id
                    FROM DBA_USERS
                   WHERE username NOT IN ('SYS','SYSTEM')
                )
             ) V1
        GROUP BY SUBSTR(SQL_TEXT,1,150)
     ) v,
       V$SQLAREA s
 WHERE v.hash_value=s.hash_value
  AND parsing_user_id IN
    ( SELECT user_id
        FROM DBA_USERS
       WHERE username NOT IN ('SYS','SYSTEM')
    )
  AND s.module NOT LIKE 'SmartSQL%'
ORDER BY buffer_gets;

위 쿼리의 제목은 "쿼리수행시간이 10초이상걸리거나, 10000블록 이상 접근하는 쿼리 " 이 정도가 되겠다.

※아래는 이해를 돕기위한 설명.

- Buffer Gets : 해당 SQL이 수행되면서 액세스한 블록의 수이며 V$SQL 등에서는 Executions가 곱해져서 보여진다.


- Executions : 해당 SQL이 수행된 횟수를 의미하며 변수 처리를 바인 드 변수 처리로 수행하지 않으면 다른 SQL로 집계된다.


- Elapsed Time : 해당 SQL이 수행된 수행 시간이며 V$SQL에서는 1,000,000으로 나눠야 초가 된다. 물론 Executions로 곱해져 있기 때 문에 Executions로도 나눠야 1회 수행 시 수행 시간이 된다.


- (ROUND(BUFFER_GETS/DECODE(EXECUTIONS,0,1,NULL,1, EXECUTIONS),1) > 10000 - 10,000 Block 이상 액세스한 SQL

- ELAPSED_TIME/(DECODE(EXECUTIONS,0,1,NULL,1,EXECUT IONS)*1000000) >1- 수행시간 1초 이상


- order by BUFFER_GETS; - Block 액세스에 수행 횟수를 곱한 순으로 결과 추출

 

프로그램(DB) 유지보수에 큰 도움이 되길 ..

반응형
반응형

구글에서 주워온이미지..문제가 된다면 죄송합니다...봐주세요

지난 포스팅 "실시간으로 10초이상 걸리는 쿼리 확인하기" 에 이어,

이번에는 테이블 자체에 LOCK이 걸린 내역을 조회하는 쿼리이다.

※지난 포스팅은 아래 링크 참조

 

[오라클] 실시간으로 10초이상 걸리는 쿼리 확인하기

현재 DB서버가 폭주중이라면, 먼저 장시간 수행중인 쿼리들이 없는지 1차적으로 체크해야 할 필요가있다. 때에 따라 확인하는 것 뿐만 아니라, 강제로 KILL하여 자원의 안정적인 확보가 필요하다.

masswhale.tistory.com


SELECT DISTINCT X.SESSION_ID, A.SERIAL#, D.OBJECT_NAME, A.MACHINE, A.TERMINAL,
       A.PROGRAM, A.LOGON_TIME, 'ALTER SYSTEM KILL SESSION'''||A.SID||', '||A.SERIAL#||''';' AS qry
FROM GV$LOCKED_OBJECT X, GV$SESSION A, DBA_OBJECTS D
WHERE  X.SESSION_ID = A.SID
AND X.OBJECT_ID = D.OBJECT_ID
ORDER BY LOGON_TIME;

마찬가지로 오라클의 Dynamic Performance View로 부터 조회하는 방식이다.

Lock 세션이 발견되어 DB서버가 과부하다 못해 죽기 직전에 쓰는 응급조치라고 할수 있겠다.

SELECT절의 가장 끝 컬럼에 "ALTER SYSTEM KILL SESSION~"을 넣어뒀으니, 복사 후 바로 사용할 수 있다.

DB에 자주 무리가 가거나, 별도의 모니터링 툴이 없으신 곳은 이전포스팅의 내용과 현재 포스팅의 내용을 

잘 참조하셔서 별도의 모듈을 만들면, 굉장한 도움이 될것으로 예상된다.

다음포스팅에서도 관련된 정보 포스팅 예정!

 

많은 분들에게 도움되길!

※오라클만 됩니다.

반응형
반응형

그냥 허전해서 주워온 이미지..사진 사용에 문제가 될시...죄송합니다.

현재 DB서버가 폭주중이라면, 먼저 장시간 수행중인 쿼리들이 없는지 1차적으로 체크해야 할 필요가있다.

때에 따라 확인하는 것 뿐만 아니라, 강제로 KILL하여 자원의 안정적인 확보가 필요하다.

아래 쿼리는 현재 수행시간이 10초 이상인 것들의 대한 SQL과 프로세스 정보를 확인하는 쿼리이다.

이는 오라클에서 제공하는 Dynamic Performance View로 부터 실시간으로 확인하는 정보다.

 

바로 kill할수 있도록 SELECT 절 가장 끝 컬럼에

ALTER SYSTEM KILL ~구문을 추가했으니, 바로 복사해서 사용하면 된다.

--당일 실시간으로 10초이상 걸리는 쿼리를 조회
SELECT
  A.SID,       -- SID
  A.SERIAL#,   -- 시리얼번호
  A.STATUS,    -- 상태정보
  A.MODULE,
  A.MACHINE,
  A.USERNAME,  -- 유저
  A.OSUSER,    -- 접속자의 OS 사용자 정보
  A.LOGON_TIME, --세션 로그온 시간
  B.LAST_ACTIVE_TIME, --마지막 활성화 시간
  ROUND(ELAPSED_TIME/(DECODE(EXECUTIONS,0,1,NULL,1,EXECUTIONS)*1000000),1)AS ELAPSED_T, --평균수행시간(초)
  SUBSTR (TO_CHAR (LAST_CALL_ET), 1, 6) AS  EXECUTESECONDS, --실제 수행중시간 (초)
  A.PROCESS,   -- 프로세스정보
  B.SQL_TEXT,  -- sql
  'ALTER SYSTEM KILL SESSION'''||A.SID||', '||A.SERIAL#||''';' AS qry
FROM
  V$SESSION A,
  V$SQLAREA B,
  V$PROCESS C
WHERE
  A.SQL_HASH_VALUE=B.HASH_VALUE
  AND A.SQL_ADDRESS=B.ADDRESS
  AND A.PADDR=C.ADDR  
  AND A.MODULE IS NOT NULL
  AND TO_CHAR(A.LOGON_TIME,'YYYY') >= SUBSTR(TO_CHAR(SYSDATE,'YYYYMMDD'),0,4)
  AND TO_CHAR(LAST_ACTIVE_TIME,'YYYYMMDD') = TO_CHAR(SYSDATE,'YYYYMMDD')
  AND (B.ELAPSED_TIME/B.EXECUTIONS/1000000) > 1 /* 평균수행시간이 ?초 이상인것 */
  AND SUBSTR (TO_CHAR (LAST_CALL_ET), 1, 6) > 1 /* 현재 실제수행중인 쿼리가 ? 초 이상인것 */
  AND A.STATUS='ACTIVE'
ORDER BY A.LAST_CALL_ET DESC

해당 쿼리를 이용하여, 자동으로 체크하는 로직을 만들수 있고, 그에따라 가장 끝 컬럼에 있는

값들인 (ALTER SYSTEM KILL~~) 구문을 실행하여 부하걸린 프로세스를 바로 종료시킬수도 있다.

개별모듈로써 활용가능성이 있음..

※오라클에서만 됩니다.

반응형
반응형

드디어 스터디 마지막회차.

이번 스터디에서는 Map 심화버전을 다뤄보고자 한다. 

먼저 간단한 예제를 통해 Map과 List를 알아보자.

void main() {
Map map = {
	'Apple' : '사과',
	'Banana' : '바나나',
	'Kiwi' : '키위'
};

	print(map.keys);
	print(map.values);
    
}
(Apple, Banana, Kiwi)
(사과, 바나나, 키위)

Map에서 key값과 value값들을 확인하기 위해선 위와같이 확인할 수 있다.

※물론, print(map['Apple']); 이런형태로도 개별확인은 가능하다.

이번에는 위 map을 List로 변경하려면 어떻게 해야할까?

print(map.keys.toList());
print(map.values.toList());
[Apple, Banana, Kiwi]
[사과, 바나나, 키위]

toList()로 간단하게 List로 변경하여 활용이 가능하다.


이번엔 Map에 entries에 대한 개념에 대해서 익혀보자

Map에 존재하는 entries는 key값과 value값을 셋트로 매핑하여 꺼낼수 있는 기능이라 할수 있다.

아래 예제로 살펴보자.

  Map map = {
    'Apple' : '사과',
    'Banana' : '바나나',
    'Kiwi' : '키위'
  };
  
    final newMap = map.entries.map((entry){
    final key = entry.key;
    final value = entry.value;
    
    return '$key는 한글로 $value 입니다.';
  });
    
  print(newMap);
(Apple는 한글로 사과 입니다., Banana는 한글로 바나나 입니다., Kiwi는 한글로 키위 입니다.)

위 소스에서 entry변수는 인덱스 마다의 key와 value를 담고 있다.

entry.key와 entry.value로 각 인덱스마다 값을 추출할 수 있다.

 

또한 List에서 사용했던 forEach, reduce와 fold도 entries를 이용하면 사용할 수 있다.

reduce와 fold가 기억나지 않는다면, 아래 포스팅 다시 참조!

 

Dart언어공부-25.List 심화 (forEach, map, reduce, fold)

이번 스터디에서는 List심화단계를 다뤄보려 한다. 바로 소스로 확인해 보자. 1. Looping 활용 List world = [ '한국', '중국', '일본', '러시아', '미국' ]; world.forEach((value){ print(value); }); 한국..

masswhale.tistory.com


바로 예제로 확인해보자.

  Map map = {
    'Apple' : '사과',
    'Banana' : '바나나',
    'Kiwi' : '키위'
  };
  
  
    map.entries.forEach((entry){
    final key = entry.key;
    final value = entry.value;
    
    print('$key는 한글로 $value 입니다.');
  
  });
  
  final total = map.entries.fold(0,(vTotal,entry){
    return vTotal + entry.key.length;
    
  });
    
  print(total);
Apple는 한글로 사과 입니다.
Banana는 한글로 바나나 입니다.
Kiwi는 한글로 키위 입니다.
15

위와 같이 entries를 사용하며, forEach와 fold를 무리없이 사용할 수 있다.


Map얘기를 잠깐 떠나,  만약 List에서 index정보까지 받아서 확인하고 싶다면 어떻게 해야할까?

바로 asMap()를 사용하면 된다.

  List<int> numbers = [
    10,
    20,
    30,
    40,
    50,    
  ];
  
  
  final newMap3 = numbers.asMap();
  
  print(newMap3);
{0: 10, 1: 20, 2: 30, 3: 40, 4: 50}

위와같이 List에서 asMap()이라는 간단한 함수를 통해, 자리번호에 따른 값을 확인할 수 있다.

 

여기서 바로 asMap과 entries를 이용하여, 셋트로 추출이 가능하다.

  List<int> numbers = [
    10,
    20,
    30,
    40,
    50,    
  ];
  
    final newMap4 = numbers.asMap().entries.map((entry){
    final index = entry.key;
    final value = entry.value;
    
    return 'index가 $index 일때 값은 $value 입니다.';
  
  });
  
  print(newMap4);
(index가 0 일때 값은 10 입니다., index가 1 일때 값은 20 입니다., index가 2 일때 값은 30 입니다., index가 3 일때 값은 40 입니다., index가 4 일때 값은 50 입니다.)

이렇게 List를 맵으로바꿔서 entries, reduce,fold도 가능하다.

Map과 List를 상황에 따라 서로 바꿔가며 사용을 할수 있다. 

코딩에 정답은 없으니, 언제든 구현하려는 기능에, 상황에 따라 

구현하면 된다.

 

Dart 왕초보 기초 파트 스터디 끝!

반응형

+ Recent posts