Now Loading ...
-
💾[Database] Primary Key 생성 전략 - 유니크 정렬 문자열
“💾[Database] Primary Key 생성 전략 - 유니크 정렬 문자열”
🍎 Intro.
Primary Key(PK)를 생성할 때, 각 ID가 고유하면서도 생성된 순서대로 정렬이 가능하도록 만드는 방식입니다.
이 방식은 UUID처럼 충돌 없는 고유성을 유지하면서도, 정렬이 가능하도록 시간 기반의 요소를 포함하는 것이 핵심입니다.
✅1️⃣ 유니크 정렬 문자열 방식이 필요한 이유.
기존의 PK 생성 방식에는 몇 가지 문제점이 있습니다.
❌1️⃣ UUID의 문제점.
UUID는 충돌 없이 유니크하지만, 정렬이 불가능합니다.
ID가 랜덤하게 생성되기 때문에 최근 데이터 정렬이 어렵습니다.
문자열 길이가 길고 인덱싱 성능 저하 가능성이 있습니다.
❌2️⃣ AUTO_INCREMENT(숫자 증가 방식)의 문제점.
여러 서버(분산 환경)에서 사용하면 중복 발생 가능성이 있습니다.
ID가 예측 가능하여 보안에 취약점이 존재합니다.
✅ 유니크 정렬 문자열 방식이 해결하는 문제.
UUID처럼 고유하지만, 시간순으로 정렬이 가능합니다.
서버가 여러 개여도 중복되지 않습니다 (분산 환경에서도 안정적).
ID가 일정한 패턴을 가지므로, 인덱싱 성능이 더 좋습니다.
✅2️⃣ 유니크 정렬 문자열 방식 종류
전략
예제
길이
특징
KSUID
0ujsswThIGTUYm2K8FjOOfXtY1K
27자
UUID보다 짧고, 시간 정렬 가능
ULID
01F8MECHZX3TBXYN5RRTG1X3J6
26자
UUID보다 짧고, 생성 순서대로 정렬 가능
Sonyflake
404168231342172160
19자
Snowflake와 유사, 빠른 속도
Short UUID + Timestamp
20250131235959-8f9c7d3a
가변
날짜 기반으로 정렬 가능
각 방식은 시간 정보가 포함되어 생성된 순서대로 정렬이 가능하도록 설계되어 있습니다.
✅3️⃣ 유니크 정렬 문자열 방식의 예제 코드.
🛠️1️⃣ ULID(Universally Unique Lexicographically Sortable Identifier)
ULID는 UUID보다 짧고, 생성 순서대로 정렬이 가능한 ID 방식입니다.
📌 ULID 특징.
UUID보다 10자 정도 짧음 (26자)
생성된 순서대로 정렬 가능 (시간 정보 포함)
URL-safe (특수문자가 없음)
대소문자 구분 (Base32 사용)
📝 Spring Boot에서 ULID 사용하기.
ULID를 사용하려면 ulid 라이브러리를 추가해야 합니다.
1️⃣ Maven 또는 Gradle에 라이브러리 추가.
<dependency>
<groupId>de.huxhorn.sulky</groupId>
<artifactId>de.huxhorn.sulky.ulid</artifactId>
<version>8.3.0</version>
</dependency>
2️⃣ ULID 기반 ID 생성.
import de.huxhorn.sulky.ulid.ULID;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@Entity
@Table(name = "article")
public class Article {
@Id
@Column(name = "article_id", updatable = false, nullable = false, length = 26)
private String articleId;
private String title;
private String content;
@PrePersist
public void generateId() {
ULID ulid = new ULID();
this.articleId = ulid.nextULID(); // ULID 생성
}
}
✅ ULID의 주요 장점.
nextULID()를 호출할 때마다 새로운, 정렬 가능한 고유 ID가 생성됨.
시간 정렬이 가능하여 ORDER BY article_id ASC로 최근 데이터를 쉽게 조회 가능.
🛠️2️⃣ KSUID(K-Sortable Unique ID)
KSUID는 ULID와 비슷하지만, 더 긴 ID(27자)를 사용하며 UUID보다 정렬이 쉽습니다.
📌 KSUID의 특징.
시간 기반 정렬 기능.
UUID보다 짧고 읽기 쉬움.
고유성이 보장됨,
📝 Spring Boot에서 KSUID 적용.
1️⃣ Maven 또는 Gradle에 라이브러리 추가.
<dependency>
<groupId>com.github.ksuid</groupId>
<artifactId>ksuid</artifactId>
<version>1.0.0</version>
</dependency>
2️⃣ KSUID 기반 ID 생성.
import com.github.ksuid.Ksuid;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@Entity
@Table(name = "article")
public class Article {
@Id
@Column(name = "article_id", updatable = false, nullable = false, length = 27)
private String articleId;
private String title;
private String content;
@PrePersist
public void generateId() {
this.articleId = Ksuid.newKsuid().toString(); // KSUID 생성
}
}
✅ KSUID의 주요 장점
newKsuid().toString()을 호출할 때마다 새로운, 정렬 가능한 고유 ID가 생성됨.
UUID보다 짧고, 더 빠름.
정렬이 가능하여 최근 데이터 조회가 쉽다.
🛠️3️⃣ Short UUID + Timestamp (커스텀 방식)
만약 직접 UUID를 짧게 변형하고, 시간 정보와 조합하여 고유한 정렬 문자열을 만들 수도 있습니다.
📌 Short UUID + Timestamp의 특징.
날짜 기반으로 정렬 가능
UUID보다 짧고, 가독성이 좋음
특정 비즈니스 로직에 맞게 커스텀 가능
📝 Java에서 Short UUID + Timestamp 적용
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
public class CustomIdGenerator {
public static String generateId() {
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String shortUUID = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
return timestamp + "-" + shortUUID;
}
public static void main(String[] args) {
System.out.println(generateId()); // 예: 20250201093045-8f9c7d3a
}
}
✅ 이 방식의 장점
정렬 기능 (날짜 기반)
UUID보다 짧고 가독성이 좋음
UUID의 충돌 방지 기능을 유지
✅4️⃣ 유니크 정렬 문자열 방식의 비교
전략
예제
길이
특징
ULID
01F8MECHZX3TBXYN5RRTG1X3J6
26자
UUID보다 짧고, 생성 순서대로 정렬 가능
KSUID
0ujsswThIGTUYm2K8FjOOfXtY1K
27자
UUID보다 짧고, 시간 정렬 가능
Short UUID + Timestame
20250201093045-8f9c7d3a
가변
날짜 기반으로 정렬 가능
✅5️⃣ 결론.
UUID는 정렬이 어렵고 길다.
ULID, KSUID 같은 방식은 유니크하면서도 생성된 순서대로 정렬 가능.
Short UUID + Timestamp는 직접 커스텀하여 사용할 수도 있음.
-
💾[Database] Primary Key 생성 전략 - 유니크 정렬 숫자
“💾[Database] Primary Key 생성 전략 - 유니크 정렬 숫자”
🍎 Intro.
PK(Primary Key)를 생성할 때, 각 ID가 고유하면서도 생성된 순서대로 정렬이 가능하도록 만드는 방식입니다.
이 방식은 숫자 기반 ID(예: Snowflake, Sonyflake, TikTok ID 등)를 사용하여 생성된 순서대로 정렬 가능하도록 설계된 것이 특징입니다.
✅1️⃣ 유니크 정렬 숫자 방식이 필요한 이유.
✅1️⃣ 유니크 정렬 숫자 방식의 장점.
생성된 순서대로 정렬 가능 ➞ 최근 데이터를 쉽게 조회 가능.
숫자형 ID이므로 인덱싱 성능이 우수 ➞ UUID보다 빠름.
다중 서버 환경(분산 시스템)에서도 고유성 보장 가능.
대량 트래픽 처리에 적합.
❌2️⃣ 기존 숫자 기반 PK(AUTO_INCREMENT)의 문제점.
단일 서버 환경에서는 문제 없지만, 다중 서버(분산 환경)에서는 충돌 가능성 있음.
ID가 예측 가능하여 보안상 취약함 ➞ 공격자가 특정 ID를 추측할 수 있음.
대량 트래픽 처리에 적합하지 않음.(숫자가 순차적으로 증가하면서 성능 저하 가능)
✅2️⃣ 유니크 정렬 숫자 방식의 종류.
전략
예제
길이
특징
Snowflake (Twitter 방식)
146789123456789012
19자
시간 기반 정렬 가능, 성능 최적화.
Sonyflake (Go 언어 기반)
404168231342172160
19자
Snowflake보다 더 빠름.
TikTok ID
720615963569438720
18~19자
Snowflake 변형, 글로벌 서비스 사용.
Flake ID (Custom 방식)
1706745678123456
16자
Snowflake를 단순화한 버전
✅3️⃣ 유니크 정렬 숫자 방식의 예제 코드
🛠️1️⃣ Snowflake(Twitter에서 개발한 분산 ID)
📌 Snowflake란?
Twitter에서 대량의 트래픽을 처리하기 위해 개발한 ID 생성 알고리즘.
64비트 정수 (19자리)를 사용하여 정렬 가능.
시간 정보 + 서버 정보 + 시퀀스 번호로 ID를 생성.
📝 Snowflake ID 구조
비트 수
설명
1비트
예약(항상 0)
41비트
타임스탬프(현재 시간 기준)
10비트
서버 ID 또는 데이터센터 ID
12비트
시퀀스 번호 (같은 밀리초 내에서 증가)
📌 Snowflake ID Java 구현.
import java.time.Instant;
public class Snowflake {
private static final long EPOCH = 1640995200000L; // 기준 시간(2022-01-01 00:00:00)
private static final long MACHINE_ID = 1L;
private static final long SEQUENCE_BITS = 12L;
private long lastTimestamp = -1L;
private long sequence = 0L;
public synchronized long nextId() {
long timestamp = Instant.now().toEpochMilli();
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
if (sequence == 0) {
while (timestamp <= lastTimestamp) {
timestamp = Instant.now().toEpochMilli();
}
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH) << (64 - 41)) | (MACHINE_ID << (64 - 41 - 10)) | sequence;
}
}
✅ Snowflake ID 특징.
시간 기반 ID이므로 자동 정렬 가능.
19자리 정수(BIGINT)로 저장 가능.
다중 서버 환경에서도 충돌 없음.
🛠️2️⃣ Sonyflake(Go 언어 기반의 빠른 ID 생성)
📌 Sonyflake란?
Snowflake보다 단순하고 빠른 ID 생성 알고리즘.
시간. 정보 + 머신 ID + 시퀀스 번호로 구성.
📌 Sonyflake ID Java 구현.
import java.time.Instant;
public class Sonyflake {
private static final long EPOCH = 1640995200000L; // 기준 시간(2022-01-01 00:00:00)
private static final long MACHINE_ID = 1L;
private static final long SEQUENCE_BITS = 8L;
private long lastTimestamp = -1L;
private long sequence = 0L;
public synchronized long nextId() {
long timestamp = Instant.now().toEpochMilli();
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
if (sequence == 0) {
while (timestamp <= lastTimestamp) {
timestamp = Instant.now().toEpochMilli();
}
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH) << (64 - 39)) | (MACHINE_ID << (64 - 39 - 8)) | sequence;
}
}
✅ Sonyflake의 장점.
Snowflake보다 더 빠르고 경량.
비트 연산을 최적화하여 성능 향상.
간단한 구조로 서버에서 쉽게 사용 가능.
🛠️3️⃣ TikTok ID (Snowflake 변형)
📌 TikTok ID란?
Snowflake 기반이지만 시퀀스 번호가 더 크고, 글로벌 사용에 최적화됨.
데이터센터 ID, 머신 ID 등을 최적화하여 사용.
📌 TikTok ID Java 구현
public class TikTokIdGenerator {
private static final long START_TIMESTAMP = 1420070400000L; // 2015-01-01 00:00:00
private static final long SEQUENCE_BITS = 12L;
private static final long MACHINE_ID = 1L;
private long lastTimestamp = -1L;
private long sequence = 0L;
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
if (sequence == 0) {
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - START_TIMESTAMP) << (64 - 41)) | (MACHINE_ID << (64 - 41 - 10)) | sequence;
}
}
✅ TikTok ID의 특징.
Snowflake보다 더 유연한 구조.
분산 시스템에서 고유성 유지.
✅4️⃣ 유니크 정렬 숫자ㅏ 방식의 비교.
전략
예제
길이
특징
Snowflake
146789123456789012
19자
시간 기반 정렬 가능, 성능 최적화
Sonyflake
404168231342172160
19자
Snowflake보다 더 빠름.
TikTok ID
720615963569438720
18 ~ 19자
Snowflake 변형, 글로벌 서비스 사용
Flake ID
1706745678123456
16자
Snowflake를 단순화한 버전
✅5️⃣ 결론..
Snowflake, Sonyflake, TikTok ID 같은 유니크 정렬 숫자 방식은 고유성과 정렬 가능성을 동시에 제공.
UUID보다 인덱싱 성능이 우수하며, 대량 트래픽에서도 안정적.
고성능 시스템, 금융 서비스, 로그 저장 등에 적합.
-
💾[Database] Primary Key 생성 전략 - 유니크 문자열 또는 숫자
“💾[Database] Primary Key 생성 전략 - 유니크 문자열 또는 숫자”
🍎 Intro.
PK(Primary Key)를 단순한 AUTO_INCREMENT가 아닌, 고유한 문자열(UUID) 또는 숫자(Snowflake, Nano ID 등)로 생성하는 방식입니다.
이 방식은 분산 시스템, 대용량 트래픽 처리, 보안성 강화 등의 이유로 많이 사용됩니다.
✅1️⃣ “유니크 문자열 또는 숫자” PK 방식이 필요한 이유.
기존의 AUTO_INCREMENT PK는 단순히 1씩 증가하는 방식이므로:
1. 보안에 취약 ➞ 공격자가 ID를 예상할 수 있음(/articles/1, /articles/2 …).
2. 다중 서버(샤딩) 환경에서 충돌 발생 가능 ➞ 각 서버에서 독립적인 ID 생성이 어려움.
3. 데이터 마이그레이션 시 충돌 가능성 ➞ 다른 데이터베이스로 데이터를 옮길 때 ID가 겹칠 수 있음.
위와 같은 문제를 해결하기 위해, UUID, Snowflake, Nano ID 등을 사용하여 고유한 문자열 또는 숫자로 PK를 생성하는 방식이 등장했습니다.
✅2️⃣ 유니크 문자열 또는 숫자를 이용한 PK 생성 전략.
전략
예제
길이
특징
UUID(Universally Unique Identifier)
550e8400-e29b-41d4-a716-446655440000
36자
전 세계적으로 유일한 문자열, 속도가 느릴 수 있음
Snowflake(Twitter ID 방식)
146789123456789012
19자
시간 기반으로 생성, 고유성 보장, 성능 최적화
Nano ID
V1StGXR8_Z5jdHi6B-myT
21자
랜덤 문자열, URL-safe, 짧고 충돌 확률이 낮음
KSUID(K-Sortable Unique ID)
0ujsswThIGTUYm2K8FjOOfXtY1K
27자
시간 정렬 가능, UUID보다 짧고 읽기 쉬움
✅3️⃣ UUID(Universally Unique Identifier)
📌 UUID란?
128비트의 고유한 문자열을 생성하는 알고리즘.
전 세계적으로 유일한 값을 만들 수 있음.
랜덤성이 강하여 충돌 확률이 매우 낮음.
길이가 길어(36자) 인덱싱 성능이 저하될 수 있음.
🛠️ UUID를 PK로 사용하는 MySQL 테이블 예제.
CREATE TABLE article (
article_id CHAR(36) PRIMARY KEY, -- UUID 사용
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
📝 Spring Boot JPA에서 UUID 적용.
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import java.util.UUID;
@Getter
@NoArgsConstructor
@Entity
@Table(name = "article")
public class Article {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@Column(name = "article_id", updatable = false, nullable = false, length = 36)
private String articleId;
private String title;
private String content;
}
✅ UUID를 자동으로 생성하여 PK로 사용
✅ JPA에서 @GeneratedValue(generator = “UUID”)를 사용
✅ DB에는 CHAR(36)로 저장
✅4️⃣ Snowflake(Twitter에서 개발한 분산 ID)
📌 Snowflake란?
Twitter에서 고유한 숫자 ID를 빠르게 생성하기 위해 개발한 알고리즘.
64비트 정수 (19자리)를 사용하여 시간 정렬 가능.
성능 최적화 & ID 충돌 없음.
분산 시스템(여러 서버)에서 사용 가능.
🛠️ MySQL 테이블 예제(Snowflake).
CREATE TABLE article (
article_id BIGINT PRIMARY KEY, -- Snowflake ID 사용
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
📝 Spring Boot에서 Snowflake 적용.
import java.time.Instant;
public class Snowflake {
private static final Long EPOCH = 1640995200000L; // 2022-01-01 기준
private static final Long MACHINE_ID = 1L;
private static final Long SEQUENCE_BITS = 12L;
private Long lastTimestamp = -1L;
private Long sequence = 0L;
public synchronized Long nextId() {
Long timestamp = Instant.now().toEpochMilli();
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
if (sequence == 0) {
while (timestamp <= lastTimestamp) {
timestamp = Instant.now().toEpochMilli();
}
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH)) << (64 - 41) | (MACHINE_ID << (64 - 41 - 10)) | sequence;
}
}
✅ UUID보다 짧은 숫자(BIGINT)로 고유한 ID 생성.
✅ 날짜 기반이므로 정렬 가능 (최근 데이터 조회 시 유리).
✅ 서버가 여러 개여도 중복되지 않음.
✅5️⃣ Nano ID (가볍고 짧은 랜덤 문자열)
📌 Nano ID란?
UUID보다 짧고 성능이 빠른 ID 생성기.
URL-safe (URL에 사용 가능).
랜덤성으로 인해 충돌 확률이 낮음.
자바스크립트 환경에서도 사용 가능.
🛠️ MySQL 테이블 예제 (Nano ID)
CREATE TABLE article (
article_id VARCHAR(21) PRIMARY KEY, -- Nano ID 사용
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL.
created_at TIME
)
VARCHAR(21) ➞ Nano ID는 기본적으로 21자 길이를 가지므로 테이블에서도 VARCHAR(21)로 설정.
📝 Spring Boot에서 Nano ID 적용.
Java에서는 Nano ID 라이브러리(com.aventrix.jnanoid)를 사용하여 Nano ID를 생성할 수 있습니다.
1️⃣ Maven 또는 Gradle에 Nano ID 라이브러리 추가
Maven 사용 시
<dependency>
<groupId>com.aventrix.jnanoid</groupId>
<artifactId>jnanoid</artifactId>
<version>2.0.0</version>
</dependency>
Gradle 사용 시
implementation 'com.aventrix.jnanoid:jnanoid:2.0.0'
2️⃣ Entity에서 Nano ID를 사용하여 Primary Key 설정.
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
@Getter
@NoArgsConstructor
@Entity
@Table(name = "article")
public class Article {
@Id
@Column(name = "article_id", updatable = false, nullable = false, length = 21)
private String articleId;
private String title;
private String content;
@PrePersist
public void generateId() {
this.articleId = NanoIdUtils.randomNanoId(); // Nano ID 생성
}
}
✅ Nano ID 방식의 장점.
1. UUID보다 짧음(21자) ➞ 성능 최적화
2. 랜덤한 값이므로 보안성 우수 (ID 예측 불가능)
3. URL-safe ➞ URL에서 안전하게 사용 가능
4. 서버 부담이 적고, 빠른 속도로 생성 가능
❌ Nano ID 방식의 단점.
1. UUID보다 충돌 확률이 높지만, 충분히 낮은 수준.
2. 정렬이 어려움 ➞ 시간 기반이 아느므로 최근 데이터 정렬이 필요할 경우 적합하지 않음.
-
-
💾[Database] Primary Key 생성 전략 - DB auto increment(2)
“💾[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)만 노출하여 보안성과 확장성을 확보.
데이터베이스 성능을 유지하면서 애플리케이션 레벨에서 유니크한 식별자를 가질 수 있음.
-
-
💾[Database] 게시글 목록 조회 - 페이지 번호
“💾[Database] 게시글 목록 조회 - 페이지 번호”
🍎 Intro
이 방식은 사용자가 특정 페이지를 요청하면 해당 페이지의 데이터만 가져와서 성능을 최적화하는 방법입니다.
✅1️⃣ 페이지 번호 방식이란?
게시글을 여러 페이지로 나누고, 사용자가 특정 페이지를 요청하면 해당 페이지의 데이터만 조회하는 방식입니다.
일반적으로 “LIMIT”와 “OFFSET”을 활용하여 페이지 단위로 데이터를 가져옵니다.
📌1️⃣ 페이지 번호 방식에서 LIMIT과 OFFSET의 의미.
LIMIT과 OFFSET은 페이지 번호 방식(Pagination)에서 특정 페이지의 데이터만 조회할 때 사용되는 SQL 키워드입니다.
LIMIT ➞ 가져올 데이터 개수
OFFSET ➞ 건너뛸 데이터 개수
즉, LIMIT과 OFFSET을 함께 사용하면 특정 페이지에 해당하는 데이터만 가져올 수 있습니다.
📌2️⃣ LIMIT의 의미.
LIMIT이란?
LIMIT은 최대 몇 개의 행(ROW)을 가져올지 결정하는 SQL 키워드 입니다.
주로 페이지 크기(Page Size)를 설정할 때 사용됩니다.
📌 예제: LIMIT.
SELECT *
FROM article
ORDER BY created_at DESC
LIMIT 10;
실행 결과
가장 최신(created_at DESC) 기준으로 최대 10개의 데이터만 가져옵니다.
📌3️⃣ LIMIT의 특징.
항상 첫 번째 데이터부터 가져옵니다.(즉, 1페이지).
특정 페이지를 조회하려면 OFFSET과 함께 사용해야 합니다.
📌2️⃣ OFFSET의 의미.
OFFSET이란?
OFFSET은 앞에서부터 건너뛸 데이터 개수를 지정합니다.
보통 LIMIT과 함께 사용하여 특정 페이지의 데이터를 가져올 때 사용됩니다.
📌 예제: OFFSET(2페이지 조회)
SELECT *
FROM article
ORDER BY created_at DESC
LIMIT 10 OFFSET 10;
실행 결과
OFFSET 10 ➞ 앞의 10개 데이터를 건너 뜀.
LIMIT 10 ➞ 그 다음 10개 데이터 가져옴(즉, 11~20번째 데이터).
✅2️⃣ 페이지 번호 방식의 SQL 쿼리.
MySQL에서 일반적인 페이지 번호 기반 게시글 조회 쿼리는 다음과 같습니다.
SELECT *
FROM article
ORDER BY created_at DESC
LIMIT 10 OFFSET 20; -- 3페이지 (페이지 크기: 10)
설명
ORDER BY created_at DESC ➞ 최신 게시글부터 정렬.
LIMIT 10 ➞ 한 번에 10개의 게시글을 가져옴.
OFFSET 20 ➞ 앞의 20개 데이터를 건너뛰고(=2페이지까지 건너뜀), 3페이지부터 가져옴.
✅3️⃣ 대규모 데이터에서 발생하는 문제점.
데이터가 많을 경우 OFFSET을 사용한 페이지 조회 방식은 성능 저하가 발생할 수 있습니다.
❌성능 문제.
OFFSET 증가 시 검색 속도 저하
OFFSET은 건너뛴 데이터도 내부적으로 읽어야 하므로, OFFSET 값이 클수록 조회 시간이 길어짐.
예시
SELECT *
FROM article
ORDER BY created_at DESC
LIMIT 10 OFFSET 100000;
MySQL은 처음부터 100,000개의 데이터를 읽은 후, 10개만 반환하므로 비효율적.
페이지가 뒤로 갈수록 성능 저하
페이지가 커질수록 OFFSET 값이 커지면서 데이터베이스 부하 증가.
예시: 1,000,000번째 게시글을 조회하는 경우
SELECT *
FROM article
ORDER BY created_at DESC
LIMIT 10 OFFSET 999990;
이 경우 999,990개의 데이터를 먼저 스캔한 후, 마지막 10개만 반환 ➞ 매우 느림
✅4️⃣ 대규모 데이터에서 페이지 번호 방식 최적화.
대규모 데이터에서 성능을 개선하기 위해 여러 가지 최적화 방법이 있습니다.
✅1️⃣ 커서 기반 페이징(Cursor-Based Pagination)
OFFSET을 사용하지 않고, “현재 페이지의 마지막 데이터”를 기준으로 다음 데이터를 조회하는 방식입니다.
SELECT *
FROM article
WHERE created_at < '2025-01-31 12:00:00'
ORDER BY created_at DESC
LIMIT 10;
장점.
OFFSET을 사용자지 않아 건너뛴 데이터의 불필요한 조회를 방지.
데이터가 많아도 성능이 일정하게 유지.
일반적인 SNS(페이스북, 트위터) 및 대형 게시판에서 많이 사용.
✅2️⃣ ID 기반 페이징
게시글의 고유한 ID를 활용하여 페이징을 수행하는 방식입니다.
SELECT *
FROM article
WHERE article_id < 1050
ORDER BY article_id DESC
LIMIT 10;
장점.
특정 ID를 기준으로 데이터를 가져와서 OFFSET보다 성능이 뛰어남.
인덱스를 활용하여 효율적인 검색 가능.
-
💾[Database] MySQL의 쿼리를 기반으로 작성된 네이티브 SQL 쿼리 분석.
💾[Database] MySQL의 쿼리를 기반으로 작성된 네이티브 SQL 쿼리 분석.
📝 Intro
아래의 Query 문은 “MySQL”의 쿼리를 기반으로 작성된 Native SQL Query입니다.
“Spring Data JPA”에서 @Query 어노테이션을 통해 사용되며, 특정 boardId에 속한 게시물(Article)을 페이지네이션 방식으로 조회하는 역할을 합니다.
@Query(
value = "SELECT article.article_id, article.title, article.board_id, article.writer_id, " +
"article.created_at, article.modified_at " +
"FROM (" +
" SELECT article_id FROM article " +
" WHERE board_id = :boardId " +
" ORDER BY article_id DESC " +
" LIMIT :limit OFFSET :offset " +
") t LEFT JOIN article ON t.article_id = article.article_id ",
nativeQuery = true
)
List<Article> findAll(
@Param("boardId") Long boardId,
@Param("offset") Long offset,
@Param("limit") Long limit
);
✅1️⃣ Query 문 분석.
SELECT article.article_id, article.title, article.board_id, article.writer_id,
article.created_at, article.modified_at
FROM (
SELECT article_id
FROM article
WHERE board_id = :boardId
ORDER BY article_id DESC
LIMIT :limit OFFSET :offset
) t
LEFT JOIN article ON t.article_id = article_article_id
1️⃣ 내부 서브쿼리.
SELECT article_id
FROM article
WHERE board_id = :boardId
ORDER BY article_id DESC
LIMIT :limit OFFSET :offset
목적 : 특정 게시판(board_id)에서 필요한 게시물의 ID만 추출.
세부 내용:
board_id = :boardId
↘︎ 전달 받은 boardID에 해당하는 게시물만 조회
ORDER BY article_id DESC
↘︎ article_id를 지군으로 내림차순으로 정렬.(최신 게시물 순)
LIMIT :limit OFFSET :offset
↘︎ 페이지네이션 처리를 위한 키워드.
:limit 👉 한 페이지에 표시할 게시물 수.
:offset 👉 몇 번째부터 데이터를 가져올지 결정.
2️⃣ 외부 쿼리.
SELECT article.article_id, article.title, article.board_id, article.writer_id,
article.created_at, article.modified_at
FROM ... LEFT JOIN article ON t.article_id = article.article_id
목적 : 서브쿼리세어 가져온 article_id를 기준으로 게시물을 상세 정보를 조회.
세부 내용 :
LEFT JOIN
↘︎ 서브쿼리(t)와 article 테이블을 조인.
↘︎ t.article_id와 article.article_id가 일치하는 데이터를 가져옴.
SELECT …
↘︎ 게시물의 주요 정보를 선택적으로 가져옴.
3️⃣ Query의 동작 과정.
1️⃣ 서브쿼리 실행.
↘︎ article 테이블에서 board_id가 :boardId인 게시물의 ID를 최신 순으로 정렬.
↘︎ LIMIT와 OFFSET을 사용해 필요한 게시물 ID만 선택.
4️⃣ 외부 쿼리 실행.
↘︎ 서브 쿼리에서 가져온 article_id를 기준으로 article 테이블의 나머지 데이터를 가져옴.
↘︎ 각 게시물의 ID, 제목, 게시판 ID, 작성자 ID, 생성/수정 시간을 반환.
4️⃣ 파라미터.
@Param(“boardId”) Long boardId
↘︎ 특정 게시판의 ID를 나타냅니다.
↘︎ WHERE board_id = :boardId 조건에 사용됩니다.
@Param(“offset”) Long offset
↘︎ 페이지네이션의 시작 지점을 나타냅니다.
↘︎ 예: 0이면 첫 번째 데이터부터, 10이면 11번째 데이터부터 조회.
@Param(“limit”) Long limit
↘︎ 한 페이지에 가져올 데이터의 수를 나타냅니다.
↘︎ 예: 10이면 한 번에 10개의 데이터를 반환.
-
💾[Database] Hash Based Sharding이란?
💾[Database] Hash Based Sharding이란?
📝 Intro.
Hash Based Sharding은 데이터베이스 샤딩(“데이터를 여러 개의 데이테베이스로 나누는 기법”) 중 하나로, 데이터를 저장할 샤드(Shard)를 결정할 때 해시 함수(Hash Function)를 사용하는 기법입니다.
해시 함수(Hash Function)를 이용해 데이터가 특정 샤드(Shard)에 균등하게 분배되도록 하며, 데이터 분포와 조회 효율성을 최적화합니다.
끄악!! 벌써 너무 어려운 용어들이 많이 나와요!! 그래도 차근 차근 알아가봐요!! 😆
✅1️⃣ 샤딩(Sharding)이란 무엇일까요?
✅ 샤딩(Sharding).
샤딩(Sharding)은 데이터를 여러 개의 작은 조각(Shard)으로 나누어 저장하고 관리하는 방법을 의미합니다.
이러한 샤드(Shard)는 각기 독립적인 데이터베이스나 서버로 동작하며, 대규모 데이터와 트래픽을 처리할 때 성능과 확장성을 향상시키는 데 사용됩니다.
✅ 샤딩과 샤드.
샤딩(Sharding): “데이터를 여러 개의 작은 조각(Shard)으로 나누어 저장하고 관리하는 방법.”
샤드(Shard): 데이터베이스 샤딩에서 Shard는 데이터를 저장하는 “독립된 데이터베이스나 서버”를 가리킴.
✅ 샤딩이 왜 필요하지?
성능 문제 해결!
“병목 현상을 줄일 수 있어요 :)”
데이터베이스에 데이터가 많아지면 쿼리 속도가 느려지고 성능 저하가 발생할 수 있어요. 👎
“샤딩(Sharding)을 통해 데이터를 나누면 각 샤드(Shard)가 독립적으로 처리되므로, 병목 현상을 줄일 수 있지요”
확장성 확보!
“샤딩을 통해 여러 서버를 추가하여 확장이 가능해요 :)”
데이터가 급격히 증가하거나, 트래픽이 많아질 경우 단일 데이터베이스로는 감당할 수 없어요.
때문에 “샤딩을 통해 여러 서버를 추가하여 확장이 가능하지요.”
신뢰성 및 가용성 향상!
“하나의 샤드가 장애를 겪더라도 다른 샤드는 정상적으로 작동하여 서비스 중단을 방지해요.”
✅ 샤딩의 작동 원리를 알아봅시다!
샤딩은 데이터를 저장할 때 특정 기준에 따라 나눕니다.
이 기준에 따라 어떤 데이터를 어떤 샤드에 저장할지 결정됩니다.
1️⃣ 샤드 키(Shard Key)
데이터를 나눌 때 사용하는 기준이 되는 키.
예: 사용자 ID, 날짜, 특정 데이터의 해시 값.
2️⃣ 샤드 할당
샤드 키를 기반으로 데이터를 특정 샤드에 분배.
예:
shard = hash(UserID) % number_of_shards
위 식에 따라 데이터를 샤드에 할당합니다.
✅ 샤딩의 장점은 무엇일까요?
확장성(Scalability)!
데이터를 분산 저장하여 수평적 확장이 가능합니다.
예: 서버를 추가하면 더 많은 데이터를 저장하고 처리할 수 있습니다.
성능 향상!
데이터가 분산되므로 각 샤드에서 처리해야 할 데이터량이 줄어들어 쿼리 성능이 향상됩니다.
가용성!
특정 샤드에 장애가 발생해도, 다른 샤드는 정상적으로 작동합니다.
✅ 샤딩의 단점은 무엇일까요?
복잡성의 증가.
데이터를 나누고 관리하는 추가적인 로직이 필요합니다.
샤드 간 데이터를 조회해야 하는 경우(조인 쿼리) 구현이 복잡해질 수 있습니다.
데이터 재분배 비용.
샤드의 개수를 늘리거나 줄일 경우, 데이터를 재분배해야 하며 이는 시간이 많이 소요됩니다.
핫스팟 문제.
특정 샤드에 데이터가 몰리면 해당 샤드에 과부하가 걸리는 문제가 발생합니다.
✅ 샤딩의 종류에는 무엇이 있을까요?
1️⃣ Range Based Sharding(범위 기반 샤딩)
데이터의 범위에 따라 샤드를 나눕니다.
예: 사용자 ID가 11000은 샤드 1, 10012000은 샤드 2.
장점: 특정 범위의 데이터를 조회할 때 효율적입니다.
단점: 특정 범위에 데이터가 몰릴 경우, 샤드가 불균형해질 수 있습니다.
2️⃣ Hash Based Sharding(해시 기반 샤딩)
데이터의 해시 값을 기준으로 샤드를 나눕니다.
예: shard = hash(UserID) % number_of_shards
장점: 데이터가 균등하게 분배됩니다.
단점: 샤드 개수 변경 시 모든 데이터를 재분배해야 합니다.
3️⃣ Directory Based Sharding(디렉토리 기반 샤딩)
샤드 키와 샤드를 매핑한 별도의 디렉토리(매핑 테이블)를 사용합니다.
장점: 유연하게 데이터를 분배가 가능합니다.
단점: 매핑 테이블 관리의 복잡성이 증가합니다.
✅2️⃣ Hash Based Sharding의 작동 방식은 어떻게 될까요?
1️⃣ 해시 함수(Hash Function).
해시 함수는 입력값(예: User ID, Order ID 등)을 받아서 고정된 크기의 숫자(해시 값)로 변환하는 함수입니다.
예: hash(UserID) = 123456
2️⃣ 샤드 할당.
해시 값을 샤드의 개수로 나눈 나머지 값(Modulo)을 계산하여 데이터를 저장할 샤드를 결정합니다.
예: shard = hash(UserID) % number_of_shards
샤드가 3개이고, hash(UserID) = 123456이라면?
shard = 123456 % 3 = 0
따라서 데이터는 샤드 0에 저장됩니다.
3️⃣ 데이터 저장.
해시 값을 계산한 결과에 따라, 해당 데이터를 특정 샤드에 저장합니다.
✅3️⃣ Hash Based Sharding의 장점.
1️⃣ 균등 분배.
해시 함수는 데이터를 각 샤드에 균등하게 분배하려고 합니다.
따라서 특정 샤드에 데이터가 몰리는 현상(핫스팟)이 줄어듭니다.
2️⃣ 조회 성능 최적화.
데이터를 특정 샤드에만 조회하면 되므로, 전체 샤드를 탐색할 필요가 없어 성능이 향상됩니다.
3️⃣ 설계 단순화.
해시 함수를 통해 샤드를 결정하기 때문에 복잡한 샤딩 로직이 필요하지 않습니다.
✅4️⃣ Hash Based Sharding의 단점.
1️⃣ 샤드 추가/삭제의 어려움.
샤드 수가 변경되면 해시 값이 재계산되어 기존 데이터의 위치가 바뀝니다.
예: 샤드가 3개에서 4개로 증가하면, 데이터의 재배치를 피할 수 없습니다.
2️⃣ 복잡한 데이터 이동.
샤드 수가 변경되면, 모든 데이터를 새로운 샤드 구조에 맞게 이동해야 합니다.
3️⃣ 조인 연산의 어려움.
서로 다른 샤드에 저장된 데이터를 조인해야 하는 경우, 성능이 저하될 수 있습니다.
4️⃣ 핫스팟 문제(특정 키의 과도한 요청).
해시 함수가 균등 분배를 보장하지 못하거나 특정 키에 집중적인 요청이 발생할 경우, 특정 샤드에 부하가 집중될 수 있습니다.
-
-
💾[Database] Secondary Index(보조 인덱스)는 무엇일까요?
💾[Database] Secondary Index(보조 인덱스)는 무엇일까요?
📌 Intro.
↘︎ Secondary Index (보조 인덱스)는 테이블의 기본 키(Primary Key)나 클러스터형 인덱스(Clustered Index) 외의 다른 컬럼(Column)에 추가로 생성되는 인덱스임.
↘︎ 주로 검색 성능을 개선하거나 특정 열(Column)에서의 조회를 최적화하기 위해 사용됨.
✅1️⃣ Secondary Index의 핵심 개념.
1️⃣ 기본 키(Primary Key)와의 차이.
↘︎ Primary Key : 테이블의 주된 인덱스로, 데이터가 물리적으로 정렬됨.
↘︎ Secondary Index : 기본 키(Primary Key)가 아닌 다른 컬럼을 기준으로 생성되며, 데이터는 물리적으로 정렬되지 않음.
2️⃣ 포인터 구조.
↘︎ Secondary Index는 해당 컬럼의 값을 정렬한 후, 기본 키(Primary Key)나 물리적 주소를 가리키는 포인터를 포함함.
↘︎ 이를 통해 해당 컬럼 값으로 빠르게 데이터를 찾고, 그 데이터를 실제로 조회할 수 있음.
3️⃣ 다중 생성 가능.
↘︎ 하나의 테이블에는 여러 개의 Secondary Index를 생성할 수 있음.
↘︎ 예를 들어, name과 email 컬럼에 각각 Secondary Index를 생성할 수 있음.
4️⃣ 읽기/쓰기 성능 트레이드오프.
↘︎ Secondary Index는 읽기 성능을 향상시키지만, 쓰기 성능(INSERT, UPDATE, DELETE)은 저하될 수 있음.
↘︎ 데이터가 변경될 때마다 인덱스를 업데이트해야 하기 때문임.
✅2️⃣ Secondary Index의 장단점.
👍 장점.
1️⃣ 검색 속도 향상.
특정 컬럼에 대해 빠르게 검색 가능.
2️⃣ 여러 필드에 인덱스 생성 가능.
하나의 테이블에 여러 Secondary Index를 생성할 수 있음.
3️⃣ 다양한 쿼리 최적화.
자주 사용하는 WHERE, JOIN, ORDER BY 절에 활용 가능.
👎 단점.
1️⃣ 쓰기 성능 저하.
데이터 삽입, 업데이트, 삭제 시 Secondary Index도 함께 업데이트되어야 하므로 쓰기 성능이 저하됨.
2️⃣ 추가적인 저장 공간 필요.
Secondary Index는 별도의 저장 공간을 차지함.
3️⃣ 복잡한 유지 관리.
너무 많은 인덱스는 쿼리 최적화나 인덱스 재구성에 부하를 줄 수 있음.
✅3️⃣ Secondary Index vs Clusterd Index
구분
Clustered Index
Secondary Index
기준(Column)
Primary Key (주로)
일반 컬럼 (기본 키 외)
물리적 정렬
데이터가 정렬됨
데이터가 정렬되지 않음
인덱스 개수
하나만 생성 가능
여러 개 생성 가능
데이터 접근 방식
직접 데이터 접근
포인터를 통해 데이터 접근
읽기 성능
빠름
빠름 (하지만 포인터 단계 필요)
쓰기 성능
비교적 안정적
쓰기 성능 저하 가능
저장 공간
비교적 적음
추가 저장 공간 필요
✅4️⃣ 언제 Secondary Index를 사용해야 할까?
1️⃣ 자주 검색하는 컬럼.
특정 컬럼을 자주 사용하여 데이터를 조회할 때.
2️⃣ WHERE 절 사용 빈도가 높은 컬럼.
특정 조건으로 자주 필터링할 때.
3️⃣ JOIN 연산 최적화.
다른 테이블과 JOIN할 때 키로 자주 사용되는 컬럼.
🚀 정리.
Secondary Index(보조 인덱스)는 기본 키나 Clustered Index(클러스터형 인덱스) 외의 다른 컬럼에 대해 추가로 생성되는 인덱스.
주로 자주 조회되는 특정 컬럼에 대한 검색 성능을 개선하기 위해 사용.
하지만 너무 많은 Secondary Index를 생성하면 쓰기 성능 저하 및 저장 공간 낭비가 발생할 수 있음
🔑 핵심 포인트.
읽기 성능 최적화.
다중 생성 가능.
쓰기 성능 저하 주의.
👉 Secondary Index는 데이터베이스 설계 시 조회 패턴과 데이터 변경 빈도를 고려하여 신중하게 선택해야 함.
-
-
💾[Database] Clustered Index(클러스터형 인덱스)는 무엇일까요?
💾[Database] Clustered Index(클러스터형 인덱스)는 무엇일까요?
📌 Intro.
↘︎ 클러스터형 인덱스(Clustered Index)는 데이터베이스 테이블의 데이터가 물리적으로 정렬된 상태로 저장되는 인덱스임.
↘︎ 즉, 테이블의 데이터 행(Row)이 특정 기준(열, Column)에 따라 정렬되며, 인덱스는 그 기준에 따라 테이블의 물리적 순서를 유지함.
✅1️⃣ Clustered Index의 핵심 개념.
1️⃣ 물리적 정렬(Physical Order).
↘︎ 클러스터형 인덱스(Clustered Index)는 테이블의 데이터가 인덱스 키 값에 따라 물리적으로 정렬됨.
↘︎ 한 테이블에 단 하나의 클러스터형 인덱스(Clustered Index)만 생성할 수 있음.
↘︎ 데이터의 물리적 순서는 하나의 기준으로만 정렬 가능.
2️⃣ 기본 키(Primary Key)와의 관계.
↘︎ 대부분의 데이터베이스 시스템에서 Primary Key(기본 키)를 설정하면 자동으로 클러스터형 인덱스(Clustered Index)가 생성됨.
↘︎ 예를 들어, id가 Primary Key로 설정된 경우, 테이블은 id 순서대로 정렬됩니다.
3️⃣ 데이터 페이지(Data Pages)
↘︎ 클러스터형 인덱스(Clustered Index)는 데이터 페이지 자체가 인덱스의 일부가 됨.
따라서 클러스터형 인덱스(Clustered Index)를 사용하면 데이터에 직접 접근할 수 있어 검색 속도가 빠름.
4️⃣ Non-Clustered Index (비클러스터형 인덱스)와의 차이
↘︎ 클러스터형 인덱스(Clusterd Index) : 실제 데이터가 인덱스 키 순서대로 정렬되어 저장됩니다.
↘︎ 비클러스터형 인덱스(Non-Clustered Index) : 데이터는 정렬되지 않으며, 인덱스는 데이터의 위치를 가리키는 포인터를 포함합니다.
✅2️⃣ 클러스터형 인덱스의 장단점.
👍 장점.
1️⃣ 빠른 검색 기능.
↘︎ 인덱스 키 값으로 직접 정렬된 데이터를 빠르게 조회할 수 있음.
2️⃣ 범위 검색 최적화.
↘︎ BETWEEN, ORDER BY, GROUP BY 같은 범위 기반 쿼리에 유리함.
3️⃣ 데이터 접근 비용 절감.
↘︎ 데이터 페이지 자체가 인덱스의 일부이므로 추가 포인터가 필요 없음.
👎 단점.
1️⃣ 데이터 삽입/삭제 성능 저하.
↘︎ 인덱스 순서에 따라 데이터가 정렬되므로 삽입/삭제 시 오버헤드가 발생할 수 있음.
2️⃣ 리빌드 비용.
↘︎ 클러스터형 인덱스(Clustered Index)가 자주 변경되면 인덱스를 재구성해야 할 수도 있음.
3️⃣ 한 개만 생성 가능.
↘︎ 테이블당 하나의 클러스터형 인덱스(Clustered Index)만 생성할 수 있음.
✅3️⃣ 언제 사용해야 할까?
1️⃣ 자주 조회되는 테이블.
↘︎ 조회 쿼리가 빈번하게 실행될 경우 클러스터형 인덱스를 사용.
2️⃣ 범위 검색이 많은 경우.
↘︎ BETWEEN, >, < 와 같은 범위 검색을 자주 사용한다면 유리함.
3️⃣ 정렬된 결과가 자주 필요한 경우.
↘︎ ORDER BY 절이 자주 사용되는 경우 효과적임.
✅4️⃣ 비교: Clustered Index vs Non-Clustered Index
구분
Clustered Index
Non-Clustered Index
물리적 저장
데이터 자체가 정렬됨
데이터는 정렬되지 않음
인덱스 개수
하나만 생성 가능
여러 개 생성 가능
성능
조회 성능이 더 빠름
데이터 접근에 추가 단계 필요
주로 사용되는 경우
Primary Key로 사용됨
Secondary Key로 사용됨
🚀 정리.
↘︎ 클러스터형 인덱스(Clustered Index)는 테이블의 데이터를 특정 키 기준으로 물리적으로 정렬하여 저장하는 인덱스입니다.
↘︎ 주로 Primary Key에 의해 생성되며, 빠른 검색 및 범위 조회에 유리합니다.
↘︎ 하지만 삽입/삭제 시 성능 저하가 발생할 수 있고, 하나의 테이블에는 하나의 클러스터형 인덱스만 존재할 수 있습니다.
🎯 핵심 포인트:
↘︎ 물리적 정렬이 핵심
↘︎ Primary Key가 기본적으로 Clustered Index
↘︎ 조회 최적화에 유리, 삽입/삭제 비용은 증가
🙌 데이터베이스 설계 시 테이블의 특성과 쿼리 패턴을 고려하여 클러스터형 인덱스를 적절히 활용해야 함.
-
-
💾[Database] 게시글 목록 조회 - 페이징 처리
💾[Database] 게시글 목록 조회 - 페이징 처리.
✅1️⃣ 비효율적인 페이징 처리.
↘︎ 서버 애플리케이션 내의 메모리로 디스크에 저장된 모든 데이터를 가져오고, 특정 페이지만 추출하는 것은 비효율적임.
↘︎ 디스크 접근은 메모리 접근보다 느리기 때문임.
↘︎ 디스크 I/O 비용
↘︎ 디스크에 저장된 데이터는 메모리 용량을 초과할 수 있음.
↘︎ Out of Memory(OOM)
↘︎ 시스템에서 사용 가능한 메모리가 모두 사용되어 더 이상 할 당할 수 없는 상황.
✅2️⃣ 효율적인 페이징 처리.
↘︎ 데이터베이스에서 특정 페이지의 데이터만 바로 추출하는 방법이 필요함.
↘︎ 페이징 쿼리
✅3️⃣ 페이징 방식.
↘︎ 클라이언트 또는 서비스 특성에 따라 크게 두 가지로 나뉨
↘︎ 페이지 번호
↘︎ ** 무한 스크롤**
📌 페이지 번호 방식.
↘︎ 이동할 페이지 번호가 명시적으로 지정됨.
↘︎ 원하는 페이지로 즉시 이동 가능.
📌 무한 스크롤 방식.
↘︎ 스크롤을 내리면 다음 데이터가 조회됨. ➞ 더보기.
↘︎ 주로 모바일 환경에서 사용함.
✅4️⃣ 페이지 번호 방식.
↘︎ 필요한 정보
↘︎ 1️⃣ N번 페이지에서 M개의 게시글
↘︎ 2️⃣ 게시글의 개수
↘︎ 페이지 번호 활성화에 필요.
↘︎ 예시: 페이지 당 30개의 게시글을 보여주고, 총 94개의 게시글이 있다면, 사용자는 클라이언트 화면에서 4번 페이지까지 이동할 수 있다는 사실을 인지해야 함.
↘︎ 3️⃣ N번 페이지에서 M개의 게시글을 조회하려면?
↘︎ SQL offset, limit을 활용하여 페이지 쿼리를 할 수 있음.
↘︎ offset 지점부터, limit개의 데이터 조회.
↘︎ 4️⃣ SELECT 쿼리로 만들어보면?
↘︎ 게시판별 게시글 목록 최신순 조회
↘︎ shard key = board_id이기 때문에, 단일 샤드에서 조회할 수 있음.
↘︎ limit = M개의 게시글
↘︎ offset = (N번 페이지 - 1) * M
↘︎ N > 0
↘︎ SQL QUERY
SELECT * FROM article // 게시글 테이블
WHERE board_id = {board_id} // 게시판별
ORDER BY created_at DESC // 최신순
LIMIT {LIMIT} OFFSET {OFFSET}; // N번 페이지에서 M개
↘︎ 1,200만 건의 적은 데이터에서 30개의 게시글을 조회하는데 4초가 소요되었음. 정상적으로 서비스하기에는 어려운 상황임.
↘︎ explain select * from article where board_id = 1 order by created_at desc limit 30 offset 90;
↘︎ type = ALL ➞ 테이블 전체를 읽는다 (풀 스캔)
↘︎ Extras = Using where; Using filesort ➞ where 절로 조건에 대해 필터링,
↘︎ 데이터가 많기 때문에 메모리에서 정렬을 수행할 수 없어서, 파일(디스크)에서 데이터를 정렬하는 filesort 수행
↘︎ 전체 데이터에 대해 필터링 및 정렬하기 때문에 아주 큰 비용이 든 것.
🙋♂️ Query Plain
데이터베이스에서 쿼리에 의해 데이터 접근이 실행되는 계획 또는 절차 사용법.
explain {query}
✅5️⃣ 인덱스에 대한 이해
📌 Intro
↘︎ 인덱스(Index)는 데이터베이스에서 데이터를 빠르게 검색하기 위해 사용하는 데이터 구조.
↘︎ 책의 색인(Index)과 비슷한 개념으로, 특정 데이터를 찾기 위해 모든 데이터를 처음부터 끝까지 탐색하지 않고도 원하는 데이터를 효율적으로 조회할 수 있도록 도와줌.
✅6️⃣ 인덱스의 핵심 개념.
↘︎ 빠른 검색 : 테이블에서 특정 데이터를 더 빠르게 찾을 수 있음.
↘︎ 정렬된 구조 : 인덱스는 일반적으로 B-Tree 또는 Hash 구조를 사용하여 데이터를 정렬함.
↘︎ 조회 성능 향상 : WHERE, JOIN, BY와 같은 SQL 연산 시 성능을 개선함.
↘︎ 공간 차지 : 인덱스를 유지하기 위해 추가적인 저장 공간이 필요함.
↘︎ 쓰기 성능 저하 : INSERT, UPDATE, DELETE 작업 시 인덱스를 업데이트해야 하므로 쓰기 작업의 성능이 저하될 수 있음.
✅7️⃣ 인덱스의 작동 원리.
↘︎ 데이터베이스는 테이블의 특정 컬럼(열)에 인덱스를 생성함.
↘︎ SQL 쿼리를 실행할 때, 인덱스가 있는 컬럼을 기준으로 데이터베이스 엔진은 인덱스를 먼저 조회함.
↘︎ 인덱스를 통해 데이터의 위치를 찾고, 해당 위치에서 데이터를 가져옴.
✅8️⃣ 인덱스의 종류.
1️⃣ 일반 인덱스(B-Tree Index)
↘︎ 가장 많이 사용되는 인덱스.
↘︎ 컬럼의 값을 오름차순 또는 내림차순으로 정렬하여 저장함.
2️⃣ 고유 인덱스(Unique Index)
↘︎ 인덱스가 지정된 컬럼은 중복된 값을 가질 수 없음.
↘︎ PRIMARY KEY나 UNIQUE 제약 조건이 포함된 경우 자동으로 생성됨.
3️⃣ 복합 인덱스(Composite Index)
↘︎ 두 개 이상의 컬럼을 결합하여 하나의 인덱스를 만듦.
↘︎ 복합 인덱스는 여러 조건을 동시에 사용할 때 유용.
4️⃣ 풀텍스트 인덱스(Full-Text Index)
↘︎ 문자열 검색에 최적화된 인덱스.
↘︎ 대량의 텍스트 데이터를 검색할 때 사용.
5️⃣ 해시 인덱스(Hash Index)
↘︎ 값을 해시 함수로 변환하여 저장.
↘︎ 정확한 값을 빠르게 찾을 때 사용.
✅9️⃣ 인덱스를 사용해야 하는 경우.
↘︎ WHERE 절로 특정 데이터를 자주 조회할 때.
↘︎ JOIN 연산이 빈번하게 발생할 때.
↘︎ ORDER BY 또는 GROUP BY 절로 정렬이나 그룹화가 필요할 때
↘︎ 자주 사용되는 컬럼에 대해 빠른 검색이 필요할 때.
✅1️⃣0️⃣ 인덱스 사용 시 주의점.
↘︎ 과도한 인덱스 생성 : 너무 많은 인덱스는 쓰기 성능을 저하시키고, 추가적인 저장 공간을 차지함.
↘︎ 불필요한 인덱스 : 자주 사용되지 않는 인덱스는 오히려 성능 저하를 유발할 수 있음.
↘︎ 인덱스 히트 비율(Index Hit Rate) : 쿼리가 인덱스를 제대로 활용하는지 모니터링해야 함.
-
💾[Database] 페이징(Paging)이란 무엇일까요?
💾[Database] 페이징(Paging)이란 무엇일까요?
📌 Intro.
↘︎ 페이징(Paging)은 대량의 데이터를 한 번에 모두 조회하지 않고 작은 단위(Page, 페이지)로 나누어 필요한 부분만을 가져오는 기법.
↘︎ 주로 데이터베이스 쿼리 결과나 웹 애플리케이션에서 사용자의 요청에 따라 데이터의 목록을 보여줄 때 사용.
✅1️⃣ 페이징의 목적.
1. 성능 최적화.
↘︎ 한 번에 많은 데이터를 조회하면 시스템 리소스를 많이 소모하게 됨.
↘︎ 페이징을 통해 데이터베이스와 애플리케이션의 부하를 줄일 수 있음.
2. 사용자 경험 개션.
↘︎ 모든 데이터를 한 번에 보여주면 사용자가 원하는 데이터를 찾기 어려워질 수 있음.
↘︎ 페이징을 통해 데이터를 보기 쉽게 나눌 수 있음.
3. 네트워크 부담 감소.
↘︎ 페이징을 통해 필요한 데이터만 전송하여 네트워크 트래픽을 줄일 수 있음.
✅2️⃣ 페이징의 기본 개념.
1️⃣ 페이지 번호(Page Number)
↘︎ 사용자가 보고자 하는 페이지의 번호임.(예: 1페이지, 2페이지,…)
2️⃣ 페이지 크기(Page Size)
↘︎ 한 페이지당 보여줄 데이터의 개수임.(예: 10개, 20개,…)
3️⃣ 오프셋(Offset)
↘︎ 가져올 데이터의 시작 위치임.(SQL에서 OFFSET 사용)
4️⃣ 한 페이지당 데이터 항목
↘︎ 페이지마다 보여줄 항목의 목록임.
✅3️⃣ 페이징 예시.
📌 SQL 예시 (MySQL)
-- 1페이지 (1~10번 데이터)
SELECT * FROM articles LIMIT 10 OFFSET 0;
-- 2페이지 (11~20번 데이터)
SELECT * FROM articles LIMIT 10 OFFSET 10;
📌 HTTP 요청 예시
GET /articles?page=1&size=10
✅4️⃣ 페이징 방식.
1️⃣ 기본 페이지네이션 (offset 기반 페이징)
↘︎ 페이지 번호와 페이지당 항목 수를 기준으로 쿼리 실행.
↘︎ 예: LIMIT, OFFSET.
2️⃣ 커서 기반 페이징(Cursor-based Pagination)
↘︎ 마지막으로 조회한 항목을 기준으로 다음 항목을 불러옴.
↘︎ 주로 고성능 API에서 사용됨.
3️⃣ 무한 스크롤 (Infinite Scroll)
↘︎ 사용자가 스크롤할 때마다 새로운 항목을 불러옴.
↘︎ 모바일 앱, SNS 피드 등에서 주로 사용됨.
✅5️⃣ 페이징의 주의사항.
1️⃣ 오프셋 성능 문제.
↘︎ OFFSET이 클 경우 쿼리 성능이 저하될 수 있음.(커서 기반 페이징 권장)
2️⃣ 정렬 중요성.
↘︎ 데이터가 일관성 있게 정렬되지 않으면 사용자가 혼란을 겪을 수 있음.
3️⃣ 데이터 일관성 문제.
↘︎ 데이터가 중간에 변경되면 페이지네이션 결과가 일관되지 않을 수 있음.
✅6️⃣ 페이징이 사용되는 대표적인 사례.
↘︎ 1. 블로그 글 목록
↘︎ 2. 게시판 글 목록
↘︎ 3. 전자상거래 상품 목록
↘︎ 4. SNS 피드
↘︎ 5. 검색 결과 페이지
🚀 요약.
↘︎ 페이징(Paging) : 데이터를 일정 단위로 나누어 조회하는 기법
↘︎ 기본 개념 : 페이지 번호, 페이지 크기, 오프셋
↘︎ 목적 : 성능 최적화, 사용자 경험 개선, 네트워크 부하 감소
↘︎ 주의사항 : 오프셋 성능 문제, 데이터 일관성 문제
-
💾[Database] H2 Database란 무엇인가요?
💾[Database] H2 Database란 무엇인가요?
H2 Database는 Java로 구현된 오픈 소스의 경량형 관계형 데이터베이스(RDBMS) 입니다.
주로 테스트 및 개발 환경에서 빠르고 간편하게 데이터베이스를 사용하고자 할 때 활용됩니다.
H2는 메모리 기반 또는 파일 기반으로 동작할 수 있어, 설치 과정 없이 애플리케이션에 내장하여 사용할 수 있는 것이 특징입니다.
1️⃣ H2 Database의 주요 특징.
1️⃣ 경량성(Lightweight)
데이터베이스 엔진의 크기가 작고 빠르며, 메모리 기반으로 동작 시 매우 높은 성능을 제공합니다.
2️⃣ Java로 구현.
Java로 작성되어 Java 기반 애플리케이션과 통합이 용이하며, 플랫폼 독립적입니다.
3️⃣ 내장형 및 독립형.
1️⃣ 내장형 모드(Embedded mode)
애플리케이션에 내장되어 애플리케이션과 함께 실행.
2️⃣ 독립형 모드(Server mode)
독립된 서버로 동작하며, 다른 클라이언트가 접속 가능.
4️⃣ 메모리 기반 및 디스크 기반.
메모리 기반 모드에서는 데이터를 메모리에 저장하여 초고속 성능 제공(애플리케이션 종료 시 데이터 소멸).
디스크 기반 모드에서는 데이터를 파일에 저장하여 지속성을 유지.
5️⃣ SQL 표준 준수.
SQL 표준을 지원하며, 다른 데이터베이스와 유사한 명령어를 사용할 수 있습니다.
6️⃣ 웹 콘솔 제공.
사용하기 편리한 웹 기반 관리 콘솔을 제공하여 SQL 쿼리 실행 및 데이터 확인 가능.
7️⃣ 오픈 소스.
Apache 2.0 라이선스에 따라 무료로 사용 가능.
2️⃣ H2 Database의 주요 활용.
1️⃣ Spring Boot와의 통합.
Spring Boot에서 기본적으로 내장된 데이터베이스로 설정되어 개발 및 테스트 환경에서 자주 사용됩니다.
application.properties에 설정을 추가하면 쉽게 사용할 수 있습니다.
2️⃣ 단위 테스트.
실제 데이터베이스 연결 없이 H2를 사용해 테스트 환경을 구성할 수 있습니다.
3️⃣ 빠른 프로토타이핑.
애플리케이션 개발 초기 단계에서 데이터베이스 설계를 빠르게 실험하고 검증할 수 있습니다.
4️⃣ 학습용.
관계형 데이터베이스 및 SQL 학습에 적합합니다.
3️⃣ H2 Database 설정 예시.
1️⃣ Maven Dependency 추가.
H2 Database를 사용하려면 Maven 프로젝트에 다음 의존성을 추가합니다.
```xml
com.h2database
h2
runtime
### 2️⃣ Spring Boot 설정.
- Spring Boot에서는 `application.properties` 또는 `application.yml` 파일에 H2 설정을 추가합니다.
```properties
# H2 Database 설정
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=""
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:testdb : 메모리 기반 데이터베이스를 사용합니다.
spring.h2.console.enabled=true : H2 콘솔을 활성화합니다.
spring.h2.console.path=/h2-console : H2 콘솔의 접속 경로를 지정합니다.
3️⃣ H2 웹 콘솔 접속
애플리케이션을 실행한 후, 브라우저에서 http://localhost:8080/h2-console로 접속합니다.
JDBC URL : jdbc:h2:mem:testdb
User Name : sa
Password : ""
4️⃣ H2 사용 시 주의 사항.
1️⃣ 데이터 영속성.
메모리 모드에서는 애플리케이션 종료 시 데이터가 사라지므로, 영속성을 유지하려면 파일 기반 (jdbc:h2:file:~/testdb)을 사용해야 합니다.
2️⃣ 운영 환경에서는 부적합.
H2는 주로 개발 및 테스트 환경에서 사용됩니다.
운영 환경에서는 MySQL, PostgreSQL, Orcle 등 더 강력한 데이터베이스를 사용해야 합니다.
3️⃣ 동시성 제한.
단일 사용자 또는 소규모 동시 작업에는 적합하지만, 많은 트랜잭션이 필요한 경우 성능이 떨어질 수 있습니다.
5️⃣ H2 Database의 장점.
간단한 설정과 사용성.
빠른 성능(특히 메모리 모드).
SQL 표준 준수로 학습 및 프로토타이핑에 적합,
Spring Boot와의 완벽한 호환성.
6️⃣ H2 Database의 단점.
대규모 데이터 및 복잡한 트랜잭션 처리에 한계.
운영 환경에서는 적합하지 않음.
영속성 관리가 부족(메모리 기반 모드 사용 시).
7️⃣ 결론.
H2 Database는 경량성과 편의성을 갖춘 데이터베이스로, 주로 개발과 테스트에 최적화된 도구입니다.
빠른 프로토타이핑 및 학습 환경이 필요할 때 활용하면 효율적입니다.
-
-
💾[Database] 스키마(Schema)란 무엇일까요?
💾[Database] 스키마(Schema)란 무엇일까요?
스키마(Schema)는 데이터베이스의 구조를 정의하는 용어로, 데이터베이스에서 데이터가 어떻게 저장되고, 어떻게 조직화되는지를 설명하는 데 사용됩니다.
스키마(Schema)는 데이터베이스의 논리적 설계를 나타내면, 테이블, 뷰, 인덱스, 트리거, 저장 프로시저, 제약 조건 등과 같은 데이터베이스 객체들이 어떻게 구성되는지를 정의합니다.
1️⃣ 스키마의 주요 요소.
1️⃣ 테이블(Table).
스키마(Schema)에서 가장 기본적인 요소로, 데이터를 행(Row)과 열(Column) 형식으로 저장합니다.
각 테이블은 하나의 엔티티(예: 사용자, 제품 등)를 표현하며, 테이블의 열(Column)은 속성을, 행은 각 개체의 데이터를 나타냅니다.
2️⃣ 컬럼(Column).
테이블의 각 필드를 나타내며, 데이터 유형(정수, 문자열 등)과 제약 조건(예: NOT NULL, UNIQUE)이 설정됩니다.
스키마(Schema)에서 컬럼(Column, 열)의 이름, 데이터 타입, 크기 등을 정의합니다.
3️⃣ 기본 키(Primary Key)
테이블에서 각 행(Row)을 고유하게 식별할 수 있는 특정 열(또는 열의 조합)입니다.
스키마(Schema)에서 기본 키(Primary Key)는 특정 테이블에서 중복되지 않는 값으로 정의됩니다.
4️⃣ 외래 키(Foreign Key)
다른 테이블의 기본 키(Primary Key)와 연결되는 열(Column)로, 두 테이블 간의 관계를 정의하는 데 사용됩니다.
스키마(Schema)에서 외래 키(Foreign Key)는 데이터베이스 테이블 간의 참조 무결성을 유지하도록 합니다.
5️⃣ 인덱스(Index)
검색 성능을 향상시키기 위해 테이블의 특정 열(Column)에 대한 인덱스를 정의합니다.
스키마(Schema)에서 인덱스는 데이터의 효율적인 검색을 위한 추가적인 구조를 나타냅니다.
6️⃣ 뷰(View)
하나 이상의 테이블에서 데이터를 추출하여 보여주는 가상의 테이블입니다.
데이터베이스 내에 물리적으로 저장되지 않고, SQL(Structured Query Language) 쿼리 결과를 통해 생성됩니다.
7️⃣ 제약 조건(Constraints)
데이터 무결성을 보장하기 위해 테이블이나 열(Column)에 적용되는 규칙입니다.
예를 들어, NOT NULL, UNIQUE, CHECK, FOREIGN KEY 등의 제약 조건이 스키마에 정의됩니다.
2️⃣ 스키마의 종류.
1️⃣ 논리적 스키마(Logical Schema)
데이터베이스의 전체적인 논리적 구조를 나타냅니다.
테이블, 뷰, 인덱스 등의 논리적인 구조를 정의하며, 데이터베이스 사용자들이 데이터를 어떻게 볼지를 설명합니다.
2️⃣ 물리적 스키마(Physical Schema)
데이터가 실제로 데이터베이스에 어떻게 저장되는지를 나타냅니다.
이는 하드웨어 레벨에서 데이터가 저장되는 방식을 설명하며, 데이터 파일, 인덱스 파일 등이 포함됩니다.
3️⃣ 사용자 스키마(User Schema)
특정 사용자에게 보여지는 데이터베이스 구조를 나타냅니다.
일반적으로 사용자는 전체 데이터베이스가 아닌, 특정 뷰나 테이블만 접근할 수 있도록 설정됩니다.
3️⃣ 스키마 예시.
스키마는 SQL을 통해 정의할 수 있으며, 이를 통해 데이터베이스의 구조가 설정됩니다.
예를 들어, 사용자 테이블의 스키마는 다음과 같이 정의할 수 있습니다.
CREATE TABLE Users (
user_id INT PRIMARY KEY, -- 기본 키
username VARCHAR(50) NOT NULL -- NULL을 허용하지 않음
email VARCHAR(100) UNIQUE, -- 고유한 값
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
위 스키마 정의에서는 User 테이블이 생성되며, 다음과 같은 구조를 가집니다.
user_id: 기본 키(Primary Key)로, 고유한 사용자 식별자입니다.
username: 사용자의 이름을 저장하며, NULL을 허용하지 않습니다.
email: 사용자의 이메일을 저장하며, 고유한 값이어야 합니다.
created_at: 사용자가 생성된 시간을 나타내며, 기본값으로 현재 시간을 저장합니다.
4️⃣ 스키마의 역할.
데이터 구조 정의
스키마는 데이터베이스 내의 모든 데이터 구조를 정의합니다.
이는 테이블, 열(Column), 제약 조건 등을 명확하게 정의함으로써 데이터베이스의 일관성을 유지합니다.
데이터 무결성 유지
스키마는 제약 조건과 규칙을 설정하여 데이터의 무결성을 보장합니다.
예를 들어, 외래 키(Foreign Key) 제약 조건은 데이터 간의 참조 무결성을 유지합니다.
데이터베이스 관리
스키마 데이터베이스의 관리를 용이하게 하며, 개발자나 DBA(Database Administrator)가 데이터 구조를 설계하고 유지보수할 수 있도록 돕습니다.
5️⃣ 요약.
스키마(Schema)는 데이터베이스 구조의 설계를 나타내며, 데이터가 어떻게 저장되고 조직되는지를 정의합니다.
테이블(Table), 열(Column), 인덱스(Index), 뷰(View), 제약 조건(Constraints) 등이 스키마에 포함되며, 이를 통해 데이터베이스의 일관성과 무결성을 보장합니다.
스키마(Schema)는 데이터베이스의 논리적 구조를 정의하는 데 매우 중요한 요소이며, 데이터베이스의 효율적인 운영과 관리에 필수적입니다.
-
💾[Database] 데이터베이스 URL이란 무엇일까요?
💾[Database] 데이터베이스 URL이란 무엇일까요?
데이터베이스 URL은 애플리케이션이 데이터베이스에 연결할 때 사용되는 고유한 주소입니다.
URL은 애플리케시연이 데이터베이스 서버를 찾고, 연결할 데이터베이스를 지정하기 위한 정보를 포함하고 있습니다.
이 URL은 데이터베이스 종류에 따라 고유한 형식으로 작성되며, 보통 프로토콜, 서버 위치(호스트), 포트 번호, 데이터베이스 이름 등을 포함합니다.
1️⃣ 데이터베이스 URL의 기본 형식.
데이터베이스 URL은 보통 다음과 같은 형식을 따릅니다.
jdbc:<데이터베이스 유형>://<호스트>:<포트>/<데이터베이스 이름>?<옵션들>
각 부분의 의미는 다음과 같습니다.
jdbc
Java Database Connectivity의 약자로, JDBC URL임을 나타냅니다.
JDBC(Java Database Connectivity)를 사용하여 데이터베이스와 연결하는 표준 방식입니다.
<데이터베이스 유형>
사용하는 데이터베이스의 유형을 나타냅니다.
예를 들어, MySQL, PostgreSQL, Oracle, SQL Server 등이 여기에 들어갑니다.
<호스트>
데이터베이스가 실행되고 있는 서버의 주소를 나타냅니다.
로컬에서 실행될 경우 localhost를 사용하고, 원격 서버의 경우 서버 IP 주소나 도메인 이름을 사용합니다.
<포트>
데이터베이스 서버가 수신 대기 중인 네트워크 포트 번호입니다.
각 데이터베이스는 기본 포트가 있지만, 필요에 따라 다른 포트를 사용할 수도 있습니다.
MySQL: 3306
PostgreSQL: 5432
Oracle: 1521
<데이터베이스 이름>
연결할 데이터베이스의 이름입니다.
같은 데이터베이스 서버에서 여러 데이터베이스를 운영할 수 있으므로, 연결할 데이터베이스를 명시합니다.
<옵션들>
추가적으로 데이터베이스 연결을 위한 옵션을 전달할 수 있습니다.
예를 들어, 인코딩 방식이나 SSL 사용 여부 등의 설정이 여기에 포함될 수 있습니다.
📝 SSL(Secure Socket Layer)
네트워크 상에서 데이터를 안전하게 암호화하여 전송하기 위한 보안 프로토콜입니다.
SSL은 클라이언트와 서버 간의 통신을 암호화하여, 데이터가 전송되는 동안 제3자가 이를 도청하거나 위조하지 못하도록 보호합니다.
SSL은 특히 웹 브라우저와 웹 서버 간의 안전한 통신을 보장하는 데 널리 사용되었습니다.
현재는 SSL의 후속 버전인 TLS(Transport Layer Security)가 SSL을 대체하여 사용되고 있지만, 보통 사람들은 여전히 SSL이라는 용어를 사용해 TLS도 함께 지칭합니다.
2️⃣ 데이터베이스 URL 예시.
1️⃣ MySQL
jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC
mysql : MySQL 데이터베이스 사용
localhost : 데이터베이스 서버의 주소 (로컬에서 실행 중인 경우)
3306 : MySQL의 기본 포트 번호
mydatabase : 연결할 데이터베이스 이름
useSSL=false : SSL 사용 여부 (이 예시에서는 사용하지 않음)
serverTimezone=UTC : 서버의 타임존 설정
2️⃣ PostgreSQL
jdbc:postgresql://localhost:5432/mydatabase
postgresql : PostgreSQL 데이터베이스 사용
localhost : 데이터베이스 서버 주소
5432 : PostgreSQL의 기본 포트 번호
mydatabase : 연결할 데이터베이스 이름
3️⃣ Oracle
jdbc:oracle:thin:@localhost:1521:ORCL
oracle:thin : Oracle의 JDBC 드라이버 사용
localhost : 데이터베이스 서버 주소
1521 : Oracle의 기본 포트 번호
ORCL : 데이터베이스 서비스 이름
4️⃣ SQL Server
jdbc:sqlserver://localhost:1433;databaseName=mydatabase;integratedSecurity=true;
sqlserver : Microsoft SQL Server 사용
localhost : 데이터베이스 서버 주소
1433 : SQL Sever의 기본 포트 번호
mydatabase : 연결할 데이터베이스 이름
integratedSecurity=true : 통합 보안(Windows 인증) 사용
5️⃣ H2(In-Memory Database)
jdbc:h2:mem:testdb
h2:mem : H2 데이터베이스의 메모리 모드 사용
testdb : 메모리 내에서 사용할 데이터베이스 이름
3️⃣ 데이터베이스 URL 사용 방법.
데이터베이스 URL은 주로 Spring Boot와 같은 프레임워크나 JDBC(Java Database Connectivity) API를 통해 데이터베이스에 연결할 때 설정합니다.
예를 들어, Spring Boot에서 application.properties나 application.yml 파일에 데이터베이스 URL을 지정할 수 있습니다.
👉 application.properties에서 데이터베이스 URL 설정.
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=secret
👉 JDBC API로 데이터베이스 연결 예시
String url = "jdbc:mysql://localhost:3306/mydatabase?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "secret";
Connection conn = DriverManager.getConnection(url, username, password);
4️⃣ 데이터베이스 URL의 구성 요소 요약.
프로토콜(JDBC) : jdbc:로 시작하며 JDBC(Java Database Connectivity)를 사용한 데이터베이스 연결을 의미합니다.
데이터베이스 유형 : 사용할 데이터베이스의 종류(MySQL, PostgreSQL, Oracle 등)를 지정합니다.
서버 주소(호스트와 포트) : 데이터베이스 서버의 위치를 나타냅니다(로컬 또는 원격).
데이터베이스 이름 : 연결하려는 데이터베이스의 이름을 지정합니다.
추가 옵션 : SSL 사용, 타임존 설정 등 추가적인 설정이 필요할 때 URL에 포함될 수 있습니다.
5️⃣ 요약.
데이터베이스 URL은 애플리케이션이 데이터베이스에 연결할 때 사용하는 고유한 주소로, 데이터베이스 유형, 서버 주소, 포트 번호, 데이터베이스 이름 등의 정보를 포함하여 연결 설정을 정의합니다.
-
💾[Database] 관계형 데이터베이스(Relational Database, RDB)란 무엇일까요?
💾[Database] 관계형 데이터베이스(Relational Database, RDB)란 무엇일까요?
관계형 데이터베이스(Relational Database, RDB)는 테이블 형식으로 데이터를 저장하고, 테이블 간의 관계를 정의하여 데이터를 관리하는 데이터 모델입니다.
이를 관리하기 위해 데이터베이스 관리 시스템(Database Management System, DBMS)이 사용되며, RDB(Relational Database, 관계형 데이터베이스)를 관리하는 DBMS(Database Management System, 데이터베이스 관리 시스템)는 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)이라고 합니다.
관계형 데이터베이스(Relational Database, RDB)는 데이터를 행(Row)과 열(Column)로 구성된 테이블(Table)에 저장되며, 각 테이블은 서로 관계를 맺어 구조화된 데이터를 관리하고 검색하기 쉽게 합니다.
1️⃣ 관계형 데이터베이스(RDB, Relational Database)의 주요 특징.
1️⃣ 테이블 구조.
관계형 데이터베이스(RDB, Relational Database)는 데이터를 테이블 형태로 저장합니다.
각 테이블은 행(Row)과 열(Column)로 구성되며, 행(Row)은 레코드(Record)라고 하고, 열(Column)은 속성(Attribute) 또는 필드(Field)라고 부릅니다.
예를 들어, “사용자”라는 테이블이 있다면, 각 행(Row)은 사용자 정보(이름, 이메일, 나이 등)를 나타내고, 각 열(Column)은 사용자 정보를 설명하는 속성(Attribute)을 나타냅니다.
2️⃣ 관계.
관계형 데이터베이스(Relational Database, RDB)는 여러 테이블 간의 관계를 정의할 수 있습니다.
키(Key)를 사용해 테이블 간의 관계를 맺고, 데이터를 참조하고 연결할 수 있습니다.
예를 들어, “사용자” 테이블과 “주문” 테이블이 있다고 하면, “사용자” 테이블의 기본 키(Primary Key)가 “주문” 테이블에 외래 키(Foreign Key)로 사용되며, 사용자와 주문 간의 관계를 나타낼 수 있습니다.
3️⃣ 고유한 키(Primary Key).
각 테이블에는 고유한 키(Primary Key)가 있습니다.
이 키는 테이블의 각 레코드(Record)를 유일하게 식별하는 역할을 합니다.
기본 키(Primary Key)는 중복될 수 없으며, 이를 통해 데이터를 정확하게 검색하고 관리할 수 있습니다.
4️⃣ 데이터 무결성 및 일관성.
관계형 데이터베이스(Relational Database, RDB)는 데이터 무결성(Integrity)과 일관성(Consistency)을 유지하도록 설계되었습니다.
이를 통해 데이터의 정확성과 신뢰성을 보장할 수 있습니다.
제약 조건(Constraints)을 통해 데이터의 무결성(Integrity)을 유지합니다.
예를 들어, NOT NULL 제약 조건을 사용하여 특정 열이 항상 값을 가져야 한다는 것을 보장하거나, FOREIGN KEY 제약 조건을 사용해 테이블 간의 관계를 유지합니다.
5️⃣ SQL(Structured Query Language)
관계형 데이터베이스(Relational Database, RDB)는 데이터를 관리하기 위해 SQL(Structured Query Language)이라는 언어를 사용합니다.
SQL(Structured Query Language)은 데이터를 조회, 삽입, 수정, 삭제하는 데 사용되는 표준 언어입니다.
SQL(Structured Query Language)은 관계형 데이터베이스(Relational Database, RDB)에서 데이터 검색과 조작을 위한 강력한 도구입니다.
예: 데이터를 삽입하기 위한 INSERT문, 데이터를 조회하기 위한 SELECT문, 데이터를 수정하기 위한 UPDATE문, 데이터를 삭제하기 위한 DELETE문 등이 있습니다.
2️⃣ 관계형 데이터베이스(Relational Database, RDB)의 구성 요소.
1️⃣ 테이블(Table)
관계형 데이터베이스(Relational Database, RDB)의 기본 단위입니다.
데이터는 행(Row)과 열(Column)로 구성된 테이블에 저장됩니다.
예: 사용자(Users) 테이블, 주문(Order) 테이블
2️⃣ 기본 키(Primary Key)
각 테이블에서 고유하게 레코드를 식별하는 열(Column)입니다.
중복될 수 없으며, 각 행(Row)을 유일하게 구분할 수 있습니다.
예: 사용자 테이블의 user_id 열(Column)은 기본 키(Primary Key)로 사용될 수 있습니다.
3️⃣ 외래 키(Foreign Key)
다른 테이블의 기본 키(Primary Key)를 참조하는 열(Column)로, 테이블 간의 관계를 정의합니다.
외래 키(Foreign Key)는 두 테이블을 연결하는 역할을 하며, 데이터 간의 일관성을 유지하는 데 도움을 줍니다.
예: 주문(Orders) 테이블에서 user_id 열이 사용자(Users) 테이블의 user_id를 참조하는 경우, 이를 외래키(Foreign Key)라고 합니다.
4️⃣ 속성(Attribute)
테이블의 열(Column)을 의미하며, 각 속성(Attribute)은 특정 유형의 데이터를 저장합니다.
예를 들어, 사용자 테이블에서 name, email, age와 같은 속성이 있을 수 있습니다.
5️⃣ 레코드(Record)
테이블의 행(Row)을 의미하며, 하나의 레코드는 테이블에 저장된 데이터의 한 항목을 나타냅니다.
예를 들어, 사용자 테이블의 한 행(Row)은 한 사용자의 정보를 나타냅니다.
3️⃣ 관계형 데이터베이스(Relational Database, RDB)의 예시.
예를 들어, 전자상거래 웹사이트를 위한 데이터베이스를 설계한다고 가정해봅시다.
여기에는 사용자와 주문 정보를 저장하기 위해 두 개의 테이블이 있을 수 있습니다.
1️⃣ 사용자(Users) 테이블.
user_id(기본 키, Primary Key)
name`
email
address
2️⃣ 주문(Orders) 테이블.
order_id(기본 키, Primary Key)
user_id(외래 키, Foreign Key, 사용자와의 관계를 나타냄)
product
quantity
3️⃣ 설명.
이 예에서, 사용자 테이블과 주문 테이블은 user_id를 통해 관계를 맺고 있습니다.
이를 통해 특정 사용자가 어떤 주문을 했는지 쉽게 조회할 수 있습니다.
4️⃣ 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)의 예.
MySQL
오픈 소스 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)으로, 웹 애플리케이션에서 많이 사용됩니다.
PostgreSQL
오픈 소스 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)로, 확장성과 표준 준수에 중점을 둔 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)입니다.
Oracle
대규모 상업용 데이터베이스로, 높은 성능과 보안성을 자랑하는 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)입니다.
Microsoft SQL Server
마이크로소프트에서 개발한 관계형 데이터베이스 관리시스템(RDBMS, Relational Database Management System)으로, 기업 환경에서 많이 사용됩니다.
5️⃣ 관계형 데이터베이스(Relational Database, RDB)의 장점.
1️⃣ 데이터 무결성 보장.
관계형 데이터베이스(Relational Database, RDB)는 제약 조건(Constraints)을 통해 데이터의 무결성을 보장합니다.
예를 들어, 외래 키(Foreign key)를 통해 테이블 간의 참조 무결성을 유지하고, 데이터의 일관성을 확보합니다.
2️⃣ SQL을 통한 데이터 관리.
관계형 데이터베이스(Relational Database)는 SQL(Structured Query Language)이라는 표준 언어를 사용하여 데이터를 검색, 삽입, 수정, 삭제할 수 있습니다.
SQL은 관계형 데이터베이스에서 데이터를 쉽게 관리할 수 있도록 해줍니다.
3️⃣ 데이터 중복 최소화.
관계형 데이터베이스(Relational Database, RDB)는 데이터를 여러 테이블로 나누고, 중복을 최소화하여 저장합니다.
이로 인해 데이터 저장소의 효율성이 증가하고, 데이터 일관성을 유지할 수 있습니다.
4️⃣ 데이터 보안.
관계형 데이터베이스(Relational Database, RDB)는 사용자 권한을 관리하여, 데이터에 대한 접근을 제어하고 보안을 강화할 수 있습니다.
6️⃣ 관계형 데이터베이스의 단점.
1️⃣ 복잡한 구조.
데이터가 여러 테이블에 분산되어 저장되기 때문에, 데이터의 구조가 복잡해질 수 있습니다.
특히, 데이터간의 관계가 많아질수록 관리와 설계가 어려워질 수 있습니다.
2️⃣ 확장성의 한계.
관계형 데이터베이스(Relational Database, RDB)는 데이터의 수평적 확장(데이터를 여러 서버로 나누어 저장)이 어려운 경우가 많습니다.
데이터가 크고 관계가 복잡할수록 확장성과 성능에 제약이 있을 수 있습니다.
3️⃣ 고정된 스키마.
관계형 데이터베이스(Relational Database, RDB)는 고정된 스키마를 사용합니다.
즉, 테이블 구조(열(Row)의 수와 이름 등)가 정해진 후, 이를 변경하기 어렵습니다.
데이터 구조가 자주 변경되는 경우 유연성이 떨어질 수 있습니다.
7️⃣ 관계형 데이터베이스(Relational Database, RDB)와 NoSQL 데이터베이스의 차이.
1️⃣ 관계형 데이터베이스(Relational Database, RDB)
데이터를 테이블 형태로 저장하며, 테이블 간의 관계를 정의합니다.
SQL(Structured Query Language)을 사용하여 데이터를 관리합니다.
일관성과 무결성을 중요하게 다루며, 고정된 스키마 구조를 가집니다.
2️⃣ NoSQL 데이터베이스
데이터를 유연한 구조로 저장하며, 문서(Document), 키-값(Key-Value), 그래프(Graph) 등 다양한 방식으로 데이터를 저장할 수 있습니다.
스키마가 유연하여 데이터 구조가 자주 변경될 때 유리합니다.
관계형 데이터베이스(Relational Database, RDB)에 비해 수평적 확장이 용이하며, 대규모 분산 시스템에 적합합니다.
8️⃣ 결론.
관계형 데이터베이스(Relational Database, RDB)는 데이터를 테이블 형태로 저장하고, 여러 테이블 간의 관계를 정의하여 데이터를 효율적으로 관리하는 데이터베이스 관리 시스템입니다.
SQL을 사용해 데이터를 관리하며, 데이터 무결성과 일관성을 유지하는 데 강점을 가집니다.
대표적인 관계형 데이터베이스로는 MySQL, PostgreSQL, Oracle 등이 있으며, 복잡한 관계를 가지는 정형 데이터 관리에 적합합니다.
-
💾[Database] 데이터베이스에서 테이블을 만든다는 의미는 무엇일까?
💾[Database] 데이터베이스에서 테이블을 만든다는 의미는 무엇일까?
데이터베이스에서 테이블을 만든다는 것은, 데이터를 저장할 구조를 정의하는 것을 의미합니다.
테이블은 데이터베이스 내에서 정보를 저장하는 기본 단위로, 행(Row) 과 열(Column) 로 구성된 표(Table) 형태로 관리합니다.
1️⃣ 테이블 생성의 의미.
1. 데이터 구조의 정의.
테이블을 만든다는 것은 특정 유형의 데이터를 저장할 수 있는 데이터 구조를 정의하는 것입니다.
각 열(Column)은 저장될 데이터의 속성을 나타내며, 각 행(Row)은 데이터의 개별 항목(레코드) 나타냅니다.
예를 들어, Users 테이블을 만든다면 사용자에 대한 정보를 저장할 수 있도록, 이름, 이메일, 나이와 같은 속성을 정의하는 것입니다.
2. 데이터 타입 설정.
테이블의 각 열(Column)은 특정 데이터 타입을 가집니다.
데이터 타입은 해당 열(Column)에 어떤 종류의 데이터가 저장될 수 있는지를 결정합니다.
예를 들어, name 열(Column)은 문자열 데이터를 저장하고 age 열(Column)은 숫자 데이터를 저장할 수 있습니다.
3. 제약 조건 설정.
테이블 생성 시, 제약 조건을 설정하여 데이터의 무결성을 보장할 수 있습니다.
예를 들어, 기본 키(Primary Key)를 설정하여 각 레코드를 고유하게 식별하거나, 특정 열(Column)에 NOT NULL 제약을 걸어 해당 열(Column)이 비어 있을 수 없도록 설정할 수 있습니다.
2️⃣ 예시: 테이블 생성.
CREATE TABLE Users (
id INT KEY, -- Primary Key: 각 사용자를 고유하게 식별
name VARCHAR(100) NOT NULL, -- 이름: 문자열, null 값을 허용하지 않음
email VARCHAR(100) UNIQUE, -- 이메일: 고유한 문자열
age INT, -- 나이: 정수
created_at TIMESTAMP -- 생성 시간: 타임스탬프
);
위의 SQL 예시는 Users라는 테이블을 정의하는 것입니다.
테이블이 정의되면 해당 구조에 맞게 데이터를 저장할 수 있습니다.
id 열은 정수형 데이터 타입으로, 각 사용자를 고유하게 식별하는 기본 키(Primary Key)입니다.
name 열은 VARCHAR(100) 데이터 타입으로 최대 100자의 문자열을 저장하며, null 값을 허용하지 않습니다.
email 열은 UNIQUE 제약을 가집니다. 즉, 테이블 내에서 중복된 이메일이 저장될 수 없습니다.
age 열은 정수형 데이터를 저장할 수 있습니다.
created_at 열은 타임스탬프로, 데이터가 생성된 시간을 기록하는 열입니다.
3️⃣ 테이블 생성의 목적
1. 데이터 저장 및 관리.
테이블을 생성하면, 해당 구조에 맞게 데이터를 저장할 수 있습니다.
각 행(Row)은 하나의 레코드를 나타내며, 테이블에 정의된 각 열(Column)은 그 레코드의 속성을 나타냅니다.
2. 데이터 무결성 보장.
테이블을 생성할 때 정의하는 제약 조건(Primary Key, Foreign Key, Unique, Not Null 등)은 데이터의 정확성과 일관성을 보장합니다.
3. 효율적인 데이터 조회.
테이블을 통해 데이터를 구조화하여 저장하면, SQL 쿼리를 통해 효율적으로 데이터를 검색, 수정, 삭제할 수 있습니다.
적절한 인덱스와 관계 설정을 통해 데이터베이스 성능을 최적화할 수 있습니다.
4️⃣ 테이블을 만든 후
테이블을 만든 후, 해당 테이블에 데이터를 삽입하고, 필요에 따라 데이터를 조회, 수정, 삭제할 수 있습니다.
테이블은 데이터베이스에서 데이터를 논리적으로 그룹화하고 관리하는 핵심적인 역할을 합니다.
-
💾[Database] 데이터베이스 모델링.
💾[Database] 데이터베이스 모델링.
1️⃣ 정보 시스템 구축의 개요.
정보 시스템을 구축하기 위해서는 일반적으로 “분석-설계-구현-시험-유지.보수”라는 5단계를 거칩니다.
분석은 프로젝트의 첫 번째 단계로 시스템 분석 또는 요구 사항 분석이라고도 합니다.
요구 사항 분석은 ‘무엇을(what)’할지 결정하는 것으로, 이 단계에는 사용자 인터뷰와 업무 조사 등을 수행합니다.
분석은 프로젝트의 첫 단추를 끼우는 중요한 단계이므로 당연히 많은 시간 동안 심혈을 기울여야 합니다.
두 번째로 설계 단계는 시스템 설계 또는 프로그램 설계라고도 하며, 구축하고자 하는 시스템을 ‘어떻게(how)’ 설계할 것인지 결정합니다.
설계 단계가 끝나면 그 결과 문서를 프로그래머(또는 코더)에게 넘겨주고, 프로그래머는 설계서에 있는 대로 프로그램을 작성하기만 하면 됩니다.
따라서 일반적으로는 시스템 설계가 끝나면 가장 큰 작업을 마친 것으로 여깁니다.
대부분의 프로젝트에서는 분석과 설계 단계가 전체 공정의 50% 이상을 차지합니다.
2️⃣ 데이터베이스 모델링과 필수 용어.
데이터베이스 모델링이란 현실 세계에서 사용되는 데이터를 MySQL에 어떻게 옮겨놓을지 결정하는 과정으로, 정보 시스템 구축 시 분석과 설계 단계에서 가장 중요한 작업 중 하나입니다.
인터넷 쇼핑몰을 생각해봅시다.
인터넷 쇼핑몰에는 사람(또는 회원)이 필요합니다.
그렇다면 이 사람을 어떻게 MySQL에 넣을까요?
데이터베이스에서는 사람을 나타내는 여러 가지 특성(속성)을 추출하여 저장합니다.
어떤 사람의 신분을 증명하는 신분증에 이름, 주민등록번호, 주소 등의 정보가 있는 것과 비슷한 개념입니다.
일상 생활에서 판매하는 제품도 마찬가지입니다.
제품 자체를 컴퓨터에 넣을 수는 없으니 제품명, 가격, 제조일, 제조사, 남은 수량 등을 저장합니다.
이때 정보가 단편적으로 저장되는 것이 아니라 테이블이라는 형식에 맞춰 저장됩니다.
지금까지 설명한 사람과 제품에 관한 정보를 테이블에 구현하면 다음 그림과 같습니다.
테이블의 구조와 관련 용어.
데이터.
토마스, 컴퓨터, 2019-07-01과 같이 테이블에 저장된 하나하나의 단편적인 정보를 데이터라고 합니다.
즉 정보는 있으나 아직 체계화되지 않은 상태입니다.
테이블.
회원이나 제품의 데이터를 입력하기 위해 표 형태로 만든 것을 말합니다.
위 그림에서는 인터넷 쇼핑몰을 구현하기 위해 회원 정보를 보관할 회원 테이블과 제품 정보를 보관할 제품 테이블을 합쳐서 총 2개의 테이블을 만들었습니다.
데이터베이스.
테이블이 저장되는 저장소로, 위 그림과 같이 원통 모양으로 표현합니다.
위 그림에는 3개의 데이터베이스가 있으며, 각 데이터베이스는 각각의 고유한 이름을 가지고 있습니다.
DBMS.
DataBase Management System의 약자로, 데이터베이스를 관리하는 시스템 또는 소프트웨어를 말합니다.
예를 들어 MySQL과 같은 것이 DBMS이다.
위 그림에서는 DBMS가 3개의 데이터베이스를 관리하고 있습니다.
열(필드).
각 테이블은 열(Column)로, 구성됩니다.
위 그림의 회원 테이블은 ‘아이디’, ‘회원 이름’, ‘주소’라는 3개의 열로 구성되어 있습니다.
데이터 형식.
열의 데이터 형식을 말합니다.
회원 테이블의 회원 이름 열은 당연히 숫자가 아닌 문자 형식이어야 합니다.
또한 제품 테이블의 가격 열은 숫자(특히 정수) 형식이어야 합니다.
가격에 ‘고가’같은 글자가 들어가서는 안 되기 때문입니다.
데이터 형식은 테이블을 생성할 때 열 이름과 함꼐 지정합니다.
행(레코드).
실질적인 데이터를 말합니다.
회원 테이블의 ‘Thomas/토마스/경기도 부천시 중동’은 하나의 행으로 ‘행 데이터’라고도 부릅니다.
행(Row)은 회원 테이블에서 회원이 몇 명인지, 행 데이터가 몇 개 있는지와 동일한 의미입니다.
회원 테이블의 행은 4개, 즉 4명의 회원이 존재합니다.
기본키(주키).
기본키는 각 행을 구분하는 유일한 열을 말합니다.
기본키는 중복되면 안 되고 비어 있어서도 안 됩니다.
또한 각 테이블에는 기본키가 하나만 지정되어 있어야 합니다.
회원 테이블의 기본키는 아이디 열에 지정되어 있는데, 만약 기본키를 회원 이름 열에 지정하면 어떻게 될까요?
기본키는 각 행을 구분하는 유일한 열이라고 했는데, ‘토마스’라는 이름만으로 그 사람이 경기도 부천시 중동에 산다는 것을 확신할 수 있나요?
만약 ‘토마스’라는 이름이 또 있다면?
현실적으로 같은 이름을 가진 사람이 있을 수 있기 때문에 회원 이름 열은 기본키로 지정하기에 부적합합니다.
그렇다면 주소 열은 어떨까요?
마찬가지로 주소만 가지고 유일한 사람이라고 단정지을 수 없습니다.
같은 집에 여러 사람이 살 수도 있기 때문입니다.
마지막의 아이디 열은 어떤가요?
쇼핑몰 사이트에 가입해봤다면 회원 가입을 할 때 아이디를 만들면서 버튼을 클릭해본 경험이 있을 것 입니다.
즉 아이디는 중복되지 않게 지정해야 합니다.
또한 쇼핑몰 사이트에 회원 가입을 할 때 아이디를 만들지 않고는 가입할 수 없습니다.
결국 모든 회원은 아이디를 가지고 있고 모든 회원의 아이디가 각각 다르기 때문에 아이디는 기본키로 지정하기에 매우 적절합니다.
한편 회원 테이블에 주민등록번호나 이메일 열이 있다면 역시 중복되지 않고 비어있지도 않으므로 기본키로 지정할 수 있습니다.
외래키
위 그림에서는 나타나 있지 않지만 외래키는 두 테이블의 관계를 맺어주는 키를 말합니다.
SQL(구조화된 질의 언어)
DBMS에서 어떤 작업을 하고 싶다면 어떻게 해야 할까요?
사람끼리 주고 받는 언어로 말할 수는 없습니다.
DBMS에서 어떤 작업을 하고 싶다면 DBMS가 알아듣는 말로 해야 할 텐데, 이때 사용하는 것이 바로 SQL입니다.
SQL은 사람과 DBMS가 소통하기 위한 말(언어)입니다.
-
-
-
💾[Database] 데이터베이스의 정의와 특징.
💾[Database] 데이터베이스의 정의와 특징.
1️⃣ 데이터베이스 : 여러 사용자나 응용 프로그램이 공유하고 동시에 접근 가능한 ‘데이터의 집합’ 이라고 정의할 수 있습니다.
2️⃣ DBMS(DataBase Management System) : ‘데이터베이스’를 ‘관리,운영하는 소프트웨어’ 입니다.
🙋♂️ 데이터베이스
‘데이터 저장 공간’ 자체를 의미하기도 합니다.
DBMS 중 하나인 MySQL에서는 ‘데이터베이스’를 ‘자료가 저장되는 디스크 공간(주로 파일로 구성됨)’으로 취급합니다.
위 그림은 데이터베이스, DBMS, 사용자, 응용 프로그램의 관계를 보여줍니다.
위 그림에서 보듯이 DBMS는 데이터베이스를 관리하는 역할을 하는 소프트웨어입니다.
여러 사용자나 응용 프로그램은 DBMS가 관리하는 데이터에 동시에 접속하여 데이터를 공유합니다.
👉 즉, DBMS에서는 데이터베이스에서 사용되는 데이터가 집중 관리됩니다.
🙋♂️ 데이터베이스와 DBMS
데이터베이스를 DBMS와 혼용해서 같은 용어처럼 사용하는 경우도 흔히 있습니다.
바라보는 시각에 따라 그렇게 사용하는 것이 틀린 것은 아니지만
저는 데이터베이스를 ‘데이터의 집합’ 또는 ‘데이터의 저장 공간’으로 보고,
DBMS는 데이터베이스를 운영하는 ‘소프트웨어’라는 의미로 공부하겠습니다.
DBMS에는 MySQL 외에도 많은 종류의 프로그램이 있습니다.
MySQL
MariaDB
PostgreSQL
Oracle
SQL Server
DB2
Access
SQLite
…
🙋♂️ 위 명시된 리스트는 2018년 기준 많이 사용되는 DBMS입니다.
3️⃣ DBMS 또는 데이터베이스의 몇 가지 중요한 특징.
👉 데이터 무결성
데이터베이스 안의 데이터는 어떤 경로를 통해 들어왔든 오류가 있어서는 안 되는데 이를 무결성(Integrity)이라고 합니다.
무결성을 지키기 위해 데이터베이스는 제약 조건(constraint)을 따릅니다.
예를 들어 학생 데이터에서 모든 학생은 학번이 반드시 있어야 하고 학번이 중복되면 안 된다는 제약 조건을 생각해봅시다.
이 제약 조건을 충실히 지킨다면 학번으로도 학번으로도 학생 데이터에서 학생을 정확히 찾을 수 있습니다.
즉, 학번은 무결한 데이터를 보장하는 요소이며, 자동 발급기로 성적 증명서나 재학 증명서를 뗄 떼 학번만 조회해도 정확한 자료를 줄력할 수 있습니다.
👉 데이터의 독립성
데이터베이스의 크기를 변경하거나 데이터 파일의 저장소를 변경하더라도 기존에 작성된 응용 프로그램은 전혀 영향을 받지 않습니다.
즉 데이터베이스와 응용 프로그램은 서로 의존적인 관계가 아니라 독립적인 관계입니다.
예를 들어 데이터베이스가 저장된 디스크가 새것으로 변경되어도 기존에 사용하던 응용 프로그램은 아무런 변경 없이 계속 사용할 수 있습니다.
👉 보안
데이터베이스 안에 데이터는 아무나 접근할 수 있는 것이 아니라 데이터를 소유한 사람이나 데이터에 접근이 허가된 사람만 접근할 수 있습니다.
또한, 같은 데이터에 접근할 때도 사용자의 계정에 따라서 각각 다른 권한을 갖습니다.
최근 들어 고객 정보 유출 사고가 빈번하여 보안(Security)은 데이터베이스에서 더욱 중요한 이슈가 되고 있습니다.
👉 데이터 중복 최소화
데이터베이스에서는 동일한 데이터가 여러 군데 중복 저장되는 것을 방지합니다.
학교를 예로 들면, 학생 정보를 이용하는 교직원들(학생처, 교무처, 과사무실 등)이 각 직원마다 별도의 엑셀 파일로 학생 정보를 관리하면 한 명의 학생 정보가 각각의 엑셀 파일에 중복 저장됩니다.
그러나 데이터베이스에 통합하여 관리하면 하나의 테이블에 데이터를 저장한 후 응용 프로그램마다 이를 공유하여 사용할 수 있어 데이터의 중복을 최소화할 수 있습니다.
👉 응용 프로그램 제작 및 수정 용이
기존 파일 시스템에서는 각각의 파일 포맷에 맞춰 응용 프로그램을 개발했습니다.
그러나 데이터베이스를 이용하면 통일된 방식으로 응용 프로그램을 작성할 수 있고 유지,보수 또한 쉽습니다.
👉 데이터의 안전성 향상
대부분의 DBMS는 데이터의 백업/복원 기능을 제공합니다.
따라서 데이터가 손상되는 문제가 발생하더라도 원래의 상태로 복원 또는 복구할 수 있습니다.
Touch background to close