Chapter 2. Introduction to the Relational Model

한 줄 핵심: 관계형 모델은 데이터를 테이블(릴레이션)의 집합으로 표현하고, 로 튜플을 식별·연결하며, 관계 대수라는 절차적 언어로 릴레이션을 입력받아 새 릴레이션을 만들어 질의한다.

이 챕터가 답하는 핵심 질문

  • Q1. 관계형 모델은 데이터를 어떻게 구조화하는가?
  • Q2. 속성 값에는 어떤 제약이 있는가? (도메인·원자성·null)
  • Q3. 스키마와 인스턴스, 그리고 튜플의 순서는?
  • Q4. 튜플을 식별하고 릴레이션을 연결하는 키에는 어떤 종류가 있는가?
  • Q5. 스키마 다이어그램은 무엇을 보여주는가?
  • Q6. 관계 대수란 무엇이고 왜 “절차적” 언어인가?
  • Q7. 6개 기본 연산자는 각각 무엇을 하는가?
  • Q8. 기본 연산 외에 자주 쓰는 추가 연산은? (∩, ⋈, ←)
  • Q9. 같은 결과를 내는 쿼리가 여러 개일 수 있는가? (동치 쿼리)

Q1. 관계형 모델은 데이터를 어떻게 구조화하는가?

A. 데이터를 릴레이션(relation), 즉 테이블의 집합으로 표현한다.

기본 용어:

  • 릴레이션(Relation): 테이블. 행과 열로 구성.
  • 튜플(Tuple): 릴레이션의 한 행(row). 하나의 레코드.
  • 속성(Attribute): 릴레이션의 한 열(column). 각 속성은 이름을 가짐.
  • 릴레이션 스키마(Relation Schema): 릴레이션의 논리적 설계. R = (A₁, A₂, ..., Aₙ) 형태.
    • 예: instructor = (ID, name, dept_name, salary)
  • 릴레이션 인스턴스(Relation Instance): 스키마 R 위에 정의된 실제 데이터 r(R). 현재 값들이 테이블로 표현되며, 그 원소 t(튜플)가 한 행.

Q2. 속성 값에는 어떤 제약이 있는가? (도메인·원자성·null)

A. 각 속성은 허용 값의 집합인 도메인을 가지며, 값은 보통 **원자적(atomic)**이어야 하고, 특수 값 null이 존재한다.

  • 도메인(Domain): 각 속성에 허용되는 값의 집합.
  • 원자적(Atomic): 값은 더 이상 분할할 수 없어야 한다.
    • 예: 전화번호를 하나의 값으로 두면 원자적. 국가코드/지역코드/번호로 쪼개 부분 값으로 쓰면 위반.
  • null: “값을 모름(unknown)“을 나타내는 특수 값. 모든 도메인의 멤버다. 많은 연산의 정의를 복잡하게 만든다.

Q3. 스키마와 인스턴스, 그리고 튜플의 순서는?

A. 스키마는 논리적 구조(타입), **인스턴스는 특정 시점의 데이터 스냅샷(값)**이며, 튜플의 순서는 무의미하다.

  • 데이터베이스 스키마(Database Schema): 데이터베이스의 논리적 구조. (예: instructor(ID, name, dept_name, salary))
  • 데이터베이스 인스턴스(Database Instance): 특정 시점의 데이터 스냅샷(snapshot).
  • 비유: 스키마 = 변수의 타입, 인스턴스 = 변수의 .
  • 튜플의 순서는 무의미하다 (Relations are Unordered): 릴레이션은 튜플의 집합이므로 저장 순서는 임의적이며, 어떤 순서로 나열해도 같은 릴레이션이다.

Q4. 튜플을 식별하고 릴레이션을 연결하는 키에는 어떤 종류가 있는가?

A. 슈퍼키 ⊃ 후보키 ⊃ 기본키의 포함 관계로 튜플을 식별하고, 외래키로 다른 릴레이션을 참조한다.

K ⊆ R 일 때:

