엑셀 한 장으로는 안 되는 이유
만화방을 운영한다고 해 보자. 회원 명부가 필요하고, 보유한 만화책 목록이 필요하고, 누가 언제 무엇을 빌려 갔다 반납했는지 기록이 필요하다.
이걸 엑셀 한 장에 다 넣을 수 있을까. 억지로는 가능하겠지만 곧 못 쓰게 된다. 왼쪽 구역은 회원, 가운데는 책, 아래쪽 몇 번째 줄부터는 대출 기록 같은 식으로는 관리가 안 된다.
그래서 시트를 나눈다. 회원은 회원 시트에, 책은 책 시트에, 대출 기록은 또 다른 시트에 둔다. 그리고 서로를 연결한다. 이 회원이 이 책을 빌렸다는 사실은 두 시트를 잇는 형태로 적힌다.
관계형 데이터베이스가 정확히 이 모양이다. 이름의 관계라는 말이 바로 이 연결을 가리킨다.
테이블·행·열, 그리고 키
표 하나를 테이블이라고 한다. 엑셀의 시트 한 장에 해당한다.
맨 윗줄에는 열 이름이 들어간다. 아이디, 이름, 연락처 같은 것들이다. 그 아래는 한 줄에 하나씩 데이터가 쌓인다. 회원 한 명이 한 줄, 책 한 권이 한 줄이다.
이제 연결이다. 회원 표에서 어떤 회원의 아이디가 1이라고 하자. 대출 기록 표에 회원 아이디를 적는 열을 두고 거기에 1을 적으면, 그 대출 기록이 이 회원의 것이라는 사실이 표현된다. 이렇게 다른 표를 가리키는 값을 외래 키라고 한다.
그리고 각 줄을 유일하게 가리키는 값이 필요하다. 회원 표의 아이디처럼 겹치지 않는 값이다. 이걸 기본 키라고 한다. 외래 키는 결국 다른 표의 기본 키를 가리킨다.
members books loans
───────────── ───────────── ──────────────────────
id name id title id member_id book_id
1 김민수 7 슬램덩크 1권 1 1 7
2 이서연 8 슬램덩크 2권 2 1 8
3 2 7
loans.member_id 는 members.id 를 가리키는 외래 키
loans.book_id 는 books.id 를 가리키는 외래 키스키마는 뻣뻣한 대신 안정적이다

표의 생김새를 스키마라고 한다. 어떤 열이 있는지, 각 열에 어떤 형태의 값이 들어갈 수 있는지를 미리 정해 두는 것이다.
정하는 것이 꽤 세밀하다. 이 열은 숫자만, 저 열은 글자 몇 자까지, 이 값은 비어 있으면 안 되고, 저 값은 서로 겹치면 안 된다는 식이다.
뻣뻣하다. 나중에 열을 하나 추가하거나 형태를 바꾸려면 이미 쌓인 데이터를 손봐야 한다. 대신 안정적이다. 정해진 형태에 안 맞는 값은 애초에 들어가지 못한다.
그래서 어떤 표를 몇 개로 나누고 어떻게 이을지를 정하는 일 자체가 전문 영역이다. 서비스가 커지면 이 설계만 전담하는 사람을 둔다. 같은 데이터도 나누는 방식에 따라 나중에 감당할 수 있는 것과 없는 것이 갈린다.
쿼리, 그리고 관계형이 아닌 것들

데이터베이스에 무언가를 시키는 문장을 쿼리라고 한다. 값을 꺼내 오거나, 넣거나, 고치거나, 지우는 일을 이 문장으로 시킨다.
SQL이 이름에 붙은 제품들은 전부 이 문장을 쓴다. PostgreSQL도 그중 하나이고 바이브 코딩 프로젝트에서 자주 만난다. 문장 생김새는 대체로 비슷해서 하나를 익히면 다른 제품에서도 통한다.
요즘은 쿼리를 코드 안에 직접 쓰는 일이 줄었다. 중간에서 대신 만들어 주는 도구가 잘 갖춰져 있어서, 앞 편에서 본 백엔드 코드에 데이터의 모양만 정의해 두면 쿼리는 그쪽이 만든다.
관계형이 아닌 종류도 있다. 각 항목을 통째로 하나의 문서처럼 저장하는 문서형은 형태가 자주 바뀌는 데이터에 쓴다. 무엇과 무엇이 이어졌는지만 저장하는 그래프형도 있다. 다만 웹 서비스의 기본은 여전히 관계형이다. 다음 편에서는 이 표에 넣지 않는 것, 이미지와 영상을 어디에 두는지 본다.
SELECT title FROM books WHERE id = 7;
INSERT INTO loans (member_id, book_id) VALUES (1, 7);
UPDATE members SET name = '김민수' WHERE id = 1;
DELETE FROM loans WHERE id = 3;