Home > DB > πŸ’Ύ[Database] Primary Key 생성 μ „λž΅ - DB auto increment(2)

πŸ’Ύ[Database] Primary Key 생성 μ „λž΅ - DB auto increment(2)
Database Primary Key DBMS

β€œπŸ’Ύ[Database] Primary Key 생성 μ „λž΅ - DB auto increment(2)”

βœ…1️⃣ PK와 Unique Indexλ₯Ό λΆ„λ¦¬ν•˜λŠ” 이유.

  • β€œPKλŠ” λ°μ΄ν„°λ² μ΄μŠ€ λ‚΄μ—μ„œλ§Œ μ‹λ³„μžλ‘œ μ‚¬μš©ν•˜κ³ , μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œμ˜ μ‹λ³„μžλŠ” λ³„λ„μ˜ Unique Indexλ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€.”
    • μœ„ κ°œλ…μ€ λ°μ΄ν„°λ² μ΄μŠ€ λ‚΄μ—μ„œ κ΄€λ¦¬ν•˜λŠ” PK와 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©ν•˜λŠ” μ‹λ³„μžλ₯Ό λΆ„λ¦¬ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
    • 즉, PK둜 id(Auto Increment)λ₯Ό μ‚¬μš©ν•˜κ³ , μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ article_id(Snowflake λ˜λŠ” UUID)λ₯Ό ν™œμš©ν•˜λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€.

βœ…2️⃣ 예제 μ‹œλ‚˜λ¦¬μ˜€.

πŸ“Œ1️⃣ PK: id(AUTO_INCREMENT)

  • DBμ—μ„œ κΈ°λ³Έ ν‚€ 역할을 μˆ˜ν–‰ν•˜λ©°, μ •μˆ˜(BIGINT) νƒ€μž….
  • 데이터가 좔가될 λ•Œ 1μ”© μžλ™ 증가.
  • λ°μ΄ν„°λ² μ΄μŠ€ λ‚΄μ—μ„œ 관계(Join, Indexing, 검색 속도)λ₯Ό μ΅œμ ν™”ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©.

πŸ“Œ2️⃣ Unique Index: article_id(Snowflake λ˜λŠ” UUID)

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ™ΈλΆ€ μ‹œμŠ€ν…œκ³Ό μ—°λ™ν•˜κ±°λ‚˜ API μ‘λ‹΅μ—μ„œ μ‚¬μš©ν•˜λŠ” μ‹λ³„μž.
  • UUID λ˜λŠ” Snowflakeλ₯Ό μ‚¬μš©ν•˜μ—¬ μ „μ—­μ μœΌλ‘œ κ³ μœ ν•œ 값을 생성.
  • Unique Indexλ₯Ό μ„€μ •ν•˜μ—¬ μ€‘λ³΅λ˜μ§€ μ•Šλ„λ‘ 보μž₯.

βœ…3️⃣ DDL 예제(MySQL κΈ°μ€€).

