이번 포스팅은 DBMS 에 대한 포스팅이다.
이번 주는 MySQL을 중심으로 관계형 데이터베이스의 기본 개념과 SQL 문법을 훑는 한 주였다.

데이터베이스는 학부시절 꽤 재밌게 수강했던 강의 중 하나였다.
우리 교수님이 데이터베이스 돛단배 책 번역을 맡으셨던 분이셨고, 강의력이 훌륭하셨던 기억이 난다.
개발자에게 있어서 데이터베이스는, 단순히 데이터를 저장하기 위한 도구로서만 동작하는건 아니다.
데이터의 정제, 구조화, 관리, 조회와 사용의 흐름을 만들어내기 위해서 사용하는 것이다.
그래서 이번 주는 그 일련의 과정들을 한 주에 압축해서 배우게 된다... 고 생각했지만
대부분은 쿼리문에 대한 이야기였다.
단순히 쿼리문을 작성하는 이야기로 끝나는 건 아쉽기 때문에 나는 DBMS의 메인 특징을 살펴보기로 했다.
많다면 많지만, 또 그렇게 복잡한 이야기는 아니기에, 데이터가 만들어지고 조회되기까지의 흐름을 기준으로 정리해보려고 한다.
DB와 DBMS : 데이터의 저장과 관리
가장 먼저 들어간 개념은 DB와 DBMS의 차이다.
DB는 데이터베이스, 즉 데이터의 집합이다.
DBMS는 DataBase Management System, 즉 데이터를 관리하는 소프트웨어다.
DBMS는 데이터를 중복없이 관리하고, 데이터가 잘못 저장되지 않도록 제약을 걸어서 다른 프로그램이 실제 저장 방식에 의존하지 않도록 중간 계층을 역할을 해주는 것이다.

DBMS으로 데이터베이스를 구축하고 난 후부터는, 여러 사용자들이 동시에 DBMS를 통해서 데이터를 접근할 수 있게 된다.
동시에 다양한 사용자들로부터 데이터 접근이 필요한 기능이 필요한 어플리케이션의 경우 자연스럽게 DBMS의 힘을 빌리게 된다.
그렇게 한 곳에서 데이터를 집중적으로 관리하면서 데이터의 품질과 운영 효율을 높일 수 있다.
DBMS가 맡는 대표 기능
DBMS가 무엇인지는 이제 어느정도 알았다.
그러면 DBMS가 정확히 어떤 기능을 수행하는지 알아보자.

우선, DBMS는 우리가 사용할 데이터를 Schema로 정의한다. 데이터의 구조, 제약 조건, 데이터간의 관계를 정의하면서 해당 데이터의 정보인 메타데이터를 관리해준다. 이렇게 스키마로 데이터를 정의하게 되면 데이터의 오염을 막고 일관된 구조를 만들어 줄 수 있다.
DBMS는 데이터를 파일이나 페이지 단위로 저장하고, 인덱스를 활용해 저장 구조를 관리하게 된다. 단순히 데이터를 쌓아두는 것이 아니라, 최적화된 구조를 만들어서 데이터의 탐색에 효율을 추구한다.
이제 사용자들은 DBMS에게 질의 (Query) 를 보낸다. DBMS는 해당 SQL 쿼리를 해석하면서 Optimizer가 좀 더 효율적이고 빠른 쿼리로 최적화하여 정보를 제공해준다.
이때, 데이터의 ACID 특성을 보장하기 위해서 Transaction 처리를 수행하게 된다. 수업시간에는 트랜잭션에 대해서 그다지 중요하게 짚고 넘어가지 않았다. 하지만 실제로 DBMS를 다룰 때, 가장 중요하게 보아야 하는 지점이 트랜잭션 부분이라고 생각한다. 트랜잭션이 중요한 이유는, 현실세계의 비즈니스와 직결되는 부분이기 때문이다.
쇼핑몰 결제나, 은행 송금, 티켓 예매와 같은 금전적인 영역의 처리 중간에 서버가 다운되거나 에러가 날 가능성이 있다. 이 때, 트랜젝션이 데이터가 꼬이지 않도록 막아주는 거의 유일한 생명선이라고 봐도 무방하다. 만약에 트랜잭션 관리가 안된다면 돈은 빠져나갔는데, 결제 완료는 안되는 말도 안되는 상황이 벌어질 수도 있다.
마찬가지로 여러명의 유저가 동시에 접속해서 동일한 데이터를 처리하려고 할 떄, 트랜잭션의 격리 수준 (Isolation Level)에 따라서 시스템의 안정성이 달라지게 된다. 티켓팅을 할 때 동일한 좌석을 두 명이 동시에 예약하는걸 막아주는 역할을 담당한다.
이런 특성과 함께 DBMS는 데이터에 접근 할 수 있는 권한도 설정할 수 있다. 함부로 접근할 수 없는 기밀 데이터나, 개인정보와 같이 민감한 데이터에 대한 접근 권한을 설정해주면서 보안성을 챙겨줄 수 있다.
마지막으로 DBMS는 데이터의 백업이나 복구에 능하다. 실제 트랜잭션 단위의 로그 기록을 남기면서 실제 DB가 엉망이 되어도 이전의 정상적인 상태로 되돌리는 것이 가능하다.
DBMS 정리