키 유형정의
슈퍼키 (Superkey)K 값으로 각 튜플을 유일하게 식별할 수 있으면 슈퍼키. {ID}도, {ID, name}도 슈퍼키.
후보키 (Candidate Key)최소(minimal) 슈퍼키. 어떤 진부분집합도 슈퍼키가 아닌 슈퍼키. 예: {ID}.
기본키 (Primary Key)후보키 중 DBA가 선택한 대표 키. 밑줄로 표시. 묶인 여러 밑줄은 함께 하나의 복합 기본키.
외래키 (Foreign Key)한 릴레이션의 값이 다른 릴레이션에 반드시 나타나야 하는 제약. 릴레이션 간 관계를 표현.

키 종류를 실제 데이터로 구분하기

instructor(ID, name, dept_name, salary) 테이블에서:

IDnamedept_namesalary
22222EinsteinPhysics95000
12121WuFinance90000
33456GoldPhysics87000
  • 슈퍼키: 행을 유일하게 구분만 하면 OK. {ID} ✅, {ID, name} ✅ (군더더기 name이 붙어도 여전히 유일하니 슈퍼키), {name} ✅ (지금은 이름이 안 겹치지만 동명이인이 생기면 깨지므로 보통 키로 안 씀).
  • 후보키: 슈퍼키 중 “한 글자도 못 빼는” 최소 조합. {ID}는 ID 하나만으로 유일 → 후보키. {ID, name}은 name을 빼도 유일하므로 최소가 아님 → 후보키 아님.
  • 기본키: 후보키 {ID}를 DBA가 대표로 지정 → ID처럼 밑줄.

직관: 슈퍼키는 “넉넉하게 구분되면 됨”, 후보키는 “더 못 줄일 만큼 딱 맞게”, 기본키는 “그중 공식 대표 하나”.

외래키 제약(Foreign Key Constraint): 참조하는 릴레이션(referencing relation)의 값이 참조되는 릴레이션(referenced relation)에 반드시 존재해야 한다.

  • 예: instructor의 dept_name은 department를 참조하는 외래키.
    • instructor(ID, name, dept_name, salary) — dept_name = 외래키
    • department(dept_name, building, budget) — dept_name = 기본키

외래키는 "유령 참조"를 막는다

department(dept_name 기본키)        instructor(dept_name 외래키)
┌───────────┐                      ┌───────┬──────────┬───────────┐
│ Physics   │  <───── 참조 ────────│ 22222 │ Einstein │ Physics   │ ✅
│ Finance   │  <───── 참조 ────────│ 12121 │ Wu       │ Finance   │ ✅
└───────────┘                      │ 99999 │ Lee      │ Magic     │ ❌
                                    └───────┴──────────┴───────────┘

“Magic”은 department에 없는 학과 → 외래키 제약이 이 행의 삽입을 거부한다. 덕분에 “존재하지 않는 학과 소속 교수” 같은 모순 데이터가 들어올 수 없다.

한 줄 정리

연결 고리가 되는 컬럼은 양쪽 테이블에 다 있어야 관계를 맺을 수 있지만, 외래키라는 제약조건은 참조하는(자식) 테이블에만 정의한다.


Q5. 스키마 다이어그램은 무엇을 보여주는가?

A. 데이터베이스의 논리적 구조를 시각화한다 — 각 릴레이션은 직사각형, 기본키는 밑줄, 외래키 관계는 화살표(참조 → 피참조).

대학 스키마의 주요 릴레이션:

department(dept_name, building, budget)
course(course_id, title, dept_name, credits)
instructor(ID, name, dept_name, salary)
section(course_id, sec_id, semester, year, building, room_number, time_slot_id)
teaches(ID, course_id, sec_id, semester, year)
student(ID, name, dept_name, tot_cred)
takes(ID, course_id, sec_id, semester, year, grade)
advisor(s_ID, i_ID)
prereq(course_id, prereq_id)
classroom(building, room_number, capacity)
time_slot(time_slot_id, day, start_hr, start_min, end_hr, end_min)

course 릴레이션 (샘플):

course_idtitledept_namecredits
BIO-101Intro. to BiologyBiology4
CS-101Intro. to Computer ScienceComp. Sci.4
CS-347Database System ConceptsComp. Sci.3
PHY-101Physical PrinciplesPhysics4

prereq 릴레이션 (선수과목, 샘플):

course_idprereq_id
BIO-301BIO-101
CS-347CS-101
EE-181PHY-101

