* 프로그래머스, 타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js) 5기 강의 수강 내용을 정리하는 포스팅.
* 원활한 내용 이해를 위해 수업에서 제시된 자료 이외에, 개인적으로 조사한 자료 등을 덧붙이고 있음.
이전 포스팅, 데이터베이스 참조.
이전 포스팅, MariaDB 참조.
데이터가 표로 관리되어 데이터를 직관적으로 조회할 수 있고, 테이블 사이의 관계를 명확하게 정의할 수 있다.
사용자가 데이터를 이해하기 쉽고, SQL을 통해 복잡한 DB를 제어하는 것도 간편하다.
대규모 데이터를 처리하거나 새로운 테이블을 추가하는 등의 확장도 용이.
특히 오랜 시간 동안 표준으로 자리 잡아 다양한 도구와 라이브러리, 커뮤니티 지원이 활발하다.
1NF (제 1 정규형): 각 컬럼이 원자값(더 이상 나눌 수 없는 값)을 가져야 함
2NF (제 2 정규형): 부분적 종속성 제거 (모든 컬럼이 기본키에 완전히 종속)
3NF (제 3 정규형): 이행적 종속성 제거 (기본키가 아닌 다른 컬럼에 종속된 컬럼 제거)
데이터베이스의 크기가 커질수록, 데이터의 CRUD 효율성은 점차 감소하게 된다.
모든 데이터가 하나의 테이블에 모여있으니, 컬럼 하나를 추가하고 수정하고 삭제하는데 다른 수많은 컬럼들까지 신경써주어야 한다.
그렇기에 테이블은 적절한 기준에 따라서 체계적으로 분리되어야 한다.
CREATE TABLE customer_orders (
customer_id INT,
customer_name VARCHAR(50),
email VARCHAR(100),
order_id INT,
order_date DATE,
product_name VARCHAR(100),
quantity INT
);
한 고객이 여러 번 주문하면, customer_name과 email 같은 정보가 반복적으로 저장된다.
이런 상황에서 데이터를 수정해야 한다면? 중복된 모든 데이터들을 다 업데이트해주어야 한다.
-- 고객 테이블
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(50),
email VARCHAR(100)
);
-- 주문 테이블
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
product_name VARCHAR(100),
quantity INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
그런데, 테이블을 이렇게 분리해주면?
고객 정보는 customers 테이블에 한 번만 저장되고, 주문 정보를 추가해도 customer_name과 email이 중복되지 않는다.
SELECT c.customer_name, o.product_name
FROM customers c
INNER JOIN orders o
ON c.customer_id = o.customer_id;
분리된 테이블을 사용할 경우, 데이터를 조회하려면 여러 테이블을 조인(Join)해주어야 한다.
테이블이 많아질수록 쿼리가 복잡해지고 성능이 저하될 수밖에 없다는 것.
SELECT c.customer_name, o.product_name, p.payment_status
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN payments p ON o.order_id = p.order_id;
INSERT INTO customers (customer_id, customer_name, email)
VALUES (2, 'Jane Smith', 'jane@example.com');
INSERT INTO orders (order_id, customer_id, order_date, product_name, quantity)
VALUES (102, 2, '2024-11-02', 'Smartphone', 2);
데이터베이스의 테이블들을 설계할 때, 각 테이블들이 서로 어떤 관계에 놓여있는지 유형을 올바르게 설계할 필요가 있다.
관계의 유형을 올바르게 설계하면 데이터베이스의 효율성과 무결성이 높아지기 때문.
이를 경시할 경우, 다음과 같은 문제가 생길 가능성이 높아진다.
- 동일한 데이터가 여러 테이블에 중복 저장.
- 데이터 간의 논리적 관계가 없음.
(고객 데이터가 삭제되었지만, 해당 고객의 주문 데이터가 남아있네?)
- 데이터 검색 및 조작 시 비효율적인 쿼리가 발생.
- 새로운 요구사항에 유연하게 대처하지 못함.
(테이블 하나를 추가해야하는데, 이전에 구현한 다른 테이블 구조를 모조리 뜯어고쳐야한다고?)
- 삽입, 삭제, 수정 작업에서 이상(Anomalies)이 발생할 수 있다.
(테이터 하나를 추가해야하는데, 쓰지도 않을 더미 데이터를 넣어주어야 한다 / 데이터를 하나 지우는데, 다른 데이터까지 같이 지워진다 / 중복되어있는 모든 데이터를 수정해야하는데, 일부 데이터가 수정이 누락된다.)
CREATE TABLE users (
user_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE user_details (
user_id INT PRIMARY KEY,
address VARCHAR(100),
phone VARCHAR(20),
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
사용자 (user_id) → 사용자 상세정보 (user_id)
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
고객 (customer_id) → 주문 (customer_id)
CREATE TABLE students (
student_id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE courses (
course_id INT PRIMARY KEY,
course_name VARCHAR(100)
);
CREATE TABLE student_courses (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
학생 (student_id) ↔ 강의 (course_id)