2025.05.15 - [DB, SQL] - [DB] Oracle Database 구조
[DB] Oracle Database 구조
최근 Oracle을 학습해야 할 일이 생겨, Oracle학습 목적으로 작성해 보겠습니다..! 지금까지 진행했던 간단한 프로젝트들에서는 SpringBoot + JPA + MySQL를 주로 사용했는데, 그러다 보니 복잡한 데이터를
ejk5148.tistory.com
SGA를 알기 전에 이전에 작성한 Oracle DB의 큰 구조를 보고 오면 좀 더 이해가 쉬울 거예요!
Database Buffer Cache의 구조별 역할과 필요성
DBC는 크게 네 가지의 풀로 나뉘게 됩니다.
Default Pool, Keep Pool, Recycle Pool, nK Pool
DBC를 왜 하나의 큰 풀이 아닌 여러 개의 풀로 나눌까요?
예시로, 쿠x, 알x 테x 같은 온라인 전자상거래에서 일어나는 일들을 봅시다.
-- 상황 1: 새벽 3시 대용량 배치 작업
SELECT * FROM order_history
WHERE order_date BETWEEN '2020-01-01' AND '2023-12-31';
-- 100GB 테이블 전체 스캔!
-- 상황 2: 오전 9시 일반 사용자
SELECT * FROM product WHERE product_id = 'iPhone15';
-- 자주 사용되는 작은 데이터
만약 하나의 풀만 있다면?
새벽 배치 작업에는 100GB 데이터가 캐시를 점령하기 때문에 iPhone 15의 데이터가 밀려나게 됩니다. 조회량이 많은 iPhone15는 오전 고객들의 조회마다 디스크 I/O가 발생하게 됩니다.
이 문제를 풀을 용도별로 분리하여 해결할 수 있습니다.
1. Default Pool - 기본 풀
온라인 전자 상거래 사이트에서 일반적인 OLTP(Online Transaction Processing) 작업을 진행합니다. 8K의 표준 블록을 가지며 LRU 알고리즘으로 관리됩니다. 보통 주문 테이블, 고객 정보가 적용되고 일반적으로 적당한 크기와 적당한 빈도를 가지는 테이블을 저장하게 됩니다.
2. Keep Pool - 보관 풀
항상 메모리에 유지합니다. 그렇기 때문에 LRU 알고리즘을 적용하지 않습니다. 보통 한 번 들어오게 되면 계속 상주합니다.
-- 실제 사용 예시
ALTER TABLE product_category
STORAGE (BUFFER_POOL KEEP);
상품 카테고리의 정보가 항상 메모리에 있어 모든 상품 조회가 빨라집니다.
3. Recycle Pool - 재활용 풀
일회성 대용량 데이터를 보관하기 때문에 매우 빠른 교체가 일어나는 풀입니다. 배치 작업이 주로 일어나는 풀입니다.
4. nK Pool
작은 테이블은 작은 블록, 큰 테이블은 큰 블록에 할당하여 데이터 특성에 맞게 최적화할 수 있는 풀입니다. 데이터 크기에 맞는 블록으로 메모리 효율성을 높이고 I/O 횟수를 감소시킵니다.
모든 버퍼 캐시는 상태를 가지게 됩니다.
Buffer State 버퍼 상태
각 상태가 존재하는 이유와 전이과정을 알아봅시다.
1. Free Buffer
즉시 사용이 가능한 빈 공간입니다. 시스템 시작이나 교체 후에 생성되며 새 데이터를 읽기 위한 공간을 확보합니다. 실제 예시로는, 사용자가 새로운 상품을 검색했을 때 Free Buffer에 로딩됩니다.
2. Clean Buffer
디스크와 동일한 데이터입니다. 언제든 덮어써도 되고, 빠른 교체가 가능합니다. 예시로, 도서관에서 빌린 책을 그대로 보관한다고 생각하면 이해하기 쉽습니다. -> 즉, 언제든 반납(교체)이 가능함
3. Dirty Buffer
메모리에서만 변경된 상태입니다. 디스크에 기록하기 전까지는 교체할 수 없으며, 트랜잭션 무결성을 보장합니다.
UPDATE product SET price = 99000 WHERE id = 'IP15';
위와 같은 쿼리문을 실행할 때 우선, 메모리의 가격만 변경되고 디스크에는 이전 가격이 남아있게 됩니다. COMMIT 후의 기록까지는 Dirty가 유지됩니다.
4. Pinned Buffer
현재 누군가 데이터를 사용하고 있는 상태입니다. 절대 교체할 수 없고 읽거나 쓰고 있는 데이터를 보호합니다. 동시성을 제어할 수 있습니다. 예시로, 사용자 1이 가격을 수정하고 있을 땐 Pinned가 되며 이 상태에서 사용자 2가 같은 상품을 조회할 때 대기가 됩니다.
그럼 이 버퍼들은 어떤 알고리즘으로 관리가 될까요?
LRU List
버퍼를 관리하는 과정에서 기존의 LRU 알고리즘은 한계가 존재합니다. 만약 대형 테이블을 전체 스캔하게 되면 더 자주 사용되는 데이터는 모두 밀려나고 캐시의 의미가 사라지게 됩니다.
예시로, 사용자 로그를 저장하는 10GB짜리 log_table을 전체 조회한다 했을 때, 상품이나 고객정보 등 중요한 데이터가 캐시에서 모두 제거되기 때문에 성능이 급락하게 됩니다.
Oracle은 개선된 LRU 알고리즘을 사용하여 성능을 유지시킵니다.
1. Midpoint Insertion 알고리즘
새 블록을 삽입하는 위치를 Midpoint(중간)으로 둡니다. 바로 Hot 영역으로 가지 않고 진짜 유용한지 검증 후 Hot으로 이동합니다
2. Touch Count 알고리즘
처음 접근 시 Cold 영역에 삽입하고 Touch Count를 1로 지정합니다. 접근할 때마다 Count가 증가하게 되고 임계값에 도달했을 때 Hot영역으로 이동하게 됩니다. 자주 사용되는 데이터만 Hot 영역에 상주하게 됩니다.
그렇다면 이 버퍼들을 찾아갈 때에는 어떤 방식을 사용할까요?
Buffer HashTable
버퍼 해시테이블을 사용합니다. 만약 해시테이블이 없다면 순차적으로 모든 버퍼를 탐색해야 되기 때문에 성능이 그리 좋진 않을 것입니다.
해시함수를 이용해 테이블에 저장하게 되고 각 버퍼의 식별정보를 비교하여 빠른 검색을 할 수 있습니다.
해시라는 자료구조에서는 해시충돌은 필연적으로 발생하게 되는데요,
체인으로 연결하여 순차 검색을 하게 됩니다. 체인이 길어지면 성능저하가 발생합니다.
해시 자료구조에 대한 글입니다.
2024.08.13 - [자료구조] - [자료구조] 해시(Hash), 그리고 JAVA
[자료구조] 해시(Hash), 그리고 JAVA
해시 (Hash)"입력 값(Input)을 고정된 길이의 데이터로 변환"해시 자료구조의 특징1. key에 value를 매핑하는 구조이다.2. 해시 함수(해시 알고리즘) 을 통해 key의 데이터를 Hash Table에 저장한다.3. key를
ejk5148.tistory.com
이러한 정보들은 버퍼 헤더에서 관리할 수 있습니다.
버퍼 헤더
버퍼 헤더의 필수 정보들
1. 상태정보
- Buffer State: Clean/Dirty/Free/Pinned → 현재 무엇을 할 수 있는지 결정
- Touch Count: LRU 위치 결정 → 얼마나 중요한 데이터인지 측정
- Access Mode: Shared/Exclusive → 동시 접근 제어
2. 블록 식별 정보
- Data Object ID: 어떤 테이블/인덱스인지?
- File Number: 몇 번 데이터 파일인지
- Block Number: 파일 내 몇 번째 블록인지?
- Class Number: 테이블인지 인덱스인지?
3. 동시성 제어 정보
- Buffer Latch: 이 버퍼의 독점권
- Shared Latch Count: 동시 읽기 세션 수
실제 상황 사용자 A: UPDATE 실행 → Exclusive Latch 사용자 B, C: SELECT 실행 → Shared Latch 대기
버퍼 캐시의 각 구조는 독립적으로 존재하는 것이 아닌 서로 유기적으로 연결되어 있습니다.
버퍼 상태 생명주기
쇼핑몰에서 상품 주문을 처리하는 예시를 들어보겠습니다.
-- 1. 고객이 상품 조회
SELECT * FROM product WHERE id = 'iPhone15';
Free -> Clean Buffer디스크에서 상품 정보를 읽어 Clean Buffer에 저장합니다.
-- 2. 재고 수정
UPDATE product SET stock = stock - 1 WHERE id = 'iPhone15';
Clean -> Dirty Buffer
메모리에서만 재고가 감소하고 디스크에는 반영이 되지 않습니다.
-- 3. 트랜잭션 커밋
COMMIT;
Dirty Buffer 유지
커밋을 해도 여전히 Dirty를 유지합니다. 실제 디스크에 쓰는 과정은 나중에 진행합니다.
Dirty -> Clean Buffer
DBWn 프로세스가 디스크에 기록 후 다시 Clean Buffer 상태가 됩니다.
Clean -> Free Buffer
메모리 부족 시 교체합니다. 다른 데이터를 위한 공간을 확보합니다.
전체 과정, SELECT 문을 예시로
SELECT * FROM orders WHERE customer_id = 12345;
1. 해시테이블 검색
해시 함수로 위치를 계산하고 해당 버퍼가 이미 메모리에 있는지 확인합니다.
2. 캐시 히트인 경우
버퍼 헤더를 확인하여 Pinned 상태로 변경합니다. LRU List에서 Hot 영역으로 이동하게 됩니다. Touch Count도 증가하겠죠? 그리고 데이터를 반환합니다.
3. 캐시 미스인 경우
Free Buffer를 찾고 없다면 LRU로 교체합니다. 디스크에서 블록을 읽어 Clean Buffer를 생성하고, Hash Table에 등록합니다. 그 후 LRU List에 삽입합니다.
'DB, SQL' 카테고리의 다른 글
[DB] Oracle SGA (System Global Area) - Shared Pool (3) | 2025.05.23 |
---|---|
[DB] Oracle Database 구조 (4) | 2025.05.15 |