Q6. 관계 대수란 무엇이고 왜 “절차적” 언어인가?

A. 관계 대수는 하나 또는 두 개의 릴레이션을 입력받아 새 릴레이션을 산출하는 연산들의 집합이며, “어떻게(How)” 연산을 순서대로 적용할지 지정하므로 절차적(procedural) 언어다.

6개 기본 연산자: select(σ), project(Π), union(∪), set difference(−), Cartesian product(×), rename(ρ).

절차적(Procedural) vs 선언적(Declarative)

  • 절차적(How): 결과를 얻기 위한 연산의 순서·절차를 지정. 관계 대수가 여기 속한다.
    • 예: “먼저 σ로 나이 ≥ 20인 행을 고르고, 그 결과에 Π로 이름만 추출하라.”
  • 선언적/비절차적(What): 원하는 결과의 **성질(조건)**만 정의, 방법은 시스템에 위임.
    • 관계 해석(Relational Calculus): 관계 대수의 짝. 무엇을 원하는지만 선언.
    • SQL: 대표적 선언적 언어. 인덱스를 쓸지 풀 스캔할지는 DBMS의 Optimizer가 결정.

핵심 성질 — 연산의 합성(Composition)

관계 대수 연산의 결과는 항상 릴레이션이므로 연산을 중첩(합성)할 수 있다.
예: Π_name(σ_{dept_name="Physics"}(instructor)) — 선택 결과(릴레이션)에 투영을 바로 적용.


Q7. 6개 기본 연산자는 각각 무엇을 하는가?

A. 행을 거르고(σ), 열을 뽑고(Π), 집합 연산(∪, −)을 하고, 두 릴레이션을 조합(×)하고, 이름을 바꾼다(ρ).

아래 예제에서 공통으로 쓸 샘플 데이터

instructor

IDnamedept_namesalary
10101SrinivasanComp. Sci.65000
22222EinsteinPhysics95000
33456GoldPhysics87000
12121WuFinance90000

직관 한 줄: σ는 “가로줄(행)을 자르는 가위”, Π는 “세로줄(열)을 자르는 가위”라고 외우면 헷갈리지 않는다.

       Π (열을 뽑음, 세로 ↓)
       │
  ─────┼────────────────  σ (행을 거름, 가로 →)
       │

Select — σ (행 선택)

조건(predicate)을 만족하는 **튜플(행)**만 선택.

σ_{조건}(릴레이션)
σ_{dept_name="Physics" ∧ salary>90000}(instructor)
  • 비교: =, ≠, >, ≥, <, ≤ / 논리: ∧(and), ∨(or), ¬(not)
  • 두 속성 간 비교도 가능: σ_{dept_name=building}(department)

σ 단계별 추적 — σ_{dept_name="Physics"}(instructor)

위 instructor의 4개 행을 한 줄씩 조건 검사:

10101 Srinivasan Comp.Sci. 65000  → Physics 아님   ✗ 버림
22222 Einstein   Physics   95000  → Physics 맞음   ✓ 남김
33456 Gold       Physics   87000  → Physics 맞음   ✓ 남김
12121 Wu         Finance   90000  → Physics 아님   ✗ 버림

결과 (열 구조는 그대로, 행만 줄어듦):

IDnamedept_namesalary
22222EinsteinPhysics95000
33456GoldPhysics87000

Project — Π (열 추출)

지정한 **속성(열)**만 남기고 나머지 열을 지운다. 결과의 중복 튜플은 자동 제거(릴레이션은 집합이므로).

Π_{ID, name, salary}(instructor)

Π가 중복을 제거하는 모습 — Π_{dept_name}(instructor)

dept_name 열만 뽑으면 Physics가 두 번 나오지만, 릴레이션은 집합이라 자동으로 1개만 남는다.

뽑힌 값:  Comp. Sci. / Physics / Physics / Finance
                                 └── 중복! 하나로 합쳐짐

결과:

dept_name
Comp. Sci.
Physics
Finance

σ와 Π의 합성 — Π_name(σ_{dept_name="Physics"}(instructor))

안쪽 σ로 Physics 행 2개를 고른 뒤, 그 결과(릴레이션)에 Π로 name만 뽑는다.

