-- 테스트용 테이블 생성
CREATE TABLE T AS
SELECT D.NO, E.*
FROM (
SELECT * FROM EMPLOYEES
JOIN DEPT_EMP USING (EMP_NO)
JOIN DEPARTMENTS USING (DEPT_NO)
) E, (SELECT ROWNUM NO FROM DUAL CONNECT BY LEVEL <= 100) D;
-- 3316만 건
SELECT COUNT(*) FROM T;
-- 인덱스 생성
CREATE INDEX T_X01 ON T(DEPT_NO, NO);
CREATE INDEX T_X02 ON T(DEPT_NO, FIRST_NAME, LAST_NAME, NO); 별다른 힌트 없이 쿼리 실행 : 옵티마이저의 판단에 따라 T_X01 선택SELECT * FROM T
WHERE DEPT_NO = 'd005'
AND NO = 1; T_X02 로 옵티마이저 힌트를 줄 때 : cost 증가---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 36845 | 2266K| 3260 (1)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 36845 | 2266K| 3260 (1)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_X01 | 36845 | | 100 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------- Full scan : cost 증가SELECT /*+ INDEX(T T_X02) */ * FROM T
WHERE DEPT_NO = 'd005'
AND NO = 1;---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 36845 | 2266K| 54548 (1)| 00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 36845 | 2266K| 54548 (1)| 00:00:03 |
|* 2 | INDEX RANGE SCAN | T_X02 | 36845 | | 17699 (1)| 00:00:01 |
---------------------------------------------------------------------------------------------SELECT /*+ FULL(T) */ * FROM T
WHERE DEPT_NO = 'd005'
AND NO = 1;--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 36845 | 2266K| 86009 (1)| 00:00:04 |
|* 1 | TABLE ACCESS FULL| T | 36845 | 2266K| 86009 (1)| 00:00:04 |
--------------------------------------------------------------------------SELECT /*+ INDEX(A 고객_PK) */
고객명, 연락처, 주소, 가입일시
FROM 고객 A
WHERE 고객ID = '1111'-- 콤마 사용은 인자에서만 가능
/*+ INDEX(A A_X01 INDEX(B,B_X03) */ -- 모두 유효
/*+ INDEX(C), FULL(D) */ -- 첫 번째 힌트만 유효
-- 테이블을 지정시 스키마 명 명시 금지
SELECT /*+ FULL(PUBLIC.EMP) */ -- 무효
FROM EMP
-- FROM 에서 ALIAS 지정시 힌트에도 ALIAS 사용
SELECT /*+ FULL(EMP) */ -- 무효
FROM EMP E| 분류 | 힌트 | 설명 |
|---|---|---|
| 최적화 목표 | ALL_ROWS | 전체 처리 속도 최적화 |
| FIRST_ROWS | 최초 N건 응답 속도 최적화 | |
| 액세스 방식 | FULL | Table Full Scan으로 유도 |
| INDEX | Index San으로 유도 | |
| INDEX_DESC | Index를 역순으로 스캔하도록 유도 | |
| INDEX_FFS | Index Fast Full Scan으로 유도 | |
| INDEX_SS | Index Skip Scan으로 유도 | |
| 조인 순서 | ORDERED | FROM 절에 나열된 순서대로 조인 |
| LEADING | LEADING 힌트 괄호에 기술한 순서대로 조인 | |
| SWAP_JOIN_INPUTS | 해시 조인 시, BUILD INPUT을 명시적으로 선택 | |
| 조인 방식 | USE_NL | NL 조인으로 유도 |
| USE_MERGE | 소트 머지 조인으로 유도 | |
| USE_HASH | 해시 조인으로 유도 | |
| NL_SJ | NL 세미조인으로 유도 | |
| MERGE_SJ | 소트 머지 세미조인으로 유도 | |
| HASH_SJ | 해시 세미조인으로 유도 | |
| 서브쿼리 팩토링 | MATERIALIZE | WITH 문으로 정의한 집합을 물리적으로 생성하도록 유도 |
| INLINE | WITH 문으로 정의한 집합을 물리적으로 생성하지 않고 INLINE 처리하도록 유도 | |
| 쿼리 변환 | MERGE | 뷰 머징 유도 |
| NO_MERGE | 뷰 머징 방지 | |
| UNNEST | 서브쿼리 Unnesting 유도 | |
| NO_UNNEST | 서브쿼리 Unnesting 방지 | |
| PUSH_PRED | 조인조건 Pushdown 유도 | |
| NO_PUSH_PRED | 조인조건 Pushdown 방지 | |
| USE_CONCAT | OR 또는 IN-List 조건을 OR-Expansion으로 유도 | |
| NO_EXPAND | OR 또는 IN-List 조건에 대한 OR-Expansion 방지 | |
| 병렬 처리 | PARALLEL | 테이블 스캔 또는 DML을 병렬방식으로 처리하도록 유도 |
| PARALLEL_INDEX | 인덱스 스캔을 병렬방식으로 처리하도록 유도 | |
| PQ_DISTRIBUTE | 병렬 수행 시 데이터 분배 방식 결정 | |
| 기타 | APPEND | Direct-Path Insert 로 유도 |
| DRIVING_SITE | DB Link Remote 쿼리에 대한 최적화 및 실행 주체 지정 | |
| PUSH_SUBQ | 서브쿼리를 가급적 빨리 필터링하도록 유도 | |
| NO_PUSH_SUBQ | 서브쿼리를 가급적 늦게 필터링하도록 유도 |
라이브러리 캐시 : SQL 파싱, 최적화, 로우 소스 생성 과정을 거쳐 생성한 내부 프로시저를 반복 재사용할 수 있도록 캐싱해두는 메모리 공간SGA(System Global Area) : 서버 프로세스와 백그라운드 프로세스가 공통으로 액세스하는 데이터와 제어 구조를 캐싱하는 메모리 공간소프트 파싱 : SQL을 캐시에서 찾아 곧바로 실행 단계에서 넘어가는 것하드 파싱 : SQL을 캐시에서 찾는데 실패해 최적화 및 로우 소스 생성까지 거치는 것CREATE PROCEDURE LOGIN (login_id in varchar2) { ... }
-- 라이브러리 캐시 : 하드 파싱 최초 1회만 발생
SELECT * FROM CUSTOMER WHERE LOGIN_ID = :1테이블스페이스 → 세그먼트 → 익스텐트 → 블록 → 로우
테이블스페이스 : 세그먼트를 담는 컨테이너세그먼트 : 테이블, 인덱스, 파티션, LOB(Large Object) 같이 저장 공간이 필요한 영역DBA_EXTENTS 뷰에서 세그먼트에 할당된 익스텐트 목록 조회 가능익스텐트 : 공간을 확장하는 단위, 여러 블록들로 구성블록 : 레코드를 실제로 저장하는 공간, 페이지라고도 불림DBA(Data Block Address) : 디스크 상에서 몇 번째 블록인지 나타냄데이터파일 : 디스크 상의 물리적인 OS 파일익스텐트 내 블록은 서로 인접, 익스텐트 끼리는 불연속!
DBA(Data Block Address): 블록의 고유 주소값
- 인덱스를 이용해 레코드를 읽을 때는
ROWID(DBA+ 로우 번호)로 조회- 테이블 스캔 시에는 세그먼트 헤더에 저장된 익스텐트 맵 이용 → 첫번째
DBA파악
DBMS에서 데이터를 읽고 쓰는 단위
V$PARAMETER 조회
SQL> show parameter block_size
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_block_size integer 8192
SQL> select value from v$parameter where name='db_block_size';
VALUE
--------------------------------------------------------------------------------
8192
시퀀셜 : 연결된 순서에 따라서랜덤 : 순서X, 한 블록씩 접근논리적 : SQL을 처리하는 과정에 발생한 총 블록 I/O (캐시를 모두 거침 - 사실상 메모리 I/O)물리적 : 디스크에서 발생항 총 블록 I/O → 시간 오래 걸림BCHR = (캐시에서 곧바로 찾은 블록 수 / 촌 읽은 블록 수) * 100
= ((논리적 I/O - 물리적 I/O) / (논리적 I/O)) * 100
= (1 - (물리적 I/O) / (논리적 I/O)) * 100
물리적 I/O = 논리적 I/O * (100% - BCHR)
SELECT e.empno, e.ename, d.dname
FROM emp e
JOIN dept d ON e.deptno = d.deptno;
db_file_multiblock_read_count 파라미터