본문 바로가기

work/oracle

Full table scan을 하고 있는 쿼리를 알아내는 Query

여러가지 방법이 있겠습니다만..

첫째로 머리에 휙 떠오르는건, trace를 떠 보는거겠군요.
고기에 해당하는 답변은 이미 제가 올렸습니다. 젤 밑에다 붙여드리죠.
그런데 이 방법의 단점은 '이미 서버상에서 돌고 있는 쿼리를 찾아내야 한다'는 거죠.

두번째는 각종 툴을 사용해야 하겠죠. 이렇게 하면 현재 서버상에서 돌고 있는 쿼리들을 쉽게 찾아 낼 수 있습니다.
뭐 오렌지니 DBMAX니 하는 것들 많죠?
그치만 그건 돈 들여서 사야하는거니깐...
OEM아시죠? Oracle Enterprise Manager입니다. 이건 오라클을 사서 쓰는 고객이라면 누구나 Oracle Client CD에서 쉽게 설치할 수 있는거죠.
요거를 설치 하시고 왼쪽에 쭉 붙어있는 메뉴 아이콘에서 "진단모음"을 누르시던지..
아님 화면 위 메뉴에서 "도구->진단->최상위SQL 또는 최상위Session"을 선택..
그럼 쿼리를 포함한 뭐 표 같은게 나옵니다.
거기서 쿼리에 대구 마우스 오른쪽 버튼을 누르시면
실행계획 보기라고 나오는데요.
거기서 이 쿼리가 full scan를 하는지 어쩌는지 확인이 가능하죠.

다만, 현재 full scan를 하고 있는 쿼리들만 뽑아내는 경우는 어떻게 해야할지 저도 잘 모르겠습니다.
또한, TOP Query라는게 full scan을 의미하는건 아닙니다.
다만 간단히 말하자면, 시스템의 resources를 많이 잡아먹는 top query를 말하는거죠. 일반적으로 인덱스 없이 풀 스캔을 한다면(테이블이 무지 작다던지 하는 경우를 제외하고는) 시스템 리소스 소비가 많겠죠.

좋은 결과 있으세요~
아래에는 제 답변을 하나 붙여드리죠.
===========
쿼리문을 딱 보고 이거 이거 잘 못 됐군요..
할 수 있는 사람은 드물죠. 왜냐면 아무리 쿼리에 도사라도 그 업무 즉, 테이블구조 등을 모르면 알기가 힘들게 됩니다. 위에 분 처럼 일반적인 조언뿐일 수 밖에 없죠.

좋은 방법으로, 트레이스(tracea)를 떠 보는게 좋겠습니다.
DBA아니시죠? 혹 sys나 system 유저로 DB접속이 가능하신가요?
아님 좀 곤란할 수 있습니다.
1. plustrace role이 있어야 합니다.
->sys유저로 로긴 후, $ORACLE_HOME/sqlplus/admin/plustrace.sql를 수행
2. plustrace롤을 가져야합니다.
->sys로 로긴 후, grant plustrace to USER명;
3. plan_table이 생성되어 있어야 합니다.
->USER로 로긴 후, $ORACLE_HOME/rdbms/admin/utlxplan.sql 수행
위의 1,2,3번은 되어있을 수 있습니다. 미리 확인해보세요.
확인은,
2번만 하심 되지 않을까 싶네요.
SQL>select * from user_role_privs; 하심 되겠습니다. 여기서 plustrace롤이 있는지 눈으로 확인하심 되겠죠?
아마 plustrace롤이 있다고 하면 1,2번은 최소한 되어있는 걸겁니다.
3번은 일단 함 돌려보세요 ^^
아..아님 님의 유저로 로긴 후,
SQL>select * from user_tables where table_name = 'PLAN_TABLE';
해보세요.

이제 진짜 trace를 떠야합니다.
sql*plus로 로긴하세요.
먼저 sys로 로긴하세요. 만약 sys로 로긴안된다면, USER(님의 유저)로 로긴한 다음,
#>sqlplus USER/USER@Connect_String
SQL>conn /as sysdba 해보세요.
1. show parameter timed
2. show parameter sql_trace
둘 다 true라는 값으로 나오야 합니다.
만약 이게 false라면
SQL>alter session set timed_statistics=true;
SQL>alter session set sql_trace=true;
로 설정해서 님의 현재 세션에서만 적용되도록 할 수 있습니다.
3. sql*plus로 로긴(님의 유저로)
4. set autot on -> set autotrace on의 약어입니다.
5. 이제 원하는 쿼리를 돌리세요.

그럼 결과가 나옵니다.

Execution Plan (참고로 아래에 왼쪽나온 숫자는 실행된 순서입니다)
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'XX'
3 2 INDEX (RANGE SCAN) OF 'XXXXX' (UNIQUE)
4 1 TABLE ACCESS (BY INDEX ROWID) OF 'XXXXX'
5 4 INDEX (UNIQUE SCAN) OF 'XXXXX' (UNIQUE)

Statistics
----------------------------------------------------------
7 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
692 bytes sent via SQL*Net to client
655 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
뭐 대략 이런 결과가 나옵니다.
그런데 정확하게 시간이 나오지 않습니다.
그래서
SQL>execute dbms_session.set_sql_trace(true);
애를 실행해줍니다.
이제 쿼리를 돌리세요.
결과는..
SQL>show parameter user
해보시면 user dump destnation이란게 나옵니다.
아니면 대부분, $ORACLE_BASE/admin/SID/udump 라는 곳에 있습니다.
여기서 #ls -altr 이라고 하시면 가장 최근 파일이 젤 밑에 보이죠?
(참고로 지금 다 유닉스입니다. Windows면..대충 비슷하게 하실 수 있겠죠? ^^)
#tkprof 가장밑에있는파일명 원하는파일명
해주시면 보기 편한 모양으로 '원하는파일명'으로 만들어집니다. 물론 text파일이죠.

결과는 대략 아래와 같습니다.


call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0
중략...

여기서 elapsed라는 시간이 바로 총 걸린 시간입니다.
일단 시간이 젤 많이 걸린 놈부터 왜 그런지 찾아들어가 보다보면
좋은 결과 있을겁니다. ^^