instructor ──σ_{Physics}──> [22222 Einstein …][33456 Gold …]
               ──Π_name──> ┌──────────┐
                           │ Einstein │
                           │ Gold     │
                           └──────────┘

핵심: σ의 결과가 다시 릴레이션이므로 Π를 곧바로 적용할 수 있다 (연산의 합성).

Union — ∪ (합집합)

두 릴레이션의 모든 튜플 합침. 중복 제거.

r ∪ s
  • 호환 조건: ① 같은 수의 속성(same arity), ② 대응 속성의 도메인 호환.
-- 2017 Fall 또는 2018 Spring에 개설된 과목
Π_{course_id}(σ_{semester="Fall" ∧ year=2017}(section))
  ∪ Π_{course_id}(σ_{semester="Spring" ∧ year=2018}(section))

∪ / − / ∩ 를 같은 데이터로 한눈에 비교

두 학기에 개설된 과목 집합이 아래와 같다고 하자.

Fall2017 = { CS-101, CS-347, PHY-101 }
Spring2018 = { CS-101, CS-315, FIN-201 }
                 └ 양쪽에 다 있는 건 CS-101 뿐
연산의미결과
∪ (합집합)둘 중 하나라도 개설CS-101, CS-347, PHY-101, CS-315, FIN-201
∩ (교집합)양쪽 모두 개설CS-101
− (차집합) Fall−SpringFall엔 있고 Spring엔 없는CS-347, PHY-101

직관: ∪=“둘을 합쳐 중복 제거”, ∩=“겹치는 부분만”, −=“내 것에서 상대 것을 뺀 나머지”. 벤다이어그램 그대로다.

Set Difference — − (차집합)

r에는 있지만 s에는 없는 튜플. 호환 조건은 union과 동일.

-- 2017 Fall에는 있고 2018 Spring에는 없는 과목
Π_{course_id}(σ_{...Fall,2017}(section)) − Π_{course_id}(σ_{...Spring,2018}(section))

Cartesian Product — × (카티션 곱)

두 릴레이션의 모든 튜플 쌍을 조합. 결과 속성은 양쪽 속성을 모두 포함하며, 공통 속성은 릴레이션 이름으로 구분(instructor.ID, teaches.ID).

instructor × teaches

왜 곱 결과 대부분이 무의미한가: instructor 5개 × teaches 13개 = 65개 튜플. 이 중 instructor.ID = teaches.ID를 만족하는 의미 있는 조합은 일부뿐. 나머지는 무관한 교수-강의 쌍. 따라서 거의 항상 σ 조건과 함께 쓴다.

× 를 작은 데이터로 직접 추적

instructor (2개) × teaches (2개) = 4개(2×2)의 모든 짝.

instructor                 teaches
┌───────┬──────────┐       ┌───────┬──────────┐
│ 22222 │ Einstein │       │ 22222 │ PHY-101  │
│ 12121 │ Wu       │       │ 12121 │ FIN-201  │
└───────┴──────────┘       └───────┴──────────┘

모든 쌍을 만들면:

instructor.IDnameteaches.IDcourse_id의미?
22222Einstein22222PHY-101✅ Einstein이 자기 과목
22222Einstein12121FIN-201❌ Einstein인데 Wu의 과목
12121Wu22222PHY-101❌ Wu인데 Einstein의 과목
12121Wu12121FIN-201✅ Wu가 자기 과목

직관: 곱은 “양쪽을 무지성으로 다 짝지은” 상태라 절반이 엉뚱하다. 그래서 instructor.ID = teaches.ID로 대각선(✅)만 남기는 게 핵심.

σ_{instructor.ID = teaches.ID}(instructor × teaches)

위 4개 중 ID가 같은 2개(✅)만 남는다 → 이것이 바로 다음 절의 조인이다.

Rename — ρ (재명명)

연산 결과 릴레이션에는 이름이 없으므로, 이름(또는 속성 이름)을 부여한다. SQL의 AS에 대응.

ρ_x(E)                  — 결과 E를 x로 명명
ρ_{x(A₁,A₂,...,Aₙ)}(E)  — 릴레이션 이름 x, 속성 이름도 모두 변경