DBMS를 사용하는 이유는, 사용자와 데이터를 중재하면서 실시간으로 다양한 업무 로직을 처리해줄 수 있기 때문이다.
또한 각 프로그램이 데이터를 직접 관리하는 것보다, 중앙집중적으로 데이터를 표준화하고 안전하게 운영할 수 있게 해주는 시스템을 운영하면서 효율적인 처리를 꾀할 수 있다.
Q. 그냥 파일 시스템 쓰면 안되나요?
사실 생각해보면 우리가 일반적인 컴퓨터 작업을 할 때 굳이 데이터베이스를 쓰지 않는다.
사진을 저장하고, 보고서를 저장하고, 프로젝트 코드를 저장할 때도 전부 파일시스템을 쓰고 있지 않은가?
DBMS가 좋은 건 알겠는데, 그냥 파일 시스템을 써서 관리하는것도 크게 불편함이 없을 것 같지 않나?
물론 파일 시스템이 나쁜 것 만은 아니다.
하지만 데이터의 저장 관점에서는 그다지 좋은 방식은 아니다.

우리가 파일 데이터를 사용할 때 불편함이 가장 크게 와닿는 부분이라면, 역시 중복되는 데이터일 것이다.
에를 들어 각 부서별 예산안 엑셀 파일을 따로 만들면, 모든 파일 상단에 '회사 대표이사 이름' 이나 '본사 주소' 가 중복으로 들어가게 된다. 그런데 만약 중간에 대표이사가 바뀌면 수십 개의 부서 예산안 파일을 다 열어서 수정해야 한다. 하지만 DBMS를 쓰면 회사 기본 정보는 중앙에서 한 번만 관리하고 예산안은 그 값을 불러오기만 하면 되므로 중복 관리가 훨씬 쉬워지게 된다.

동일한 에산안 파일인데 작년과 올해 들어갈 숫자가 달라진다고 똑같은 엑셀 파일을 생성하는 것도 비슷하다. DBMS를 쓰면 단순히 데이터를 추가해주는 일만으로 예산안 관리를 수월하게 할 수 있다.
그리고 파일 시스템으로 데이터를 관리한다면 데이터의 일관성을 보장하기 어렵다. 하지만 DBMS는 제약조건 특성으로 언제나 일관된 데이터 형식을 가질 수 있게 된다.

한마디로, 파일 시스템은 단순히 데이터를 저장만 하는 방식이고, DBMS는 데이터를 체계적으로 운영할 수 있는 어플리케이션이다.
DBMS의 핵심 구조
이제 DBMS가 어떤 녀석이고, 뭘 하는지도 알았다.
그렇다면 DBMS가 어떻게 동작하는지를 조금 알아볼 필요가 있다.

