1. ORACLE SQL DEVELOPER 에서 자동 Trace 사용하기 위해 필요한 권한 부여
GRANT SELECT_CATALOG_ROLE TO SJ_USER;
GRANT SELECT ANY DICTIONARY TO SJ_USER;
-- REVOKE SELECT_CATALOG_ROLE FROM SJ_USER;
-- REVOKE SELECT ANY DICTIONARY FROM SJ_USER;
2. DBMS_XPLAN PACKAGE를 사용하기 위해 필요한 권한 부여
GRANT SELECT ON V_$SQL TO SJ_USER;
GRANT SELECT ON V_$SQL_PLAN TO SJ_USER;
GRANT SELECT ON V_$SESSION TO SJ_USER;
GRANT SELECT ON V_$SQL_PLAN_STATISTICS_ALL TO SJ_USER;
-- REVOKE SELECT ON V_$SQL FROM SJ_USER;
-- REVOKE SELECT ON V_$SQL_PLAN FROM SJ_USER;
-- REVOKE SELECT ON V_$SESSION FROM SJ_USER;
-- REVOKE SELECT ON V_$SQL_PLAN_STATISTICS_ALL FROM SJ_USER;
* ORACLE SQL DEVELOPER의 자동 Trace 결과와 DBMS_XPLAN.DISPLAY_CURSOR 로 조회한 결과는 같다.
3. TRACE 파일을 생성했을 때와 동일하게 예측 ROW 수가 아닌 실제 ROW 수를 확인하고자 할 경우
ALTER SESSION SET STATISTICS_LEVEL = ALL;
혹은 10g 이상이면 SQL Level에 Hint 사용하면 된다.
/*+ GATHER_PLAN_STATISTICS */
4. DBMS_XPLAN.DISPLAY_CURSOR의 파라메터
DBMS_XPLAN.DISPLAY_CURSOR (SQL_ID VARCHAR2 DEFAULT NULL,
CURSOR_CHILD_NO INTEGER DEFAULT 0,
FORMAT VARCHAR2 DEFAULT 'TYPICAL')
5. 실행방법 (이방법은 잘안된다.)
-- 분석할 쿼리 실행
SELECT /*+ GATHER_PLAN_STATISTICS */
*
FROM SJ_USER.COM_MENU
START WITH MNU_PARENTUID IS NULL
CONNECT BY PRIOR SITE_ID = SITE_ID
AND PRIOR MNU_UID = MNU_PARENTUID;
-- 실행한 쿼리의 SQL_ID, CHILD_NUMBER 확인
SELECT SQL_ID
, CHILD_NUMBER
, SQL_FULLTEXT
FROM V$SQL
WHERE PARSING_SCHEMA_NAME = 'SJ_USER'
AND SQL_FULLTEXT LIKE '%GATHER_PLAN_STATISTICS%'
ORDER BY LAST_LOAD_TIME DESC;
-- 실행결과 조회
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('b4gp7hu0w97tp', 0, 'ADVANCED ALLSTATS LAST'));
6. 실행방법
SELECT /*+ GATHER_PLAN_STATISTICS */
*
FROM SJ_USER.COM_MENU
START WITH MNU_PARENTUID IS NULL
CONNECT BY PRIOR SITE_ID = SITE_ID
AND PRIOR MNU_UID = MNU_PARENTUID;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced allstats last'));
위 두개의 쿼리를 하나의 블륵으로 지정하여 한번에 실행하면 실행결과 나온다.
* 분석대상 쿼리를 정확하게 잡지 못하는 경우 조치
1. SET SERVEROUTPUT OFF; -- sql_id 잘 못가져올때 실행, 난 그래도 검색조건에 OR 연산자가 들어간 쿼리는 잘 잡지 못하더라....
SHOW SERVEROUTPUT;
2. 분석대상 쿼리의 결과가 모두 Fetch 되지 않아서 그렇다. 즉 Oracle Developer에서 모든 결과 집합이 조회되도록 한다음. 하면 된다.
1) Basics 항목
- Id : 각 Operationd의 ID임. *가 달려있는 경우는 Predicate Informatio에 Access 및 Filter에 관한 정보를 표시함
- Operation : 각각 실행되는 JOB
- Name : Operationdl 엑세스 하는 Table 및 Index
2) Query Optimizer Estimations 항목(예상치)
- E-Rows : 각 Operation이 끝났을 때 return 되는 건수.
- E-Bytes : 각 Operation이 Temporany Space를 사용한 양
- Cost(%CPU) : 각 Operation의 Cost. 괄호 안의 내용은 CPU Cost의 백분율임. 이 값은 Child Operation의 Cost를 합친 누적치.
- E-Time : 수행시간
3) Runtime Statistics 항목
- Starts : 각 Operation을 반복 수행한 건수
- A-Rows : 각 Operation이 Return 한 건수
- A-Time : 실제 실행시간. 0.01초까지 나타남(HH:MM:SS.FF). Child Operation의 A-Time을 합친 누적치
4) I/O Statistics
- Buffers : 각 Operation이 memory에서 읽은 Block 수.
- Reads : 각 Operation이 Disk에서 Read한 Block 수.
- Writes : 각 Operation이 Disk에서 White한 Block 수.
5) Memory Utilization Statistics(hash 작업이나 sort 작업 시 사용한 메모리 통계)
- OMen : Optimal Execution에 필요한 Memory
- SQL 실행 메모리가 최적의 크기를 가졌을때의 메모리. 여기서 메모리가 최적의 크기를 갖는다는 것은 예를 들어, disk에 write하지 않고 sort 작업을 수행하는 경우를 의미한다.
- 1Mem : One-pass Execution에 필요한 Momory
- SQL 실행 메모리가 1 pass의 크기를 가졌을 때의 메모리. 여기서 메모리가 1 pass의 크기를 갖는다는 의미는, 예를 들어 sort의 경우 disk에 임시 결과를 한번은 저장하고 결과를 merge해서 sort 작업을 마치는 경우를 의미한다.
- O/1/M : 각 Operation이 실행한 Optmal/One-pass/Multipass 횟수가 순서대로 표시됨
O 일 경우 메모리공간(hash_area_size)이 부족하지 않아 temp 영역(disk)을
사용하지 않고 처리 되었다는 의미임.
- multipass 횟수 : SQL 실행 메모리가 2 pass 이상의 크기를 가졌던 횟수.
- Used-mem : 마지막 실행 시 사용한 PGA -Memory
- Used-Tmp : 마지막 실행 시 메모리가 부족하여 Temporary Space를 대신 사용할 때 나타남. 보이는 값에 1024를 곱해야 함.
- Max-Tmp : 메모리가 부족하여 Temporary Space를 사용할 때 최대 Temp 사용량. Used-Tmp와 다른 점은 마지막 수행시가 아니라 SQL을 여러 번 수행했을 경우에 항상 최대값만 보인다는 것. 보이는 값에 1024를 곱해야 함.
6) 쿼리블록 정보 : Plan 상의 Id별로 쿼리블럭 및 Alias 정보를 출력.,
7) Outline Date : 오라클이 내부적으로 사용한 힌트.
8) Predicate Information : Plan 상의 Id 별로 인덱스 액세스, Filter, 조인정보 등을 표출
9) Column Projection Information : Plan 상의 Id 별로 Select 되는 컬럼의 정보.
* DBGuide.net의 GATHER_PLAN_STATISTICS 컬럼 내용
----------------------------------------------------------------------------------------------------------
Id, Operation, Name
이 부분은 우리가 흔히 봐 왔던 플랜 정보다. 자원에 대한 접근 순서와 접근 방법을 나타낸다.
참고적으로 접근 순서를 변경 할 수 있는 힌트절은 ORDERED, LEADING이 있다.
또한 접근 방법을 변경할 수 있는 힌트절은 USE_NL, USE_HASH, USE_MERGE가 있다.
Starts
오퍼레이션을 수행한 횟수를 의미한다. Starts * E-Rows 의 값이 A-Rows 값과 비슷하다면, 통계정보의 예측 Row 수와 실제 실행 결과에 따른 실제 Row 수가 유사함을 알 수 있다.
만약 값에 큰 차이가 있다면 통계정보가 실제의 정보를 제대로 반영하지 못했다고 생각할 수 있다.
이로 인해 오라클의 Optimizer가 잘못된 실행 계획을 수립할 수도 있음을 염두에 둬야 한다.
E-Rows (Estimated Rows)
통계정보에 근거한 예측 Row 수를 의미한다. 통계정보를 갱신할수록 값이 매번 다를 수 있으며,
대부분의 DB 운영에서는 통계정보를 수시로 갱신하지 않으므로 해당 값에 큰 의미를 둘 필요는 없다.
하지만 E-Rows 값과 A-Rows 값이 현격하게 차이가 있다면 오라클이 잘못된 실행 계획을 세울 수도 있음을 인지해야 하며 통계정보 생성을 검토해 보아야 한다.
A-Rows (Actual Rows)
쿼리 실행 결과에 따른 실제 Row 수를 의미한다. 우리는 A-Rows 에서 중요한 여러 정보를 추정 할 수 있다.
A-Time (Actual Elapsed Time)
쿼리 실행 결과에 따른 실제 수행 시간을 의미한다. 하지만 실행 시점의 여러 상황이 늘 가변적이고 또한 메모리에 올라온 Block의 수에 따라서 수행 시간이 달라지므로 해당 값에 큰 의미를 둘 필요는 없다.
Buffers (Logical Reads)
논리적인 Get Block 수를 의미한다. 해당 값은 오라클 옵티마이저가 일한 총량을 의미하므로, 튜닝을 진행할 때 필자가 가장 중요하게 생각하는 요소 중 하나다.
Reads (Physical Reads)
물리적인 Get Block 수를 의미한다. 동일한 쿼??음이 아닌 경우에는 값이 0인 것을 보면 알 수 있듯이 메모리에서 읽어온 Block은 제외된다. 해당 값에 큰 의미를 둘 필요는 없다.
위의 헤더에서 튜닝 시 가장 중요하게 활용되는 부분은 Buffers와 A-Rows다.
Buffers 값을 통해서 Get Block의 총량을 알 수 있고, A-Rows를 통해 플랜 단계별로 실제 Row 수를 알 수 있기 때문이다