Q8. 기본 연산 외에 자주 쓰는 추가 연산은? (∩, ⋈, ←)

A. 교집합(∩), 조인(⋈), 배정(←)은 편의를 위한 추가 연산이며, 기본 연산자로 표현 가능하다.

Set Intersection — ∩ (교집합)

r과 s 양쪽 모두에 있는 튜플. 호환 조건 동일.

r ∩ s = r − (r − s)
-- 2017 Fall과 2018 Spring 모두에 개설된 과목
Π_{course_id}(σ_{...Fall,2017}(section)) ∩ Π_{course_id}(σ_{...Spring,2018}(section))

Join — ⋈ (조인)

조인은 select + Cartesian product를 하나로 합친 연산이다. 카티션 곱에서 대부분 무의미한 행을 σ로 걸러내는 흔한 패턴을 한 연산으로 표현한다.

  • Theta Join: 조건 θ를 직접 명시.
    • 릴레이션 r(R), s(S)에 대해 θ는 스키마 R ∪ S 위의 술어(predicate).
    • 정의:
    • 예: σ_{instructor.ID = teaches.ID}(instructor × teaches) = instructor ⋈_{instructor.ID = teaches.ID} teaches

조인 = "곱 만들고 → 골라내기"를 한 번에

앞 Q7의 × 예제 결과(4행)에서 ID가 일치하는 행만 남기면 조인 결과가 된다.

instructor ⋈_{instructor.ID = teaches.ID} teaches

  ① 곱: 모든 짝 4개 생성  ──>  ② σ: ID 같은 행만 남김

결과:

IDnamecourse_id
22222EinsteinPHY-101
12121WuFIN-201

직관: 조인은 “두 표를 공통 열(ID)을 기준으로 자석처럼 딱 붙이는” 연산. 엑셀의 VLOOKUP, 인맥으로 치면 “이름이 같은 사람끼리 연결”하는 것과 같다. 실무 쿼리의 대부분이 조인이다.

Assignment — ← (배정)

중간 결과(릴레이션)에 임시 이름을 부여해 복잡한 쿼리를 순차 프로그램처럼 단계별로 작성. 프로그래밍의 대입과 같다.

Physics ← σ_{dept_name="Physics"}(instructor)
Music   ← σ_{dept_name="Music"}(instructor)
Physics ∪ Music

Q9. 같은 결과를 내는 쿼리가 여러 개일 수 있는가? (동치 쿼리)

A. 그렇다. 관계 대수에서는 한 쿼리를 여러 방식으로 쓸 수 있으며, 결과가 같으면 **동치(equivalent)**다. Query Optimizer가 그중 가장 효율적인 것을 고른다.

동치 = “동일하지는 않지만(not identical), 어떤 데이터베이스에서도 같은 결과를 준다.”

예시 1 — Physics이고 salary > 90,000인 교수:

-- Query 1: 조건을 한 번에
σ_{dept_name="Physics" ∧ salary>90000}(instructor)

-- Query 2: 선택을 중첩
σ_{dept_name="Physics"}(σ_{salary>90000}(instructor))

예시 2 — Physics 학과 교수가 가르치는 과목 정보 (조인 순서/선택 위치의 차이):

-- Query 1: 조인 후 선택
σ_{dept_name="Physics"}(instructor ⋈_{instructor.ID=teaches.ID} teaches)

-- Query 2: 선택 후 조인 (보통 더 효율적 — 먼저 걸러 데이터를 줄임)
(σ_{dept_name="Physics"}(instructor)) ⋈_{instructor.ID=teaches.ID} teaches

두 쿼리는 같은 결과를 내지만 실행 비용이 다를 수 있다.


부록. 관계 대수 연산자 요약

연산자기호유형설명
Selectσ단항조건을 만족하는 행 선택
ProjectΠ단항특정 열만 추출 (중복 제거)
Union이항합집합
Set Difference이항차집합
Cartesian Product×이항모든 튜플 쌍 조합
Renameρ단항이름 변경
Set Intersection이항교집합 (추가)
Join이항σ + × 결합 (추가)
Assignment중간 결과 명명 (추가)

출처: Database System Concepts, 7th Edition (Silberschatz, Korth, Sudarshan)