사전 데이터 독립성
개념

데이터 독립성

gabury1고친 사람 github-actions[bot]

데이터 독립성은 데이터를 담는 방식이 바뀌어도 그 데이터를 쓰는 프로그램이 멀쩡하게 해 주는 성질입니다. 데이터베이스는 프로그램과 저장된 데이터 사이에 계층을 끼워 넣어 이 성질을 얻습니다. 무엇을 바꿔도 되느냐에 따라 물리적 독립성과 논리적 독립성으로 나뉩니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 데이터를 담는 방식을 바꿔도 프로그램 코드를 고치지 않게 해 줍니다. 회원 테이블에 검색용 인덱스를 새로 달아도 회원을 찾는 질의 문장은 한 글자도 안 바뀝니다.

왜 이렇게 하나 — 이 성질이 없으면 저장 방식을 바꿀 때마다 그 데이터를 읽는 프로그램을 전부 찾아 고쳐야 합니다. 프로그램이 많을수록 저장 방식에 손대기가 어려워집니다.

어떻게 도나

  1. 프로그램은 데이터를 테이블 이름과 열 이름으로만 부릅니다
  2. 데이터베이스가 그 이름을 디스크 위의 파일과 인덱스로 옮겨 찾습니다
  3. 저장 방식이 바뀌면 데이터베이스가 이 옮기는 규칙만 고칩니다. 프로그램 코드는 그대로입니다
  4. 테이블 구조를 바꿀 때는 뷰로 옛 모양을 남겨 둡니다. 뷰는 질의 하나에 이름을 붙여 테이블처럼 부르게 한 것입니다

대가 — 저장 방식은 코드에 안 드러납니다. 그래서 질의가 왜 느려졌는지 코드만 보고는 알 수 없습니다. 옛 모양을 흉내 낸 뷰는 테이블 하나처럼 보여도 여러 테이블을 잇는 비용을 치릅니다. 이런 뷰에는 새 행을 넣지 못할 때도 있습니다.

상세

상세는 비유 하나로 시작합니다. 이어서 저장 방식에 묶인 프로그램, 세 계층 구조, 두 종류의 독립성과 그 질의 예제, 대가와 이 성질을 스스로 깨는 코드 순서로 봅니다.

벽 콘센트에 플러그를 꽂는 사람은 벽 속 전선이 어느 길로 지나는지 모릅니다. 전기 기사가 벽을 뜯고 배선을 새로 깔아도 콘센트 구멍 모양이 같으면 전자제품은 아무 일 없이 돌아갑니다.

데이터 독립성은 데이터를 저장하는 방식이나 데이터의 전체 구조를 바꿔도 그 데이터를 쓰는 프로그램을 고치지 않아도 되는 성질입니다. 회원 테이블에 인덱스를 새로 달아도 회원을 찾는 질의가 한 글자도 안 바뀌는 것이 이 성질 덕분입니다. 이 글에서 프로그램은 데이터베이스에 질의를 보내는 애플리케이션 코드를 말합니다.

저장 방식에 묶인 프로그램

데이터베이스가 따로 없던 때에는 프로그램이 파일을 직접 읽었습니다. 프로그램 안에 레코드 하나가 몇 바이트인지, 이름 칸이 몇 번째 바이트부터 시작하는지가 적혀 있었습니다. 레코드가 파일 안에 어떤 순서로 놓였는지도 프로그램이 알고 있었습니다.

이런 프로그램은 저장 방식이 바뀌면 같이 깨집니다. 이름 칸을 20바이트에서 30바이트로 늘리면 그 파일을 읽는 프로그램을 모두 고쳐 다시 빌드해야 합니다. 빨리 찾으려고 레코드를 다른 순서로 다시 늘어놓아도 마찬가지입니다.

이 묶임을 끊자는 목표가 데이터 독립성입니다. 관계형 모델을 제안한 Codd도 이 성질을 새 모델의 주된 목표로 내걸었습니다.

데이터를 세 계층으로 나눠 보는 구조

