본문 바로가기

Web/DB

[SQL] 정규화(Normalization)

728x90

SQL 정규화(Normalization)는 데이터베이스 설계에서 중복을 최소화하고 데이터를 일관되게 저장하기 위해 수행되는 과정이다.

이를 통해 데이터의 무결성, 일관성, 유지보수성 등을 개선할 수 있다.

 

정규화는 일반적으로 제1정규형부터 제3정규형까지 적용된다.

  1. 제1정규형(1NF) : 각 열이 원자값(Atomic Value)을 가져야 한다. 즉, 각 열에는 중복된 값이 없어야 한다.
  2. 제2정규형(2NF) : 부분 함수 종속을 제거하기 위해 적용된다. 부분 함수 종속이란, 기본키 일부분만으로는 유일하게 특정되지 않는 경우를 말하며, 이를 해결하기 위해서는 기본키가 아닌 속성들을 새로운 테이블로 분리해야 한다.
  3. 제3정규형(3NF) : 이행 함수 종속을 제거하기 위해 적용된다. 이행 함수 종속이란, A가 B에 종속되고, B가 C에 종속될 때, A가 C에 종속되는 것을 말한다. 이를 해결하기 위해서는 중간에 있는 B를 새로운 테이블로 분리해야 한다.

정규화는 불필요한 데이터의 중복을 제거하여 데이터베이스의 용량을 최소화하고 데이터를 일관성 있게 관리할 수 있게 해주지만, 과도한 정규화는 성능 저하를 초래할 수 있다. 따라서 정규화 수준을 적절히 선택하는 것이 중요하다.

 

 

1NF (First Normal Form)

  • 모든 테이블의 각 컬럼 값은 원자값(Atomic)을 갖는다.

2NF (Second Normal Form)

  • 테이블의 모든 컬럼이 기본 키에 대해 완전 함수적 종속(Fully functional dependency)을 갖는다.

3NF (Third Normal Form)

  • 테이블의 모든 컬럼이 기본 키에 대해 이행적 종속(Transitive dependency)을 갖지 않는다.

이와 같이 정규화를 통해 데이터 중복과 이상 현상(anomalies)을 줄이고 데이터 일관성과 정확성을 유지할 수 있다.

 

 

 

 

 

 

  • 1NF(First Normal Form)

1NF는 각 컬럼의 원자성(Atomicity)을 보장한다. 이는 하나의 컬럼에 여러 개의 값을 저장하지 않도록 해야한다.

예시) 아래와 같은 테이블은 1NF를 만족하지 않는다.

 

Student ID Course IDs
1 C001, C002
2 C002, C003, C004
3 C001

 

 

 

1NF를 만족하는 예시

Student ID Course ID
1 C001
1 C002
2 C002
2 C003
2 C004
3 C001

 

  • 2NF(Second Normal Form)

2NF는 1NF를 만족하면서 부분적 종속(Partial Dependency)을 제거한다.

이는 하나의 테이블에서 키가 아닌 컬럼이 다른 컬럼에 종속되지 않도록 해야한다.

예시) 아래와 같은 테이블은 2NF를 만족하지 않는다.

Order IDProduct NameProduct Price
001 001 Apple 1.0
001 002 Banana 1.5
002 001 Apple 1.0
002 002 Banana 1.5
002 003 Orange 2.0

 

2NF를 만족하는 예시

Order IDProduct IDQuantity
001 001 10
001 002 5
002 001 20
002 002 10
002 003 15

 

  • 3NF(Third Normal Form)

3NF는 2NF를 만족하면서 이행적 종속(Transitive Dependency)을 제거한다.

이는 하나의 컬럼이 다른 컬럼에 종속되는 것이 아닌, 다른 컬럼을 통해 간접적으로 종속되지 않도록 해야한다.

예시) 아래와 같은 테이블은 3NF를 만족하지 않는다.

Employee DepartmentID Manager
001 Sales John
002 HR Peter
003 Sales John
004 IT Mike

3NF 만족하는 예시

 

Employees 테이블

EmployeeID DepartmentID ManagerID
001 1 2
002 2 3
003 1 2
004 3 null

Departments 테이블

DepartmentID DepartmentName
1 Sales
2 HR
3 IT

Managers 테이블

ManagerID ManagerName
2 John
3 Peter
null null

위의 테이블에서 Employees 테이블의 Department ID와 Managers 테이블의 Manager ID는 각각 Departments와 Managers 테이블의 Primary key를 참조하는 외래키이다.

이를 통해 중복된 데이터를 없애고 데이터 일관성을 유지할 수 있다.

 

 

 

SQL 정규형과 Spring Entity 사이에는 일대일 대응은 없지만, SQL 정규형을 준수하는 테이블 설계를 기반으로 Spring Entity 클래스를 작성할 수 있다.

 

 

@Entity
@Table(name = "employee")
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "employee_id")
    private Long employeeId;
    
    @Column(name = "employee_name")
    private String employeeName;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    
    // getter, setter, constructor, etc.
}


@Entity
@Table(name = "department")
public class Department {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "department_id")
    private Long departmentId;
    
    @Column(name = "department_name")
    private String departmentName;
    
    // getter, setter, constructor, etc.
}


@Entity
@Table(name = "manager")
public class Manager {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "manager_id")
    private Long managerId;
    
    @Column(name = "manager_name")
    private String managerName;
    
    // getter, setter, constructor, etc.
}

 

Employee 테이블과 Department 테이블은 다대일(N:1) 관계이므로,

Employee 클래스에서 Department 필드를 선언하고,

ManyToOne 어노테이션을 사용하여 관계를 설정.

또한 JoinColumn 어노테이션을 사용하여 Department 테이블의 foreign key인 department_id 컬럼과 매핑

 

Manager 테이블은 Employee 테이블과 일대다(1:N) 관계이므로,

Manager 클래스에서 List<Employee> 필드를 선언하고,

OneToMany 어노테이션을 사용하여 관계를 설정

또한 JoinColumn 어노테이션을 사용하여 Employee 테이블의 foreign key인 manager_id 컬럼과 매핑

 

 

위 코드는 3NF를 만족시키기 위한 예시로, 하나의 테이블을 세 개의 테이블로 분리하는 과정을 보여준다.

 

첫 번째 테이블인 "employee" 테이블은 사원 정보를 담고 있다.

각각의 사원은 unique한 ID를 갖고 있으며, 부서 ID와 매니저 ID를 갖는다.

부서 ID와 매니저 ID는 다른 테이블에서 참조하는 foreign key이다.

 

두 번째 테이블인 "department" 테이블은 부서 정보를 담고 있다. 각각의 부서는 unique한 ID를 갖는다.

부서 이름을 저장하는 column이다.

 

세 번째 테이블인 "manager" 테이블은 매니저 정보를 담고 있다.

각각의 매니저는 unique한 ID를 갖고 있으며, 매니저 이름을 저장하는 column이 있다.

 

각 테이블은 Spring Framework의 JPA 어노테이션을 이용하여 Entity로 구현되었다.

이를 이용하여 데이터베이스와의 연동이 가능하며, 각각의 Entity는 다른 Entity와 관계를 가지고 있다.

728x90