리두로그버퍼(Redo Log Buffer)
- 오라클은 갑작스러운 장애 발생시 백업된 데이터파일에 리두로그버퍼를 합쳐서 데이터를 복구한다.
- 리두로그버퍼에서 리두로그파일로 저장되는 시점
DB버퍼캐시
- 버퍼상태
- Pinnded 버퍼 : 현재 사용중인 버퍼, 변경을 했지만 아직 COMMIT은 되지 않은 상태
- Dirty 버퍼 : COMMIT을 했지만 아직 데이터파일로 저장은 되지 않은 상태
- 리두로그파일에는 저장되었지만 데이터파일에는 저장안된 상태
- Free 버퍼 : 사용가능한 버퍼, 데이터가 데이터파일로 저장되었거나 사용되지 않은 상태\
- DB버퍼캐시의 데이터가 데이터파일로 저장되는 경우
- Checkpoint 신호가 발생했을 때
- DDL명령이 실행될 때
Shared Pool
- 라이브러리캐시
- 파싱된 SQL문과 실행계획을 매핑하여 저장
- 캐시 공간이 부족하면 버려졌다가 다시 하드파싱 후 저장된다.
- 딕셔너리캐시
- 오라클의 모든 객체(테이블, 뷰, 인덱스, 시퀀스 등)에 대한 정보들을 저장
- 테이블 데이터를 찾을 때 그 시작점이 된다.
LGWR(Log Writer) Background Process
- LGWR Background Process는 Log Buffer에 있는 내용을 Log File에 기록하는 일을 한다.
- 아래와 같은 시점에서 작업이 진행된다.
- Commit 되었을 때
- Log Buffer가 1/3 찼을 때
- Log Buffer가 1MB 사용했을 때
- timeout
INSERT문 실행시 내부동작
1. SQL문 실행
서버프로세스
- 구문분석
- SQL문의 문법을 확인 (키워드 검사)
- 테이블명, 칼럼명, 데이터 타입 확인 (의미 검사)
- SQL문을 실행한 계정의 권한 확인 (권한 검사)
- Shared Pool의 라이브러리캐시에 해당 쿼리 저장 (쿼리 재사용을 위해)
- 입력할 데이터를 리두로그버퍼와 DB버퍼캐시에 기록
2. COMMIT 실행
백그라운드 프로세스
LGWR (Log writer)
- 리두로그버퍼 데이터 -> 리두로그파일로 저장
- DB버퍼캐시 상태 변경 (Pinned --> Dirty)
- Checkpointer가 DBWR에게 데이터 저장 신호 전달
- DBWR가 DB버퍼캐시 데이터 -> 데이터파일로 저장
SELECT문 실행시 내부동작
서버프로세스
- 구문분석
- SQL문의 문법을 확인 (키워드 검사)
- 테이블명, 칼럼명, 데이터 타입 확인 (의미 검사)
- SQL문을 실행한 계정의 권한 확인 (권한 검사)
- 라이브러리캐시에 SQL 존재하는지 확인
- 있으면 곧바로 실행 (소프트 파싱)
- bind변수만 달라졌을 경우 소프트 파싱
- 없으면 옵티마이저가 최적화 과정을 거쳐 실행계획 생성 (하드 파싱)
- 테이블, 인덱스, 칼럼에 대한 통계정보 존재하는지 확인
- 인덱스가 존재한다면 어떤 인덱스가 최적인지
- CPU를 많이 소모하는 작업
- 있으면 곧바로 실행 (소프트 파싱)
- Shared Pool의 라이브러리 캐시에 쿼리와 실행계획 저장 (쿼리 재사용을 위해서)
- DB버퍼캐시에 해당 테이블의 데이터 있는지 확인
- 있으면 캐시에서 데이터 접근 (메모리 I/O)
- 없으면 디스크에 접근해서 해당 테이블 데이터를 DB버퍼캐시로 복사 (디스크 I/O)
- DB버퍼캐시의 데이터 중 원하는 결과만 추출하여 유저프로세스로 전송 (블록 단위)
SELECT문 논리적 실행순서
- FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
UPDATE문 실행시 내부동작
1. SQL문 실행
서버프로세스
- 구문분석
- SQL문의 문법을 확인 (키워드 검사)
- 테이블명, 칼럼명, 데이터 타입 확인 (의미 검사)
- SQL문을 실행한 계정의 권한 확인 (권한 검사)
- Shared Pool의 라이브러리캐시에 해당 쿼리 저장 (쿼리 재사용을 위해)
- DB버퍼캐시에 해당 테이블의 데이터 있는지 확인
- 없으면 디스크에 접근해서 해당 테이블 데이터를 DB버퍼캐시로 복사
- DB버퍼캐시에 변경 조건에 맞게 데이터 수정
- 입력할 데이터를 리두로그버퍼와 DB버퍼캐시에 기록
2. COMMIT 실행
백그라운드 프로세스
- 리두로그버퍼 데이터 -> 리두로그파일로 저장
- DB버퍼캐시 상태 변경 (Pinned --> Dirty)
- Checkpointer가 DBWR에게 데이터 저장 신호 전달
- DBWR가 DB버퍼캐시 데이터 -> 데이터파일로 저장
데이터베이스의 저장구조
데이터베이스는 다음과 같은 구조로 데이터를 저장한다
- 테이블 스페이스 : 세그먼트를 담는 콘테이너
- 세그먼트 : 데이터 저장공간이 필요한 오브젝트 (테이블, 인덱스, 파티션 등)
- 익스텐트 : 공간을 확장하는 단위, 연속된 블록 집합
- 블록 : 데이터를 읽고 쓰는 단위
- 데이터 파일 : 디스크 상의 물리적인 OS 파일
데이터 액세스 방법
테이블 또는 인덱스 블록을 읽는 방식으로는 시퀸셜 액세스와 랜덤 액세스가 존재한다.
- 시퀸셜 액세스 : 논리적 혹은 물리적으로 블록들이 연결된 순서에 따라 차례대로 블록을 읽는 방식이다.
- 랜덤 액세스 : 레코드 하나를 읽기 위해 한 블록씩 접근하는 방식이다. 인덱스를 통해 데이터를 읽을 때 사용되는 방식이다.
이와 관련되어 데이터를 스캔하는 방식은 다음과 같다.
- Table Full Scan : 테이블에 속한 블록 전체를 읽어서 사용자가 원하는 데이터를 찾는 방식이다. 시퀸셜 액세스를 통해 읽는다.
- Index Range Scan : 인덱스에스 일정량을 스캔하면서 얻은 ROWID로 테이블 레코드를 찾아가는 방식이다. 랜덤 액세스를 통해 읽는다.
논리적 I/O 와 물리적 I / O
디스크 I/O가 SQL의 성능을 결정한다. SQL을 최적화하기 위해 DISK I/O를 줄여야 한다. DBMS에는 DB 버퍼 캐시가 있으며, 디스크에서 읽은 데이터블록을 캐싱해두어서 I/O콜을 줄일 수 있다. I/O 기준을 잡을 때 두 가지 개념이 존재한다.
- 논리적 I/O
SQL을 수행하면서 읽은 총 블록 I/O이다.
- 물리적 I/O
SQL을 수행하면서 디스크에서 발생한 총 블록 I/O를 말한다.
Single Block I/O와 Multi Block I/O
- Single block I/O
한 번에 한 블록 씩 요청해서 메모리에 적재하는 방식을 Single Block I/O라고 한다. 인덱스를 통한 소규모 데이터를 읽을 때 사용된다.
- Multi Block I/O
한번에 여러 블록 씩 요청해서 메모리에 적재하는 방식을 Multi Block I/O라고 한다. 대량으로 데이터를 읽을 때 유용하다.
인덱스는 항상 빠르지 않다.
일반적으로 우리는 인덱스를 쓰면 조회할 때 성능이 올라가는 것으로 알고 있다.
그 이유는 인덱스는 특정 조건에 맞는 데이터를 B+트리와 같은 자료구조를 통해 단 시간에 빠르게 찾을 수 있기 때문이다.
그러나 인덱스 컬럼의 조건에 맞는 데이터 양이 전체 데이터 양에 꽤 많은 portion을 차지하고 있다면 인덱스를 통한 Index Range Scan(랜덤 액세스)가 인덱스를 사용하지 않고 전체 테이블 블록을 읽어오는 Full Scan보다 느릴 수 있다.
Table Full Scan은 Multi Block I/O 방식으로 디스크 블록을 읽는다. 한 블록에 속한 모든 레코드를 한번에 읽어들이고, 캐시에서 못 찾으면 한 번의 IO를 통해 인접한 수십 수백개의 블록을 한번에 I/O하는 메커니즘이다.
Index Range Scan을 통한 테이블 액세스는 랜덤 액세스와 SIngle Block I/O 방식으로 디스크 블록을 읽는다. 캐시에서 블록을 못찾으면, 레코드 하나를 일기 위해 매번 잠을 자는 I/O 메커니즘이다. 즉 많은 데이터를 읽을 때 Table Full Scan 보다 불리하다. 또 읽었던 블록을 반복해서 읽기 때문에 비 효율적이다.
참고 :
https://velog.io/@ilhoon93
https://myjamong.tistory.com/200
친절한 SQL 튜닝 (도서)
'DataBase > Oracle' 카테고리의 다른 글
[DataBase - Oracle] 오라클 형 변환 함수 (0) | 2023.02.10 |
---|---|
[DataBase - Oracle] NULL을 다른 값으로 변환하는 NVL함수 (0) | 2023.02.10 |