이 소절은 데이터베이스가 프로그램과 디스크 사이에 무엇을 끼워 넣는지 봅니다. 계층 셋을 표로 먼저 가릅니다. 계층 사이를 잇는 규칙은 그림으로 봅니다.

스키마는 데이터가 어떤 모양이어야 하는지 미리 적어 둔 정의입니다. 어떤 테이블이 있고 그 테이블에 어떤 열이 있는지가 스키마에 적힙니다. 데이터베이스는 같은 데이터를 세 가지 스키마로 나눠 적습니다. 이 나눔을 3단계 스키마 구조라고 부릅니다.

계층 무엇을 적나 누가 보나 예
외부 스키마 프로그램 하나가 보는 데이터의 모양 각 프로그램 정산 프로그램이 보는 주문 금액 합계
개념 스키마 데이터 전체의 논리 구조 데이터베이스 설계자 users · orders 테이블과 그 열
내부 스키마 디스크에 저장하는 방법 데이터베이스 소프트웨어 파일 배치 · 인덱스 · 행의 저장 순서

위 계층일수록 프로그램에 가깝습니다. 아래 계층일수록 디스크에 가깝습니다. 주문 프로그램과 정산 프로그램은 같은 데이터를 서로 다른 외부 스키마로 봅니다.

외부 스키마는 흔히 뷰로 만듭니다. 뷰는 질의 하나에 이름을 붙여 테이블처럼 부를 수 있게 한 것입니다. 표의 「주문 금액 합계」도 orders 의 금액을 더하는 질의에 이름을 붙인 뷰입니다.

외부 스키마를 따로 만들지 않는 프로그램도 많습니다. 그런 프로그램은 개념 스키마의 테이블을 그대로 봅니다. 이때는 개념 스키마의 테이블이 곧 그 프로그램의 외부 스키마입니다.

계층과 계층 사이에는 매핑이 있습니다. 매핑은 위 계층의 이름과 모양을 아래 계층의 것으로 옮기는 대응 규칙입니다. 프로그램이 users 테이블의 email 열을 달라고 하면 데이터베이스가 매핑을 따라 그 값이 든 파일과 위치를 찾아냅니다.

flowchart TD
    P1["주문 프로그램"] --> E1["외부 스키마 · 주문용"]
    P2["정산 프로그램"] --> E2["외부 스키마 · 정산용"]
    E1 -->|외부-개념 매핑| C["개념 스키마 · 테이블과 열"]
    E2 -->|외부-개념 매핑| C
    C -->|개념-내부 매핑| I["내부 스키마 · 파일과 인덱스"]

두 매핑이 두 종류의 독립성을 만듭니다. 내부 스키마가 바뀌면 개념-내부 매핑만 고칩니다. 개념 스키마가 바뀌면 외부-개념 매핑만 고칩니다. 어느 쪽이든 프로그램에서 내려오는 화살표는 손대지 않습니다.

물리적 데이터 독립성

물리적 데이터 독립성은 내부 스키마를 바꿔도 개념 스키마와 프로그램이 안 바뀌는 성질입니다. 줄여서 물리적 독립성이라고 부릅니다. 이 계층에서 일어나는 변경은 이런 것들입니다.

  • 인덱스를 새로 만들거나 지웁니다
  • 큰 테이블을 여러 조각으로 나눠 담습니다. 이 작업을 파티셔닝이라고 부릅니다
  • 데이터 파일을 다른 디스크로 옮깁니다

아래 SQL(Structured Query Language, 구조화 질의 언어) 예제는 인덱스를 만들기 전과 뒤에 같은 질의를 보냅니다. 이 프로그램은 뷰를 거치지 않고 테이블 users 를 그대로 부릅니다. 오른쪽 주석이 돌려받는 값입니다.

SQL
-- 인덱스를 만들기 전
SELECT name FROM users
 WHERE email = '[email protected]';  -- 'Kim'

CREATE INDEX users_email_idx
    ON users (email);

-- 인덱스를 만든 뒤
SELECT name FROM users
 WHERE email = '[email protected]';  -- 'Kim'