우리가 일주일 수업동안 배운건 사용자/어플리케이션에서 SQL 인터페이스를 통해 질의를 넣어보는 과정이었다.
물론 해당 부분이 우리 개발자에게 있어서 제일 생각을 많이 하게 만드는 부분이기도 하다.
"내가 원하는 데이터를 뽑아오기 위해서 어떻게 쿼리를 작성해야 하는거지? "
그런데 위 DBMS 아키텍처 구조도를 한 번 보면, 우리가 그토록 고민하며 질의를 던지던 'SQL 인터페이스' 는 전체 DBMS 구조에서 맨 윗단, 즉 입구에 불과하다.
그 아래로는 사용자의 질의를 분석하고 최적화하는 질의 처리기, 데이터의 안전성과 동시 접근을 제어하는 트랜잭션/동시성 관리자, 그리고 실제 데이터가 디스크에 어떻게 저장되고 캐싱되는지 관리하는 스토리지 관리자까지 수많은 구성 요소들이 겹겹이 층을 이루어 유기적으로 협력하고 있다.
단순히 데이터를 가져오는 일만 생각하지 말고, 한 번 어떻게 처리가 되는지도 확인해보는 것도 좋다.
질의 처리기 (Query Processor), 옵티마이저 (Optimizer)
우리가 쿼리를 던지고 나서 결과를 받기까지, 그 짧은 찰나에 DBMS 내부에서는 생각보다 훨씬 복잡하고 체계적인 일들이 벌어진다. 우리가 던진 쿼리문은 가장 먼저 질의 처리기(Query Processor) 를 만나게 되는데, 여기서 크게 3단계를 거친다.
- 파서(Parser): 내가 작성한 SQL 문법에 오타는 없는지, 의미상 오류는 없는지 구문 트리로 변환하며 분석한다. 문법 에러가 나면 보통 여기서 끊어낸다.
- 최적화기(Optimizer): 통과된 쿼리를 '어떻게 실행해야 가장 빠르고 비용이 적게 들지' 실행 계획을 짠다. 사실상 쿼리 성능을 결정짓는 가장 핵심적인 녀석이다.
- 실행기(Executor): 최적화기가 짜준 계획표대로 연산을 수행하고 결과를 만들어낸다.
결국 우리가 "쿼리를 잘 짠다" 라고 하는 것은, 단순히 결과를 뽑아내는 것을 넘어 '최적화기(Optimizer)가 가장 효율적인 실행 계획을 선택할 수 있도록 쿼리를 던져주는 것' 을 의미한다.
물론 그렇다고 아무렇게나 쿼리를 짠다면 내가 원하는 결과 자체를 못 받을 수도 있으니, 최소한 해당 쿼리가 어떤 동작을 하는지는 익히는게 좋다.
SELECT E.이름, D.부서명
FROM 사원 E
JOIN 부서 D ON E.부서ID = D.부서ID
WHERE E.연봉 > 8000
AND D.위치 = '서울';
가령 이런 SQL 코드를 작성한다고 생각해보자.
사원 테이블에는 1만개의 레코드가 있고, 부서 테이블에는 100개의 부서 레코드가 있다. 이 때 최적화가 없이 쿼리의 순서를 그대로 실행하게 되면 조인(JOIN) 을 먼저 수행하고, 이후에 필터링을 거치게 된다. 그러면 총 100만개의 데이터에서 필터링을 각각 수행하게 된다.
하지만 조금만 생각해보면 꽤 바보같은 짓이다. 어차피 버려질 데이터를 조인하는 것은 큰 의미가 없기 때문이다. 그래서 옵티마이저는 반대로, 필터링을 먼저 넣어서 레코드의 개수를 줄인 후에 조인을 수행한다.그러면 필터링 된 사원의 수도 적고, 부서의 수도 적어져서 둘의 조인 연산이 훨씬 가벼워지게 된다.

