데이터베이스 메모리 버퍼

곽태욱·2021년 7월 29일
0

메모리 버퍼

우리가 데이터베이스에 SQL 요청을 보내면 DBMS가 디스크에 접근해서 해당하는 데이터를 가져오는데, 디스크 접근 시 데이터 입출력은 디스크 블록 단위로 이뤄집니다. 하지만 디스크 입출력은 메모리 연산에 비해 시간이 오래 걸리기 때문에(일반적으로 디스크 연산이 몇 천 배 느림) 디스크 입출력 횟수를 최대한 줄이기 위해 디스크 입출력 결과를 메모리 버퍼에서 관리하는 방식을 사용합니다. 이렇게 디스크 접근 및 메모리 버퍼를 관리하는 주체는 아래와 같습니다.

  • buffer manager: 레코드는 블록 단위로 입출력되기 때문에 메모리에 있는 버퍼를 관리할 프로그램이 필요합니다.
  • file manager: 레코드는 파일에 저장되기 때문에 디스크에 있는 파일을 관리할 프로그램이 필요합니다.

메모리 버퍼를 사용하면 원하는 데이터가 메인 메모리의 DBMS 버퍼에 있을 때 디스크 입출력 연산을 하지 않아도 된다는 장점이 있습니다. DBMS는 먼저 버퍼에 원하는 레코드가 있는지 확인하고 있으면 디스크에 접근하지 않고 버퍼에 있는 레코드 데이터를 사용합니다. 만약 원하는 레코드가 없다면 디스크에 접근해서 블록을 가져오고 버퍼에 저장합니다. 그리고 현재 DBMS에서 사용 중인 페이지는 pin 상태가 되고 사용이 끝나면 unpin 상태로 바뀝니다.

하지만 메모리 버퍼 공간은 디스크 공간에 비해 작고 한정되어 있기 때문에 버퍼에 있는 페이지를 잘 관리하는 것이 중요합니다. 만약 버퍼 공간이 가득 차면 버퍼 공간에서 내보낼 페이지를 선택해야 하는데, 그렇다고 아무 페이지를 삭제하면 안 되고 unpin 상태인 페이지 중에서 아래 알고리즘을 사용해 삭제할 페이지를 선택합니다.

LRU

LRU(Least Recently Used)는 가장 오래 전에 마지막으로 사용했던 페이지를 버퍼에서 내보내는 알고리즘입니다. 직관적으로 생각했을 때 좋은 알고리즘으로 보이지만, 사실 데이터베이스에선 경우에 따라 안 좋을 수 있습니다. 왜냐하면 SQL 중 join 연산을 수행할 때 잘 생각해보면 최근에 접근한 레코드보다 접근한지 오래된 레코드에 먼저 접근하는 것을 볼 수 있습니다.

# Python pseudo code
join_result = []
for record1 in table1:
  for record2 in table2:
    if record1.column1 == record2.column2:
      join_result.append([*record1, *record2])

만약 테이블 table1과 테이블 table2가 있을 때 table1column1table2column2에 대해 join 연산을 수행하면 위와 같이 중첩 반복문을 수행합니다. 이때 table1의 record6과 table2의 record1에 접근한 후(파란 실선) table1의 record6과 table2의 record2에 접근하는데(파란 점선), 여기서 record2는 마지막으로 접근한지 가장 오래된 레코드고 recordn은 가장 최근에 접근한 레코드입니다.

이처럼 recordn은 가장 최근에 접근했지만 가장 나중에 접근할 것으로 예상되고 record2는 가장 오래전에 접근했지만 가장 빨리 접근할 것으로 예상되기 때문에, 데이터베이스 버퍼는 일반적으로 가장 최근에 사용한 페이지를 교체하는 전략을 사용합니다.

Toss immediate

특정 블록의 레코드에 대한 모든 처리가 끝나자마자 해당 블록을 메모리 버퍼에서 제거하는 알고리즘입니다.

MRU

LRU와 정반대의 알고리즘으로서, MRU(Most Recently Used)는 가장 최근에 연산이 끝난 블록을 버퍼에서 버리는 알고리즘입니다.


이렇게 버퍼에서 내보낼 페이지를 골랐는데 해당 페이지 내용이 디스크에 있는 블록 내용이랑 동일하다면 단순히 페이지를 삭제하면 되지만, 다르다면 페이지 내용을 디스크 블록에 반영해줍니다. 보통 페이지마다 dirty 플래그와 같이 페이지가 수정됐는지 여부를 따로 관리합니다.

profile
이유와 방법을 알려주는 메모장 겸 블로그. 블로그 내용에 대한 토의나 질문은 언제나 환영합니다.

0개의 댓글