1. PK (Primary Key)전략이란??
Primary Key (PK)는 테이블 내에서 각 행을 유일하게 식별하는 데 사용되는 필드입니다. PK는 데이터베이스에서 데이터를 정확하게 조회하고, 수정하며, 삭제하는 데 매우 중요합니다. PK를 생성하는 방법에는 여러 가지가 있지만, 가장 흔한 두 가지는 AUTO_INCREMENT
와 UUID
입니다.
1.1 AUTO_INCREMENT란?
AUTO_INCREMENT
는 MySQL과 같은 데이터베이스에서 많이 사용되는 기본 키 생성 전략입니다. 데이터가 삽입될 때마다 숫자가 1씩 증가하여 자동으로 기본 키가 생성됩니다.
CREATE TABLE member (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
1) 특징
- 장점: 간단하고 메모리 효율적입니다. 단일 데이터베이스에서 성능이 뛰어납니다.
- 단점: 분산 시스템에서는 중복 키 발생 가능성, 키 예측 가능성 등의 문제점이 있습니다.
1.2 UUID (Universally Unique Identifier)란?
UUID (Universally Unique Identifier)
는 전 세계적으로 고유한 128비트(= 16바이트) 값을 생성하는 전략입니다. 분산 시스템에서 충돌 없이 고유한 값을 생성할 수 있기 때문에, 시스템 간 데이터 통합과 중복 키 문제를 해결하는 데 효과적입니다.
1) UUID의 구조
- 128비트 길이: 총 16바이트로 표현됩니다.
- 16진수 문자열 형식:
8-4-4-4-12
의 형태로 표시됩니다.
예시: 550e8400-e29b-41d4-a716-446655440000
2) UUID 버전
UUID에는 다양한 버전이 있습니다. 가장 흔히 사용되는 버전은 UUIDv4로, 무작위(random)로 값을 생성합니다.
- UUIDv1: 타임스탬프와 MAC 주소를 기반으로 생성.
- UUIDv4: 무작위로 생성되며, 보안성 및 고유성이 뛰어납니다.
2. AUTO_INCREMENT 전략의 문제점
2.1 분산 시스템에서의 문제
AUTO_INCREMENT
는 단일 데이터베이스 환경에서는 문제가 없지만, 분산 시스템에서는 여러 데이터베이스 노드 간에 중복 키(Duplicate Key)가 발생할 수 있습니다.
- 분산된 여러 데이터베이스 노드에서 동일한
AUTO_INCREMENT
값을 생성하면 키 충돌이 발생할 수 있습니다. - 이를 방지하기 위해 각 노드마다 다른 키 생성 규칙을 적용해야 하지만, 이는 복잡성과 유지 보수 비용을 증가시킵니다.
- 분산 시스템에서의 AUTO_INCREMENT 문제점 예시
데이터베이스 A와 B가 동시에 삽입을 처리할 때, 두 데이터베이스가 각각 동일한 키 값을 생성할 수 있습니다.
- A 데이터베이스: 1, 2, 3...
- B 데이터베이스: 1, 2, 3...
이는 중복 키 충돌을 일으켜 데이터 무결성을 위협합니다.
2.2 키 예측 가능성
AUTO_INCREMENT
는 순차적으로 키가 증가하므로 예측하기 매우 쉽습니다. 외부에서 기본 키를 추정할 수 있어 보안에 취약할 수 있습니다.
- 공격자는 URL 등의 경로에서 기본 키 패턴을 쉽게 예측할 수 있습니다.
- 이로 인해 SQL Injection과 같은 공격에 노출될 위험이 있습니다.
- 다른 사용자의 데이터에 접근할 가능성이 생깁니다.
2.3 성능상의 병목 가능성
AUTO_INCREMENT
는 단일 시퀀스를 사용하기 때문에, 병렬 처리 환경에서 동시다발적인 삽입 요청이 많아지면 성능 병목이 발생할 수 있습니다. 특히 많은 양의 트래픽이 몰리는 분산 환경에서는 이를 극복하기 어렵습니다.
3. UUID의 장점
UUID는 전 세계적으로 고유한 식별자를 생성할 수 있으며, 특히 분산 시스템에서 유용합니다.
3.1 전역 고유성 보장
UUID
는 128비트로 이루어져 있어 거의 중복되지 않는 값을 생성할 수 있습니다. 분산 시스템에서도 각 노드가 독립적으로 키를 생성할 수 있기 때문에 중복 키 문제가 발생하지 않습니다. 이를 통해 분산 환경에서 충돌 없는 데이터 식별이 가능합니다.
UUID
충돌 확률은 약 10^-38 의 확률로 매우 낮은 확률을 가지고 있습니다. 사실상 중복이 발생할 가능성은 무시할 수 있습니다. 1초에 UUID를 1000만개씩 만들어도 8925년동안 만들어야합니다.
3.2 키 예측 불가능성
UUID
는 랜덤하게 생성되므로 기본 키를 예측할 수 없습니다. 이는 보안 면에서 큰 이점이며, 공격자가 키 값을 추정하는 것을 막아 줍니다.
- 공격자가 UUID 기반의 PK를 예측하기는 사실상 불가능합니다.
- 이를 통해 SQL Injection과 같은 공격에 대한 방어를 할 수 있습니다.
3.3 분산 시스템에서 적합
UUID
는 여러 데이터베이스 노드나 서버가 동시에 데이터를 삽입해도 충돌을 방지할 수 있습니다. 분산 환경에서 데이터 일관성을 유지하는 데 매우 유용합니다.
4. UUID의 단점
UUID
는 성능과 메모리 측면에서 몇 가지 주의할 점이 있습니다.
4.1 성능 문제
UUID
는 128비트 크기이기 때문에, INT(32비트)나 BIGINT(64비트)에 비해 더 많은 메모리와 저장 공간을 차지합니다. 또한 UUID는 랜덤하게 생성되므로, 데이터 삽입 시 인덱스 정렬이 깨지기 때문에 성능이 저하될 수 있습니다.
- 인덱스가 순차적으로 정렬되지 않으면, B-Tree 구조에서 성능 저하가 발생할 수 있습니다.
- 특히 대규모 삽입 작업이 발생할 때 성능에 영향을 미칠 수 있습니다.
4.2 가독성 문제
UUID는 복잡한 16진수 문자열로 이루어져 있기 때문에 사람이 이해하고 기억하기 어렵습니다. 예를 들어, 550e8400-e29b-41d4-a716-446655440000
와 같은 문자열은 로그나 디버깅 시에 가독성이 떨어집니다.
VARCHAR(36)과 BINARY(16) 차이
- VARCHAR(36): UUID는 36자리의 문자열로 저장되며, 각 문자는 1바이트를 차지합니다. 즉, 36바이트가 필요합니다.
- BINARY(16): UUID를 바이너리 형식으로 저장하면 16바이트만 필요합니다. 이 방식은 공간 효율성이 뛰어납니다.
5. JPA에서 UUID 사용하기
JPA에서는 최신 Hibernate 버전에서 GenerationType.UUID
를 사용해 쉽게 UUID를 기본 키로 설정할 수 있습니다.
5.1 @Id
및 @GeneratedValue
설정
import jakarta.persistence.*;
import java.util.UUID;
@Entity
public class Member {
// Primary Key로 UUID 사용
@Id
@GeneratedValue(strategy = GenerationType.UUID) // UUID 전략 설정
@Column(columnDefinition = "BINARY(16)")
private UUID id; // UUID 타입
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String name;
// 기타 필드 및 메서드...
}
@Id
: 기본 키임을 나타냅니다.@GeneratedValue(strategy = GenerationType.UUID)
: Hibernate에서 UUID를 자동으로 생성하는 전략을 사용합니다.@Column(columnDefinition = "BINARY(16)")
: MySQL에서 UUID를 16바이트 바이너리 형식으로 저장하여 공간 절약 및 성능 최적화를 기대할 수 있습니다.
5.2 UUID와 BINARY(16) 사용의 장점
BINARY(16)
을 사용하면 VARCHAR(36)에 비해 메모리와 저장 공간을 절약할 수 있습니다.- UUID는 128비트이므로 이를 바이너리 형식으로 저장하면 16바이트가 필요합니다.
VARCHAR(36)
은 36문자열로, 비교적 더 많은 공간을 차지합니다.
6. 정리
특징 | AUTO_INCREMENT | UUID |
---|---|---|
고유성 | 단일 DB 환경에서만 보장됨 | 전역적으로 고유한 ID를 보장 |
보안성 | 키 예측이 가능해 보안에 취약함 | 랜덤 값으로 키 예측 불가능 |
메모리 사용 | INT(4바이트), BIGINT(8바이트)로 효율적 | UUID는 128비트(16바이트) |
분산 시스템에서 적합성 | 적합하지 않음 (중복 키 발생 가능성) | 분산 환경에서 적합 (중복 키 없음) |
가독성 | 키가 간단함 | UUID는 사람이 읽기 어려움 |
성능 | 단일 DB에서 삽입 성능이 뛰어남 | 인덱스 정렬이 랜덤해 성능 저하 가능성 |
- 단일 데이터베이스: 단일 DB 환경에서는 AUTO_INCREMENT 가 성능과 메모리 측면에서 더 유리합니다. |
||
- 분산 시스템: 분산 시스템에서 데이터 일관성과 보안성을 중시한다면 UUID 가 더 적합합니다. |
7. 참고
'Database' 카테고리의 다른 글
[Database] SQL 성능 최적화: 빠른 쿼리를 위한 7가지 체크리스트 (1) | 2025.03.05 |
---|---|
[Database] 인덱스를 타지 않는 쿼리 10가지 경우 정리 (0) | 2025.01.05 |