옵티마이저의 핵심 역할은 시간과 코스트를 최소화 할 수 있도록 쿼리를 최적화해주는 일이다. 우리가 어떻게 쿼리를 짜던지 옵티마이저의 결과를 바탕으로 다시 쿼리를 만들어 실행시켜주게 된다.
하지만 결국 옵티마이저도 만능은 아니기 때문에 우리가 쿼리를 개떡같이 짜 넣으면 옵티마이저도 힘을 쓸 수가 없다. 그렇기 때문에 우리가 쿼리 공부를 소홀히 해서는 안된다는 것이다.
그리고 우리의 쿼리가 어떻게 동작하는지도 알려주는 방법도 있다.
EXPLAIN - 쿼리의 실행결과를 찾아보는 법
-- 쿼리 맨 앞에 EXPLAIN만 붙이면 된다!
EXPLAIN
SELECT E.이름, D.부서명
FROM 사원 E
JOIN 부서 D ON E.부서ID = D.부서ID
WHERE E.연봉 > 8000 AND D.위치 = '서울';
쿼리의 사용 방식에 대해서 더 자세하게 알고 싶으면 `EXPLAIN` 명령어를 쿼리 맨 앞에 붙여주자.
-> Hash Join (cost=105.00..210.50 rows=10)
-> Index Scan using idx_연봉 on 사원 E (cost=0.00..50.00 rows=500)
Index Cond: (연봉 > 8000)
-> Hash (cost=10.00..10.00 rows=10)
-> Seq Scan on 부서 D (cost=0.00..10.00 rows=10)
Filter: (위치 = '서울')
그러면 이렇게 DBMS에서 해당 쿼리에 대한 Execution Plan을 출력해준다.
처음 볼 때는 이게 무슨 소리인가 싶겠지만, 조금만 뜯어보면 최적화기가 어떻게 일하고 있는지 바로 알 수 있다.
우리가 눈여겨볼 점은 주로 두 가지 핵심 키워드를 찾아보면 된다.
- Scan 방식 (어떻게 데이터를 뒤졌는가?):
- Seq Scan (또는 Table Access Full): 테이블을 처음부터 끝까지 깡으로 다 뒤졌다는 뜻이다(Full Scan). 데이터가 몇 건 없다면 상관없지만, 수백만 건짜리 테이블에서 이게 떴다면 최대한 빠르게 해결할 수 있도록 인덱스를 생성하거나 적절하게 쿼리를 튜닝할 필요가 있을지도 모른다...
- Index Scan: 개발자가 만들어둔 인덱스를 타고 빠르게 데이터를 찾아냈다는 뜻이다.
- Cost (비용):
- CPU와 I/O 자원을 얼마나 쓸지 예상한 수치다. 낮을수록 빠르고 효율적이다.
사실 스캔 방식이 Full Scan이라도 무조건 나쁜 방식이라고 말하는건 아니다. 실제 데이터의 분포나 `WHERE` 조건절에 따라서 예상되는 코스트가 달라지기 때문이다.
마찬가지로, Explain에서 나오는 JOIN 전략도 여러가지가 존재한다. 데이터의 양과 인덱스의 유무, 가용 메모리 등을 보고 판단해서 괜찮아 보이는 알고리즘을 선택하게 된다. 이 경우에는 Hash Join을 사용할 것을 볼 수 있다.
결국 우리가 Explain을 통해 쿼리 실행 계획을 확인하는 이유는, 옵티마이저가 상황에 맞는 적절한 조인 방식을 선택했는지 검사하기 위함이다. 만약 수천만 건의 데이터를 여러 번 조인하는데 옵티마이저가 무식하게 Nested Loop Join을 돌리고 있다면 쿼리를 처리하는 동안 점심먹고 커피까지 사와도 괜찮을지도... 아무튼 개발자는 인덱스를 추가하거나 쿼리를 수정하여 옵티마이저가 Hash Join 같은 더 나은 길을 선택하도록 유도해야 한다.

그렇게 대략적으로 DBMS가 어떻게 동작하는지도 살펴보았다.
단순히 사용할 쿼리를 짜는 것도 중요하지만, 실제 돌아가는 방식을 이해하고 사용할 때 좀 더 효율적으로 쓸 수 있을 것이다.
사실 DBMS에 대한 얘기를 더 하자면 무궁무진하게 많은 내용을 풀어낼 수 있다.
처음에 언급했던 트랜잭션에 관한 이야기라든가, 데드락(Deadlock)의 발생 원인 같은 것들 말이다.
하지만 이번 포스팅은 SQL 문 뒤에서 어떤 일이 벌어지는지를 이해하는 것만으로도 충분하지 싶다.
기회가 된다면 트랜잭션과 데드락에 대해서 포스팅을 올려볼 생각이다.
현재 교육에서는 JDBC에 대한 설명으로 넘어가게 되었다.
JDBC는 Java Database Connectivity으로, 애플리케이션 단계에서 DBMS로 쿼리를 보내는 표준 인터페이스 역할이다.
자바에서는 대략적인 규격만 정의해둔 뒤, 각 DB 회사에서 만든 드라이버(Driver)를 이용해 쿼리를 송수신하는 형태다.
이 부분은 학부 수업때 배우지 못한 영역이기 때문에, 앞으로 배울 내용들에 흥미가 생긴다.
어느덧 6월이 다가오고 있다.
날씨도 더워지고 공기도 습해지고, 이제 곧 장마철이 오겠거니 싶다.
교육도 절반 가까이 지나갔다. 시간이 참 빠르다 느낀다.

'개발 > KB IT's Your Life 7기' 카테고리의 다른 글
| KB IT's Your Life 7기 - JDBC와 MyBatis로 백엔드랑 친해지기 (0) | 2026.06.13 |
|---|---|
| KB IT's Your Life 7기 - 2026 중간 회고록 (0) | 2026.06.07 |
| KB IT's Your Life 7기 - 코딩테스트 특강 2 (0) | 2026.05.23 |
| KB IT's Your Life 7기 - 코딩테스트 특강 (0) | 2026.05.17 |
| KB IT's Your Life 7기 - Java 프로그래밍 2 (0) | 2026.05.10 |