데이터베이스
Database
개념
서비스가 남겨야 할 기록을 정해진 구조로 쌓아 두고 필요한 것만 빠르게 찾아 꺼내 주는 시스템입니다.
등장 배경
프로그램이 남겨야 할 것을 파일에 직접 적어 두던 시절이 있었습니다. 주문이 들어오면 주문 파일 끝에 한 줄을 붙이고, 회원이 가입하면 회원 파일 끝에 한 줄을 붙였습니다. 적는 일은 쉬웠습니다. 문제는 그다음이었습니다.
첫째, 찾는 데 시간이 들었습니다. 파일에는 순서라는 것이 없어서 특정 주문 한 건을 꺼내려면 처음부터 끝까지 읽어야 했습니다. 줄이 백만 개면 백만 개를 다 읽습니다. 둘째, 두 사람이 같은 파일을 동시에 고치면 나중에 저장한 쪽이 앞사람의 수정을 통째로 덮어썼습니다. 셋째, 같은 사실이 여러 파일에 흩어져 있었습니다. 회원 이름이 회원 파일에도 주문 파일에도 적혀 있으면, 바꿀 때 한쪽만 고쳐지는 일이 생기고 그때부터는 어느 쪽이 맞는지 아무도 모릅니다. 넷째, 쓰는 도중에 프로그램이 죽으면 반만 적힌 줄이 남았습니다. 돈은 빠져나갔는데 주문 기록은 없는 상태가 이렇게 만들어집니다.
페이지덱도 창업 직후 반년은 이 시절을 축소판으로 겪었습니다. 기업 고객 계약 정보를 스프레드시트 한 장에 모아 두고 수아와 규원이 같이 고쳤습니다. 어느 날 수아가 손본 갱신 날짜 스무 줄이 다음 날 아침에 전부 원래 값으로 돌아와 있었습니다. 규원이 그 전에 열어 둔 창에서 저장을 눌렀기 때문입니다. 맞는 값을 가려내는 데 이틀이 걸렸고, 그사이 만료가 임박한 계약 두 건을 놓칠 뻔했습니다.
데이터베이스는 이 네 가지를 프로그램마다 따로 풀지 말고 한 곳에서 풀자는 발상입니다. 데이터를 어디에 어떤 모양으로 둘지는 데이터베이스가 정하고, 프로그램은 무엇을 원하는지만 말합니다. 찾는 일은 미리 만들어 둔 색인이 맡고, 동시에 들어온 수정은 순서를 세워 하나씩 처리하고, 중간에 끊긴 작업은 아예 없던 일로 되돌립니다. 그래서 수백만 건 중 한 건을 0.01초에 찾아내는 일이 프로그램을 짠 사람의 실력과 무관해집니다.
분야 구성
데이터베이스 아래 묶인 말은 여덟 갈래입니다. 무엇을 골라 쓰느냐가 종류, 고른 것에 어떻게 말을 거느냐가 질의입니다. 안을 어떤 모양으로 짜느냐가 구조, 거기서 빠르기를 뽑아내는 일이 성능입니다. 값이 어중간하게 남지 않게 지키는 것이 일관성, 살아 돌아가는 동안 돌보는 일이 운영입니다. 나머지 둘은 코드에서 다루는 방법인 도구와 누가 무엇까지 볼 수 있는지인 보안입니다.
종류는 무엇을 골라 쓸지 가르는 갈래이고 네 가지가 있습니다. 나뉘는 기준은 데이터를 어떤 모양으로 담느냐입니다.
- 관계형 데이터베이스 — 행과 열이 있는 표에 담고, 표끼리는 서로를 가리키는 값으로 이어 둡니다. 회원 표와 주문 표를 따로 두고 주문 줄마다 회원 번호를 적어 둡니다. 업무 시스템의 기본값이라 대개 여기서 시작합니다.
- NoSQL — 표 모양을 미리 정해 두지 않아도 되는 계열입니다. 기록마다 들어 있는 항목이 달라도 되고, 항목을 새로 더할 때 구조를 고치지 않습니다. 대신 기록끼리 이어 주는 일은 프로그램이 직접 합니다.
- 키-값 저장소 — 열쇠 하나에 값 하나를 매달아 두고 열쇠로만 꺼냅니다. 구조가 단순한 만큼 빠르고, 로그인 상태나 자주 쓰는 계산 결과를 잠깐 얹어 두는 데 씁니다.
- 벡터 데이터베이스 — 문장의 뜻을 숫자 목록으로 바꿔 저장하고, 글자가 아니라 의미가 가까운 것을 찾아 줍니다. "환불 어떻게 하나요" 와 "돈 돌려받고 싶어요" 를 같은 질문으로 묶어 내는 검색이 여기서 나옵니다.
질의는 담아 둔 것을 꺼내는 방법을 다루는 갈래입니다. SQL은 관계형 데이터베이스에 무엇을 원하는지 적어 보내는 표준 언어입니다. 어떻게 찾을지가 아니라 무엇을 원하는지만 적는다는 점이 다른 언어와 다릅니다. 지난달에 가입한 회원 중 결제가 없는 사람을 뽑아 달라고 적으면, 어느 표를 먼저 읽고 어떤 순서로 맞출지는 데이터베이스가 고릅니다. 그래서 데이터가 백 배로 늘어도 같은 문장을 그대로 씁니다.
구조는 안을 어떤 모양으로 짜느냐를 다루는 갈래이고 여섯 가지가 있습니다.
- 스키마 — 어떤 표가 있고 표마다 어떤 칸이 있으며 칸에 무엇이 들어갈 수 있는지를 적어 둔 설계도입니다. 가입일 칸에 날짜만 들어가게 정해 두면 엉뚱한 글자가 섞이는 사고가 애초에 막힙니다.
- 테이블 — 행과 열로 데이터를 담는 실제 저장 단위입니다. 회원 표의 한 행이 회원 한 명이고, 한 열이 이름이나 가입일 같은 항목 하나입니다.
- 기본 키 — 행 하나를 딱 집어 가리키는 칸입니다. 이름은 같은 사람이 여럿일 수 있어 못 쓰고, 보통 겹치지 않는 번호를 따로 둡니다.
- 외래 키 — 다른 표의 행을 가리키는 칸입니다. 주문 표의 회원 번호 칸을 회원 표에 걸어 두면, 존재하지 않는 회원의 주문이 만들어지는 일을 데이터베이스가 막아 줍니다.
- 정규화 — 같은 사실이 두 군데 적히지 않도록 표를 쪼개는 설계입니다. 회사 이름을 주문 줄마다 적는 대신 회사 표에 한 번만 두고 번호로 가리킵니다. 회사가 이름을 바꾸면 한 줄만 고치면 끝납니다.
- 비정규화 — 속도를 위해 일부러 중복을 허용하는 설계입니다. 화면 하나에 표 여섯 개를 맞춰야 한다면 자주 쓰는 값 몇 개를 미리 한 표에 복사해 둡니다. 대신 원본이 바뀔 때 복사본도 같이 고쳐야 합니다.
성능은 같은 데이터에서 빠르기를 뽑아내는 갈래입니다. 인덱스는 책 뒤에 붙은 찾아보기와 같습니다. 본문을 처음부터 읽는 대신 색인에서 쪽수를 먼저 보는 것이고, 백만 줄을 훑던 질의가 몇 줄만 읽고 끝납니다. 공짜는 아닙니다. 색인도 공간을 먹고 새 줄이 들어올 때마다 같이 고쳐야 해서, 자주 찾는 칸에만 겁니다. N+1 문제는 반대쪽 대표입니다. 목록 100건을 가져온 뒤 건마다 상세를 다시 물어 질의가 101번 나가는 상황이고, 묶어 가져오면 2번으로 끝날 일입니다.
일관성은 값이 어중간한 상태로 남지 않게 지키는 갈래입니다. 트랜잭션은 여러 작업을 한 덩어리로 묶어 전부 성공하거나 전부 없던 일이 되게 만듭니다. 잔액에서 1만 원을 빼는 일과 결제 기록을 남기는 일을 한 묶음으로 걸어 두면, 둘 사이에서 서버가 죽어도 돈만 빠진 상태는 남지 않습니다. ACID 는 그 묶음이 지켜야 할 네 가지 성질에 붙은 이름입니다. 전부 아니면 전무인 원자성, 규칙에 어긋난 상태로 끝나지 않는 일관성, 다른 묶음에 끼어들지 않는 격리성, 끝났다고 답한 뒤에는 전원이 나가도 남는 지속성입니다.
운영은 살아서 돌아가는 동안을 돌보는 갈래이고 세 가지가 있습니다.
- 마이그레이션 — 표에 칸을 더하거나 이름을 바꾸는 것처럼 구조를 옮기는 작업입니다. 코드는 배포하면 예전 것이 사라지지만 데이터는 남아 있어서, 이미 쌓인 백만 줄을 새 구조로 옮기는 절차까지 함께 짜야 합니다.
- 복제 — 같은 데이터를 여러 서버에 복사해 두는 일입니다. 한 대가 죽어도 서비스가 이어지고, 읽기만 하는 요청을 복사본 쪽으로 보내 원본의 짐을 덜어 줍니다.
- 샤딩 — 데이터를 조각내 여러 서버에 나눠 담는 일입니다. 한 대에 다 안 들어갈 만큼 커졌을 때 쓰고, 대신 여러 조각에 걸친 질문에 답하기가 어려워집니다.
도구는 코드에서 데이터베이스를 다루는 방법을 맡는 갈래입니다. ORM은 코드의 객체와 표를 이어 주어, 질의문을 직접 쓰는 대신 코드에서 다루듯 읽고 씁니다. 손이 덜 가는 만큼 어떤 질의가 실제로 나가는지 눈에 보이지 않습니다. 앞에 나온 N+1 문제가 가장 자주 자라는 자리도 여기입니다.
보안은 누가 무엇까지 볼 수 있는지를 다루는 갈래입니다. 행 수준 보안은 표 전체가 아니라 행 하나하나에 권한을 겁니다. 같은 문서 표를 읽어도 A 회사 사람에게는 A 회사 문서만 보이도록 데이터베이스 쪽에서 걸러 주는 식입니다. 프로그램이 조건을 빠뜨려도 데이터베이스가 한 번 더 막아 줍니다.
여덟 갈래는 대개 이 순서로 찾아옵니다. 종류를 고르고 구조를 짜서 질의를 쓰는 동안은 조용하다가, 쓰는 사람이 늘면 성능이 부딪히고 돈이나 권한이 걸린 기능이 붙으면 일관성과 보안이 따라옵니다. 운영은 이미 돌아가는 중에 해야 해서 가장 조심스럽습니다.
실무 용례
"이거 데이터베이스에 넣을까요, 그냥 파일로 둘까요?"
나중에 조건을 걸어 찾거나 여러 사람이 동시에 고칠 일이 있는지 묻는 말입니다. 둘 다 아니면 파일이 싸게 먹힙니다.
"그 화면 느린 건 데이터베이스 쪽이에요. 질의 하나가 매번 전체를 훑고 있어요."
코드가 아니라 저장된 것을 꺼내는 방식이 병목이라는 진단입니다.
"이번 배포에 구조 변경이 있어서 마이그레이션 먼저 돌고 앱이 올라가야 해요."
순서가 바뀌면 새 코드가 아직 없는 칸을 찾다가 서비스가 멈춘다는 뜻입니다.
페이지덱에서 이 말이 가장 많이 오간 때는 문서 목록 화면이 8초씩 걸린다는 신고가 쏟아진 주입니다. 태오가 들여다보니 원인은 둘이었습니다. 목록 100건을 가져온 뒤 작성자 이름을 건마다 따로 물어서 질의가 101번 나갔고, 회사별로 거르는 칸에 색인이 없어 그 101번이 각각 전체를 훑었습니다.
고친 방법은 두 가지였습니다. 작성자 이름을 한 번에 묶어 가져오게 바꾸고, 회사 번호 칸에 색인을 걸었습니다. 8초가 0.3초가 됐습니다. 지현이 물은 것은 왜 이제야 드러났느냐였습니다. 무료 플랜 고객은 문서가 수십 건이라 느려도 티가 안 났고, 문서가 수만 건인 기업 고객이 붙은 뒤에야 보였습니다.
흔한 오해
데이터베이스를 데이터를 담아 두는 큰 상자로만 보는 경우가 가장 흔합니다. 행과 열이 있는 표에 값을 넣었다 뺐다 하는 모습이 스프레드시트와 닮아서 자연스러운 오해입니다. 실제로 값을 넣고 꺼내는 일은 데이터베이스가 하는 일 중 가장 쉬운 축에 듭니다. 어려운 쪽은 같은 줄을 동시에 고치려는 요청 수백 개의 순서를 세우고, 절반만 반영된 상태를 남기지 않고, 수천만 줄 중 조건에 맞는 한 줄을 전부 훑지 않고 집어내는 일입니다. 상자로만 보면 설계를 건너뛰게 됩니다. 필요할 때마다 칸을 붙이고 같은 사실을 여러 표에 적어 두다가, 고객이 늘어난 뒤에 어느 값이 맞는지 아무도 답하지 못하는 상태에 닿습니다. 그때는 표를 다시 짜고 쌓인 데이터를 옮기는 일을 서비스를 세우지 않은 채 해야 해서, 처음에 설계했으면 하루였을 일이 몇 주짜리가 됩니다.
느려지면 더 좋은 서버로 바꾸면 된다는 생각도 자주 봅니다. 사양을 올리면 실제로 잠시 빨라지니 확인까지 된 것처럼 느껴져 더 굳어집니다. 하지만 느린 질의의 대부분은 자원이 모자라서가 아니라 읽는 양이 잘못돼서 느립니다. 색인 없이 전체를 훑는 질의는 서버를 두 배로 키워도 두 배 빨라지는 데 그치지만, 색인을 걸면 읽는 줄이 수백 배로 줄어듭니다. 사양으로 미루면 원인이 그대로 남은 채 매달 나가는 돈만 늡니다. 데이터는 계속 쌓이므로 키운 사양도 언젠가 다시 모자라고, 그때는 고치기가 더 어려워져 있습니다.
자주 헷갈리는 용어
| 용어 | 무엇을 위한 저장소인가 | 데이터베이스와의 차이 |
|---|---|---|
| 데이터 웨어하우스 | 모아 놓고 분석해 판단을 내리기 위한 저장소 | 서비스가 지금 돌아가는 데 쓰는 기록을 맡지 않습니다. 여러 곳의 데이터를 한데 모아 지난 분기 추세 같은 질문에 답하는 자리라, 한 건을 빠르게 읽고 쓰는 대신 수억 건을 한꺼번에 훑는 쪽에 맞춰져 있습니다 |
같이 보면 좋은 페이지
- 엔지니어링
데이터 저장이 어느 자리에 놓인 갈래인지, 앞뒤로 무엇과 맞물리는지 봅니다
- 관계형 데이터베이스
네 종류 중 가장 먼저 만나게 될 것을 자세히 봅니다
- 데이터 웨어하우스
같은 데이터를 분석용으로 다시 모으면 무엇이 달라지는지 봅니다
하위 용어
마지막 업데이트 2026-09-16