
15-445/645 Intro to Database Systems/Fall 2022 4강을 보고 정리한 내용입니다.
링크: https://www.youtube.com/watch?v=2HtfGdsrwqA
지난 강의에선 page의 layout 중 slotted pages 방식을 살펴봤다. Slotted-Page 디자인은 여러 문제가 있는데 다음과 같다.
이러한 문제를 해결하기 위해 생각을 전환해보자. 데이터의 생성을 하되 덮어쓰지 않는 시스템을 구현한다면 공백이 생기지 않아 fragmentation 문제를 해결할 수 있을 것이다.
Log-structured storage 방식은 튜플을 저장하지 않음으로써 생각을 전환한다. 튜플을 저장해야하는데 튜플을 저장하지 않는다니 언뜻보면 모순같다. 하지만 log-structured storage 방식은 튜플의 변화를 담고 있는 로그 기록을 통해 간접적으로 튜플 정보를 저장한다. 구체적으로, 로그 기록에 있는 튜플의 고유 식별자를 통해 튜플을 식별한다. 아래 그림과 같이 PUT, DELETE 명령어를 통해 튜플을 저장 혹은 삭제한다.

이러한 방식으로 페이지 내에 로그 기록을 저장했을 때, 페이지가 가득찼을 때, DBMS는 디스크에 페이지를 기록하고 새로운 페이지에 정보를 저장하기 시작한다. 따라서, 디스크에 기록하는 방식이 sequential하고 디스크에 저장된 페이지를 변경할 수 없게 된다. 페이지를 변경하지 않기 때문에 random disk I/O 문제를 부분적으로 해결한다. 앞선 강의에서 하드웨어의 물리적인 제약으로 인해 random write보다 sequential write가 더 빠르다는 것을 확인했다.

Write가 sequential하다는 것을 알았는데 그럼 이제 로그에 남아있는 기록을 어떻게 읽을지 알아본다. 특정 튜플에 대한 가장 최신 로그가 그 튜플의 현재 상태를 결정짓는다. 따라서 특정 ID의 튜플을 읽기 위해 DBMS는 해당 ID에 해당하는 최신 로그 기록을 찾는다. 튜플 ID를 찾는 데에 있어서 읽는 시간이 길어지는 random disk I/O 문제가 발생하는데 튜플 ID를 최신 로그 기록에 매핑하는 인덱스를 유지하고 관리한다면 완화할 수 있다. 만약 로그 기록이 메모리에 내에 있다면 바로 읽고 디스크에 있다면 검색한다.

튜플을 읽는 시간을 단축하는 또 다른 방법은 로그 데이터 자체를 주기적으로 압축, 즉 compaction을 수행하는 것이다. 이는 현재 시점에 불필요한 정보를 줄여 useless disk I/O를 완화시키는 의미도 있다.
동일한 튜플에 대한 로그 기록 중엔 마지막 로그 기록만이 의미가 있다. 따라서, 다음 그림과 같이 튜플 아이디 #101, #102, #103, #104, #105에 대한 가장 최신 기록만을 취합해 새로운 페이지를 만든다.

DBMS는 compaction이 완료된 페이지의 튜플 ID를 정렬하여 더 빠른 read를 가능하게 한다. 이를 Sorted String Tables(SSTables)이라고 한다.

Compaction을 수행하는 방법은 universal compaction과 level compaction 두가지가 있다. 간단히 짚어보면, universal compaction은 모든 레벨의 로그 파일을 동시에 병합하는 방식이고, level compaction은 레벨 단위로 로그 파일을 병합하는 방식이다.

Log-structured 페이지 레이아웃도 단점이 존재하며 다음과 같다.
이러한 이유로 slotted 페이지 방식을 아직 log-structured 방식에 비해 많이 사용한다. 하지만 분산형 시스템과 같은 경우에 log-structured 방식은 확실한 강점이 있으므로 점점 더 많이 쓰이는 추세에 있다.
마지막으로 정리하자면, log-structured 저장 방식은 튜플을 쓰는 시간이 빠르고, 읽는데엔 상대적으로 느리다. 따라서, 튜플 ID를 최신 로그 기록에 매핑하는 인덱스를 유지, compaction을 통해 튜플을 읽는 시간을 단축한다.
3강 Database Storage, Part1에서 튜플은 본질적으로 바이트의 시퀀스로 이러한 바이트를 해석하여 타입과 값으로 변환하는 것이 DBMS의 역할이라고 했다. 1-2.1 Data representation에서 DBMS가 타입과 값을 어떻게 바이트로 나타내는지를 살펴본다.
Variable-precision numbers는 정확하지 않은 변수 숫자 유형이다. 다음 그림과 같이 소수점 아래 20자리까지 시각화하여 최대의 정밀도를 구하고자하여도 하드웨어가 숫자들을 정확하게 표현하지 못한다는 것을 알 수 있다.

대부분의 경우 variable-precision numbers가 충분하겠지만 로켓 공학과 같이 정확한 수치가 필요할 땐 fixed precision numbers를 사용한다. 이러한 데이터가 수치를 정확하게 구할 수 있는 이유는 데이터의 길이, 소수점의 위치와 같은 추가적인 메타 데이터를 거의 문자열과 같은 형식으로 저장하기 때문이다. 많은 정보를 저장해야하므로 자연스레 비용이 증가한다.
시스템마다 저장 방식이 다르다는 점을 주의하고 MySQL이 fixed-point precision 숫자를 저장하는 방식은 다음과 같다. 이는 흔히 메모리에 바이트에 따라 의미를 나누던 익숙한 방식과는 다른 접근방식이다.

임의의 길이를 갖는 데이터 타입으로 주로 header과 함께 저장된다. Header에는 다음과 같은 정보가 저장된다.
대부분의 DBMS는 페이지 크기보다 큰 튜플을 저장하지 못하게 한다. 일부 이를 허용하는 DBMS(Postgres, MySQL)는 이러한 튜플을 overflow 페이지에 따로 저장하고 튜플에 이 페이지의 위치를 저장한다.

일부 DBMS(Oracle, Microsoft)는 큰 데이터 파일을 아예 외부 파일에 저장한다. DBMS 내에 큰 공간을 차지하지 않게한다는 장점이 있지만 DBMS는 이 파일의 내용에 대한 통제권을 잃는다.

튜플이 아닌 데이터베이스 자체에 대한 메타 데이터는 system catalog에 저장한다. 저장하는 메타 데이터는 다음과 같은 정보를 저장한다.
DBMS의 INFORMATION SCHEMA를 통해 데이터베이스에 대한 정보를 얻을 수 있다.
Q1. 현재 데이터베이스에 있는 테이블 모두 나열하시오.
# 표준 sql
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE table_catalog = '<db_name>';
# mysql
SHOW TABLES;
SHOW TABLES; 결과
Q2. student 테이블에 대하여 자세히 알려주세요.
# 표준 sql
SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'student';
# mysql
DESCRIBE student;
DESCRIBE student; 결과