두 질의는 글자가 같고 결과도 'Kim' 으로 같습니다. 달라진 것은 데이터베이스가 행을 찾는 방법입니다. 인덱스가 없을 때는 테이블의 행을 처음부터 끝까지 훑습니다. 인덱스가 생기면 인덱스를 따라 그 행으로 곧장 갑니다.

이게 되는 까닭은 SQL 이 무엇을 달라고만 적기 때문입니다. 어떻게 찾으라고는 적지 않습니다. 이렇게 원하는 결과만 적는 방식을 선언형이라고 부릅니다.

어떻게 찾을지는 질의 옵티마이저가 정합니다. 질의 옵티마이저는 질의가 올 때마다 지금 있는 인덱스와 테이블 크기를 보고 찾는 방법을 고르는 데이터베이스의 부품입니다. 인덱스가 생기면 옵티마이저가 다음 질의부터 다른 방법을 고릅니다.

논리적 데이터 독립성

논리적 데이터 독립성은 개념 스키마를 바꿔도 프로그램이 안 바뀌는 성질입니다. 줄여서 논리적 독립성이라고 부릅니다. 테이블에 열을 더하거나 테이블 하나를 둘로 나누는 일이 이 계층의 변경입니다. 이때 프로그램이 보던 옛 모양은 외부 스키마가 붙잡아 둡니다.

옛 모양을 붙잡아 두는 도구가 앞에서 본 뷰입니다. 뷰에는 데이터가 따로 저장되지 않습니다. 뷰를 읽을 때마다 그 질의가 돌아 결과를 만듭니다.

회원 테이블 users 를 둘로 나누는 경우를 봅니다. id · name · email 은 user_core 테이블로, 자기소개 bio 는 user_profile 테이블로 옮깁니다. 그리고 옛 이름 users 로 두 테이블을 이어 붙이는 뷰를 만듭니다.

SQL
CREATE VIEW users AS
SELECT c.id, c.name, c.email, p.bio
  FROM user_core c
  JOIN user_profile p ON p.user_id = c.id;

-- 나누기 전부터 쓰던 질의
SELECT name, bio FROM users
 WHERE id = 7;  -- 'Kim', '백엔드'

마지막 질의는 테이블을 나누기 전에 쓰던 문장과 같습니다. 프로그램 쪽에서는 users 가 테이블인지 뷰인지 구별되지 않습니다. 두 테이블을 잇는 일은 뷰 안의 조인이 맡습니다. 조인은 두 테이블의 행을 같은 값끼리 짝지어 한 행으로 잇는 연산입니다.

논리적 독립성은 물리적 독립성보다 지키기 어렵습니다. 저장 방식이 바뀌어도 테이블과 열에 든 값은 그대로입니다. 개념 스키마가 바뀌면 프로그램이 읽던 값이 사라질 때가 있습니다. 프로그램이 읽던 열을 지우면 어떤 뷰로도 그 값을 되살릴 수 없습니다.

이 성질이 쓸모를 보이는 때는 테이블 구조를 바꾸는 작업입니다. 이 작업을 스키마 마이그레이션이라고 부릅니다. 뷰로 옛 모양을 남겨 두면 그 테이블을 읽는 프로그램을 한꺼번에 바꾸지 않고 하나씩 옮길 수 있습니다.

계층을 두는 대가

계층을 끼워 넣으면 비용이 셋 생깁니다. 셋 다 프로그램이 아래 계층을 보지 않는다는 데서 나옵니다.

첫째는 숨은 비용입니다. 뷰 안에 조인이 들어 있으면 프로그램은 테이블 하나를 읽는다고 믿습니다. 하지만 실제로는 조인 비용을 치릅니다. 질의 문장만 봐서는 그 비용이 안 보입니다.

둘째는 성능 변화가 코드에 안 남는다는 것입니다. 누가 인덱스를 지우면 같은 질의가 갑자기 오래 걸립니다. 프로그램 코드는 한 줄도 안 바뀌었습니다. 코드 이력만 봐서는 원인이 안 나옵니다.