CREATE TABLE article (
    id BIGINT AUTO_INCREMENT PRIMARY KEY, -- PK (DB λ‚΄λΆ€μ—μ„œ μ‚¬μš©)
    article_id VARCHAR(36) UNIQUE NOT NULL, -- UUID λ˜λŠ” Snowflake (APIμ—μ„œ μ‚¬μš©)
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    modified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
  • id ➞ AUTO_INCREMENTλ₯Ό μ‚¬μš©ν•˜μ—¬ κΈ°λ³Έ ν‚€ μ—­ν•  μˆ˜ν–‰.
  • article_id ➞ UUID λ˜λŠ” Snowflakeλ₯Ό μ‚¬μš©ν•˜λ©°, UNIQUE INDEX μ„€μ •.
  • article_idλ₯Ό APIλ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ™€ 데이터λ₯Ό 주고받을 λ•Œ μ‚¬μš© (예: REST API)

βœ…4️⃣ Spring Boot JPA Entity 예제.

import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Getter
@ToString
@Entity
@Table(name = "article")
@NoArgsconstructor(access = AccessLevel.PROTECTED)
public class Article {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // DB Auto Increment
    private Long id;
    
    @Column(unique = true, nullable = false, length = 36) // UUID or Snowflake
    private String articleId;
    
    private String title;
    private String content;
    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;
    
    // 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œλ‘œ UUID λ˜λŠ” Snowflake ID 생성
    public static Article create(String title, String content) {
        Article article = new Article();
        article.articleId = generateUniqueId(); // UUID λ˜λŠ” Snowflake μ‚¬μš©
        article.title = title;
        article.content = content;
        article.createdAt = LocalDateTime.now();
        article.modifiedAt = article.createdAt;
        
        return article;
    }
    
    public void update(String title, String content) {
        this.title = title;
        this.content = content;
        this.modifiedAt = LocalDateTime.now();
    }
    
    // Snowflake λ˜λŠ” UUID ID 생성 λ©”μ„œλ“œ
    private static String generateUniqueId() {
        return java.util.UUID.randomUUID().toString(); // UUID μ‚¬μš© 예제
    }
}
  • id: λ°μ΄ν„°λ² μ΄μŠ€κ°€ κ΄€λ¦¬ν•˜λŠ” μžλ™ 증가 κ°’.
  • articleId: μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ UUIDλ₯Ό μ‚¬μš©ν•˜μ—¬ 생성.
  • generateUniqueId()λŠ” UUIDλ₯Ό μ‚¬μš©ν–ˆμ§€λ§Œ Snowflakeλ₯Ό μ μš©ν•  μˆ˜λ„ 있음

βœ…5️⃣ 데이터 μ‚½μž… 예제.

βœ… JPAλ₯Ό μ‚¬μš©ν•œ 데이터 μ €μž₯.

Article article = Article.create("My Title", "This is content.");
articleRepository.save(article);

βœ… DB에 μ €μž₯된 데이터 μ˜ˆμ‹œ.

SELECT * FROM article;
id article_id title content created_at modified_at
1 550e8400-e29b-41d4-a716-446655440000 My Title This is content 2024-02-05 12:00:00 2024-02-05 12:00:00
  • idλŠ” μžλ™ 증가(AUTO_INCREMENT)
  • article_idλŠ” UUIDλ₯Ό 기반으둜 생성됨
  • API μ‘λ‹΅μ—μ„œ article_idλ₯Ό μ œκ³΅ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈμ™€ 데이터 μ£Όκ³ λ°›κΈ° μš©λ„λ‘œ μ‚¬μš©

βœ…6️⃣ μ™œ PK와 Unique Indexλ₯Ό λΆ„λ¦¬ν• κΉŒ?

1️⃣ Auto Increment PKλŠ” DB μ„±λŠ₯ μ΅œμ ν™”μ— 유리.

  • BIGINT AUTO_INCREMENTλŠ” μ •μˆ˜ κ°’μ΄λ―€λ‘œ Join, Indexing이 빠름.
  • UUID(VARCHAR)λ₯Ό PK둜 μ‚¬μš©ν•˜λ©΄ 인덱슀 μ„±λŠ₯이 떨어짐 (특히 MySQL InnoDBμ—μ„œ).
  • Primary KeyλŠ” 내뢀적인 데이터 관리 μš©λ„λ‘œλ§Œ μ‚¬μš©ν•˜λŠ” 것이 일반적.

2️⃣ UUID(Snowflake)λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ™ΈλΆ€ μ‹λ³„μžλ‘œ 적합.

  • UUIDλ‚˜ SnowflakeλŠ” μ „μ—­μ μœΌλ‘œ κ³ μœ ν•œ 값을 μƒμ„±ν•˜λ―€λ‘œ λ‹€λ₯Έ μ‹œμŠ€ν…œκ³Ό 연동할 λ•Œ 유리.
  • id(Auto Increment)λ₯Ό μ‚¬μš©ν•˜λ©΄ λ‹€λ₯Έ DB둜 데이터λ₯Ό 이동할 λ•Œ μΆ©λŒν•  κ°€λŠ₯성이 있음.

3️⃣ 데이터 λ§ˆμ΄ν¬λ ˆμ΄μ…˜ & λΆ„μ‚° μ‹œμŠ€ν…œμ— 유리.

  • UUID/SnowflakeλŠ” μ„œλ²„κ°€ μ—¬λŸ¬ 개 μžˆμ–΄λ„ κ³ μœ ν•œ κ°’ 생성 κ°€λŠ₯.
  • Auto IncrementλŠ” 단일 DBμ—μ„œλ§Œ 고유 보μž₯됨 ➞ 샀딩(Sharding) ν™˜κ²½μ—μ„œλŠ” 좩돌 κ°€λŠ₯.

βœ…7️⃣ API μ„€κ³„μ—μ„œμ˜ 차이점.

1️⃣ id(Auto Increment)λ₯Ό APIμ—μ„œ λ…ΈμΆœν•  경우.

{
    "id": 1,
    "title": "My Title",
    "content": "This is content",
    "createdAt": "2024-02-05T12:00:00"
}
  • λ³΄μ•ˆμƒ λ¬Έμ œκ°€ 될 수 있음(예: IDλ₯Ό μ—°μ†μ μœΌλ‘œ μ¦κ°€μ‹œν‚€λ©° 쑰회 κ°€λŠ₯)

2️⃣ articleId(UUID/Snowflake)λ₯Ό APIμ—μ„œ λ…ΈμΆœν•  경우 (ꢌμž₯)

{
    "articleId": "550e8400-e29b-41d4-a716-446655440000",
    "title": "My Title",
    "content": "This is content",
    "createdAt": "2024-02-05T12:00:00"
}
  • UUID λ˜λŠ” SnowflakeλŠ” λ³΄μ•ˆμ„±μ΄ λ†’κ³ , λΆ„μ‚° ν™˜κ²½μ—μ„œλ„ μ•ˆμ „ν•¨.
  • ν΄λΌμ΄μ–ΈνŠΈλŠ” articleIdλ₯Ό μ‚¬μš©ν•˜μ—¬ 데이터λ₯Ό μ‘°νšŒν•˜κ³  μ—…λ°μ΄νŠΈν•  수 있음.

βœ…8️⃣ API μ»¨νŠΈλ‘€λŸ¬μ—μ„œ articleId ν™œμš©.

@GetMapping("/v1/articles/{articleId}")
public ArticleResponse getArticle(@PathVariable String articleId) {
    Article article = articleRepository.findByArticleId(articleId)
        .orElseThrow(() -> new RuntimeException("Article not found"));
    return ArticleResponse.from(article);
}
  • id(PK)κ°€ μ•„λ‹ˆλΌ articleIdλ₯Ό 기반으둜 쑰회 ➞ ν΄λΌμ΄μ–ΈνŠΈκ°€ 예츑 λΆˆκ°€λŠ₯ν•œ ID μ‚¬μš© κ°€λŠ₯.
  • findByArticleId()λŠ” Unique Indexλ₯Ό ν™œμš©ν•˜μ—¬ λΉ λ₯΄κ²Œ 쑰회 κ°€λŠ₯.

βœ…9️⃣ κ²°λ‘ .

PK(id) Unique Index(article_id)
AUTO_INCREMENT둜 생성됨 UUID λ˜λŠ” Snowflake둜 생성됨
DBμ—μ„œλ§Œ μ‚¬μš©(Join, Index μ΅œμ ν™”) API와 μ™ΈλΆ€ μ‹œμŠ€ν…œμ—μ„œ μ‚¬μš©
연속적인 숫자(예: 1,2,3…) 랜덀 κ°’(예: UUID 550e8400-e29b…)
λ°μ΄ν„°λ² μ΄μŠ€ μ„±λŠ₯ μ΅œμ ν™” λ³΄μ•ˆμ„±κ³Ό ν™•μž₯μ„± 증가
λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μ‹œ 좩돌 μœ„ν—˜ λΆ„μ‚° μ‹œμŠ€ν…œμ—μ„œ μ•ˆμ „ν•¨

πŸš€ 마무리

  • DB λ‚΄λΆ€ κ΄€λ¦¬μš© ID(AUTO_INCREMENT)와 API μ‹λ³„μš© ID(UUID/Snowflake)λ₯Ό λΆ„λ¦¬ν•˜λŠ” 것이 베슀트 ν”„λž™ν‹°μŠ€.
  • APIμ—μ„œλŠ” articleId(UUID/Snowflake)만 λ…ΈμΆœν•˜μ—¬ λ³΄μ•ˆμ„±κ³Ό ν™•μž₯성을 확보.
  • λ°μ΄ν„°λ² μ΄μŠ€ μ„±λŠ₯을 μœ μ§€ν•˜λ©΄μ„œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ ˆλ²¨μ—μ„œ μœ λ‹ˆν¬ν•œ μ‹λ³„μžλ₯Ό κ°€μ§ˆ 수 있음.