이 글은 'Fundamentals of Database Engineering'에 관한 아래 유데미 강의를 보고, 공부한 내용을 정리하였습니다.
https://www.udemy.com/course/database-engines-crash-course
데이터베이스 엔진
데이터베이스 엔진이란?
- 실제 디스크에 CRUD 작업을 처리하는 라이브러리
- 크게 2가지로 나눌 수 있음. 디스크에 데이터를 저장하는 것과 실제로 작업을 하는 것
- 단순히 key-value를 저장하는데 그칠 수도 있고, 완전한 ACID 트랜잭션을 지원하기 위해서 복잡할 수도 있음
- 데이터베이스 엔진은 단순히 데이터를 저장하는 것뿐 아니라, Master-Slave 구조를 이루게 하거나 프로시저를 저장하는 등 엔터프라이즈 레벨에서 사용되는 다양한 기능을 제공함
- DBMS는 데이터베이스 엔진을 사용하여 그 위에 기능을 구축할 수 있음.
- use case에 따라 엔진을 고르기만 하면됨
- MySQL & MariaDB와 같은 몇몇의 DBMS는 DB엔진을 변경할 수 있는 유연함을 제공함
- Postgres를 포함한 대부분은 내장 엔진이라 교체할 수 없음
데이터베이스 엔진 별 특징
MyISAM
- Indexed sequential access method(인덱스 순차 접근 방법)의 줄임말
- B-tree 인덱스들이 행을 직접 가리킴, 기본 키가 없음. (모든 게 인덱스여서 필요가 없음)
- 트랜잭션 지원 없음 (ACID x)
- 삽입이 빠르고, 업데이트와 삭제는 문제가 있음(조각을 만들어냄)
- 삽입은 파일 끝만 알면 되기 때문에 매우 빠르지만, 수정/삭제는 전체 파일의 구조를 변경하는 것이기에 느림
- DB가 충돌 나면 테이블이 손상됨
- 테이블 수준 잠금 지원, 행 수준 잠금 X
- MySQL 5.5까지는 MyISAM이 기본 엔진이었으나, 행 수준 잠금, 트랜잭션 지원을 위해 넘어감
InnoDB
- B+tree로 항상 기본 키가 있어, index는 기본키를 가리킴(직접 행을 가리키지 않음)
- MySQL과 MariaDB의 default
- ACID 준수, 외래키 지원, 트랜잭션 지원, 테이블 스페이스 지원
- 행 레벨 잠금 제공
- 오라클의 소유
XtraDB
- InnoDB의 fork
- MariaDB 10.1까지 사용하다가 XtraDB는 InnoDB의 최신상태를 따라가지 못해, 10.2부터는 InnoDB로 default가 바뀜
SQLite
- 매우 인기 있는 임베디드 로컬 데이터베이스 (운영체제, Web 등등)
- B-Tree 사용
- Postgres와 유사함
- 완전한 ACID 지원, 테이블 수준 락 (행 잠금 X)
- 동시에 읽고 쓸 수 있음
Aria
- MyISAM과 유사함 (오라클에서 벗어남)
- MyISAM보다 충돌에 안전하도록 고침
- 특히 MariaDB를 위해 설계됨
Berkeley DB
- 현재 오라클이 소유 중
- Key-value 내장형 데이터베이스
- ACID, 트랜잭션, 락, 복제 지원
- 한 때 bit coin core로 사용됨(현재는 LevelDB로 변경)
- MemcacheDB에 사용되고 있음
LevelDB
- Google에서 만듦, 빠른 삽입이 가능한 DB를 원함
- LSM tree 이용, SSD에 좋음(SSD는 업데이트에 대해 수명에 영향을 받음)
- 트랜잭션 없음
- 파일마다 레벨이 있음 (Memtable(메모리 테이블에 쓸 때, WAL(디스크에 커밋 로그 기록)을 통해 데이터 안정성 확보), 속도에 따라 Level 0~6
- 파일이 커지면, 더 큰 레벨은 병합되어 디스크로 보내짐
- Bit coin core, AutoCAD, Minecraft에서 사용
RocksDB
- Facebook에서 만듦, LevelDB를 fork
- LSM사용, 트랜잭션 지원, ACID 지원
- 높은 퍼포먼스, 멀티스레드 압축 지원 (LevelDB는 단일 스레드)
데이터베이스 커서
커서란?
- 커서는 쿼리를 실행시키지 않고, 실행 계획만 짜서 declare 할 수 있음. 필요할 때 fetch 하면 N개의 행씩 가져올 수 있음. (한 번에 다 가져와서 처리하는 게 아닌, 조금씩 처리하는 것)
장점
- 커서를 쓰면 DB에 연결된 백엔드 응용프로그램에서 클라이언트 측 메모리를 절약할 수 있음
- 커서를 쓰면 스트리밍을 할 수 있음. 계속해서 행을 다른 웹 소켓 연결로 스트리밍 가능. (gRPC 등)
단점
- 커서는 상태를 유지함. 데이터베이스에 할당된 메모리와 해당 커서를 가리키는 트랜잭션이 존재하게 됨. 이는 다른 서버나 프로세스에서 요청을 보내면 그 프로세스는 커서에 대해 알지 못하기에 기본적으로 커서를 공유할 수 없음. (이런 상황에서는 페이징이 더 좋을 수도 있음)
- 장기간 실행되는 프로덕션에 커서를 사용하면, 트랜잭션이 장기간 실행되어 인덱싱이나 DDL을 정상 수행 못하는 등 DB에 좋지 못함.
서버 측 vs 클라이언트 측 커서
- 클라이언트(예를 들면 python) 측 커서: 데이터베이스와 연결할 때 클라이언트에서 커서를 생성한 후, DB에서 쓰기/읽기 작업을 수행함. 쿼리의 모든 결과는 실행되고 네트워크를 통해 클라이언트에 전달됨
- 서버(DB) 측 커서: 데이터베이스에서 커서가 생성되고, 절대적으로 필요할 때만 그 결과를 가져오게 됨. 결과는 실제로 서버에서 실행되고 저장되며, 클라이언트는 점진적으로 가져오게 됨
장단점
클라이언트 측 커서
- 장점: 서버 측 오버헤드를 최소화, 데이터를 클라이언츠 측에서 메모리에 할당하기 때문
- 단점: 네트워크 대역폭에 문제 발생. 클라이언트 측 메모리가 부족할 경우 문제
서버 측 커서
- 장점: 많은 행을 처리할 때 나눠서 처리할 수 있음
- 단점: 많은 커서들이 누적되면, 메모리 leak 발생
상황에 따라 올바른 방법 사용 필요