그래서 느려진 질의는 실행 계획을 열어 봅니다. 실행 계획은 옵티마이저가 그 질의에 고른 찾는 방법입니다. 인덱스를 따라가는지, 테이블을 처음부터 끝까지 훑는지가 여기에 드러납니다.

셋째는 뷰로 흉내 낸 옛 모양에 쓰기가 막힐 수 있다는 것입니다. 여러 테이블을 조인한 뷰에 새 행을 넣으면 데이터베이스는 어느 테이블에 무엇을 넣을지 정하지 못합니다. 그래서 이런 뷰에는 쓰기를 막거나 쓰는 규칙을 따로 적게 합니다.

독립성을 스스로 깨는 코드

데이터베이스가 계층을 나눠 줘도 프로그램이 아래 계층에 기대면 독립성이 깨집니다. 백엔드 코드에서 흔한 모양은 둘입니다.

첫째는 모든 열을 받는 SELECT * 입니다. 개념 스키마에 열이 늘면 결과의 모양도 따라 바뀝니다. 열을 순서 번호로 꺼내는 코드는 새 열이 끼면 엉뚱한 값을 읽습니다. 쓰는 열을 이름으로 적으면 열이 늘어도 결과가 안 바뀝니다.

둘째는 정렬 조건 ORDER BY 없이 행 순서에 기대는 코드입니다. 순서를 적지 않은 질의의 결과 순서는 저장 방식이 정합니다. 인덱스가 생기거나 행이 다른 순서로 다시 저장되면 결과 순서가 바뀔 수 있습니다. 순서가 필요하면 질의에 적어야 저장 방식과 떨어집니다.

코드 설계와 같은 원리

이 성질은 백엔드 개발자가 코드에서 늘 쓰는 원리와 뿌리가 같습니다. 클래스의 공개 메서드는 두고 안쪽 구현만 바꾸는 일을 캡슐화라고 부릅니다.

외부 스키마가 공개된 인터페이스입니다. 개념 스키마는 인터페이스 바로 밑의 구현입니다. 내부 스키마는 가장 안쪽의 구현입니다. 부르는 쪽이 인터페이스에만 기대면 구현을 바꿔도 부르는 쪽이 안 깨집니다.

앞 소절의 두 코드는 쓰는 것보다 더 많은 것에 기댄 코드입니다. SELECT * 는 개념 스키마의 열 목록 전체에 기댑니다. 그래서 열이 늘어나는 개념 스키마 변경에 깨집니다.

순서에 기대는 코드는 내부 스키마의 저장 순서에 기댑니다. 그래서 인덱스가 생기거나 행이 다시 저장되는 내부 스키마 변경에 깨집니다.

관련 항목

데이터 독립성을 이루는 계층과 종류

3단계 스키마 구조 · 외부 스키마 · 개념 스키마 · 내부 스키마 · 물리적 데이터 독립성 · 논리적 데이터 독립성

데이터 독립성을 떠받치는 데이터베이스 장치

뷰 · 조인 · 질의 옵티마이저 · 실행 계획 · SQL · 선언형 프로그래밍 · 시스템 카탈로그

프로그램 모르게 갈아 끼우는 저장 구조

인덱스 · B-tree · 해시 인덱스 · 클러스터형 인덱스 · 파티셔닝 · 파일 시스템

데이터 독립성을 시험하는 스키마 변경

스키마 마이그레이션 · 하위 호환 · 정규화 · 비정규화

스키마에 적히는 데이터 구성 요소

스키마 · 테이블 · 열 · 행

데이터 독립성을 목표로 내건 모델과 제안자

데이터베이스 · 관계형 모델 · 관계형 데이터베이스 · Codd

데이터 독립성 이전의 저장 방식

파일 처리 시스템 · 계층형 데이터베이스 · 네트워크형 데이터베이스

코드 설계에서 같은 원리를 가리키는 개념

캡슐화 · 인터페이스 · 추상화 · 정보 은닉 · 결합도

다른 이름: data independence · 데이터 독립