1. UUID (Universally Unique IDentifier) ??
범용 고유 식별자는 네트워크 상에서 중복되지 않는 식별자를 만들기 위한 표준 규약이다. GUID(전역적으로
고유 식별자)라고도 부르며 RFC4122 로 지정되어 있다. UUID는 아래와 같은 규칙을 기반으로 생성된다.
- UUID 는 128bit(16 octec) 수이다. 32개의 16진수로 표현되며, 하이픈(-)을 포함해 총 36개 문자로 구성되어 있다.
- UUID 는 8-4-4-4-12 형태로 총 5개의 그룹이며 하이픈(-) 을 기준으로 구분되어 있다.
이름 | 길이(byte) | 길이(hex) | 길이(bits) | 내용 |
time_low | 4 | 8 | 32 | 시간의 low 32bit 를 부여하는 정수 |
time_mid | 2 | 4 | 16 | 시간의 middle 16bit 를 부여하는 정수 |
time_hi_and_version | 2 | 4 | 16 | 최상위 비트에서 4bit 는 version, 12 bit는 시간의 high |
clock_seq_hi_and_res_clock_seq_low | 2 | 4 | 16 | 최상위 비트에서 1-3 bit 는 UUID 레이아웃 형식 13-15 bit는 clock sequcne |
node | 6 | 12 | 48 | 48bit 는 node_id |

2. Time based UUID
[1] Time Based UUID version
- UUID version 1 : gregorian epoch 기반의 time-based version (ordered X)
- UUID version 6 : gregorian epoch 기반의 time-ordered version
- UUID version 7 : Unix Epoch timestamp 기반의 time-ordered version
Time-based UUID structure
00000000-0000-v000-m000-000000000000
|1-----------------------|2-----|3--------------|
1: timestamp
2: clock-sequence
3: node identifier
[2] Time Based UUID 의 장점
RDB clustered index rebalancing : MySQL 은 PK 를 기반으로 clustered index 를 생성한다. clustered index 는 PK 를 기반으로 정렬된다. 만약 정렬되지 않은 값이 삽입될 경우, 이후 인덱스의 데이터 페이지를 다시 재정렬해야 하는 경우가 발생한다. 이를 index rebalancing 이라 부르며, 운영 환경에서 index rebalaning 이 이루어지는 경우 오히려 성능이 떨어질 수 있는 위험이 있다.
흔히 사용하는 UUID version4 를 사용하는 경우 데이터를 삽입하는 경우, 데이터 페이지를 다시 정렬해야 하므로 index rebalancing 을 해야 되어 성능상이 이슈가 발생할 수 있다. 반면 time-based ordered uuid 는 데이터를 추가하더라도 마지막 데이터 페이지에 추가되므로 index rebalancing 이 되지 않아 성능상 이점이 있다.

3. JPA 에 UUID version7 을 적용.
implementation 'com.fasterxml.uuid:java-uuid-generator:4.3.0'
// UUID Version 7: 01870603-f211-7b9a-a7ea-4a98f5320ff8
System.out.println("UUID Version 7: " + UuidCreator.getTimeOrderedEpoch());
[1] Spring Boot 2.x
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import com.github.f4b6a3.uuid.UuidCreator;
public class UuidV7Generator implements IdentifierGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object o)
throws HibernateException {
return UuidCreator.getTimeOrderedEpoch();
}
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(generator = "uuidV7")
@GenericGenerator(name = "uuidV7",
strategy = "com.cooper.common.data.generator.UuidV7Generator")
@Column(columnDefinition = "BINARY(16)")
private UUID id;
...
}
[2] Spring Boot 3.x
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
import java.util.EnumSet;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.EventType;
import com.github.f4b6a3.uuid.UuidCreator;
public class UnixEpochTimeOrderedIdGenerator implements BeforeExecutionGenerator {
@Override
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue,
EventType eventType) {
return UuidCreator.getTimeOrderedEpoch();
}
@Override
public EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
}
@IdGeneratorType(UnixEpochTimeOrderedIdGenerator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE } )
@Inherited
public @interface UnixTimeOrderedUuidGeneratedValue {
}
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@UnixTimeOrderedUuidGeneratedValue
@Column(columnDefinition = "BINARY(16)")
@Getter
private UUID id;
...
}
Reference
'spring > summary' 카테고리의 다른 글
[Spring Batch] Job 실행 프로퍼티, JobParameter, Scope (0) | 2024.08.26 |
---|---|
Spring Batch Architecture (0) | 2024.05.10 |
hibernate.query.in_clause_parameter_padding = true ? (1) | 2024.03.06 |
[Spring] Spring AOP 동작 알아보기 (0) | 2024.03.04 |
[JPA] 코드로 보는 OSIV 와 고찰 (2) | 2024.01.30 |
1. UUID (Universally Unique IDentifier) ??
범용 고유 식별자는 네트워크 상에서 중복되지 않는 식별자를 만들기 위한 표준 규약이다. GUID(전역적으로
고유 식별자)라고도 부르며 RFC4122 로 지정되어 있다. UUID는 아래와 같은 규칙을 기반으로 생성된다.
- UUID 는 128bit(16 octec) 수이다. 32개의 16진수로 표현되며, 하이픈(-)을 포함해 총 36개 문자로 구성되어 있다.
- UUID 는 8-4-4-4-12 형태로 총 5개의 그룹이며 하이픈(-) 을 기준으로 구분되어 있다.
이름 | 길이(byte) | 길이(hex) | 길이(bits) | 내용 |
time_low | 4 | 8 | 32 | 시간의 low 32bit 를 부여하는 정수 |
time_mid | 2 | 4 | 16 | 시간의 middle 16bit 를 부여하는 정수 |
time_hi_and_version | 2 | 4 | 16 | 최상위 비트에서 4bit 는 version, 12 bit는 시간의 high |
clock_seq_hi_and_res_clock_seq_low | 2 | 4 | 16 | 최상위 비트에서 1-3 bit 는 UUID 레이아웃 형식 13-15 bit는 clock sequcne |
node | 6 | 12 | 48 | 48bit 는 node_id |

2. Time based UUID
[1] Time Based UUID version
- UUID version 1 : gregorian epoch 기반의 time-based version (ordered X)
- UUID version 6 : gregorian epoch 기반의 time-ordered version
- UUID version 7 : Unix Epoch timestamp 기반의 time-ordered version
Time-based UUID structure
00000000-0000-v000-m000-000000000000
|1-----------------------|2-----|3--------------|
1: timestamp
2: clock-sequence
3: node identifier
[2] Time Based UUID 의 장점
RDB clustered index rebalancing : MySQL 은 PK 를 기반으로 clustered index 를 생성한다. clustered index 는 PK 를 기반으로 정렬된다. 만약 정렬되지 않은 값이 삽입될 경우, 이후 인덱스의 데이터 페이지를 다시 재정렬해야 하는 경우가 발생한다. 이를 index rebalancing 이라 부르며, 운영 환경에서 index rebalaning 이 이루어지는 경우 오히려 성능이 떨어질 수 있는 위험이 있다.
흔히 사용하는 UUID version4 를 사용하는 경우 데이터를 삽입하는 경우, 데이터 페이지를 다시 정렬해야 하므로 index rebalancing 을 해야 되어 성능상이 이슈가 발생할 수 있다. 반면 time-based ordered uuid 는 데이터를 추가하더라도 마지막 데이터 페이지에 추가되므로 index rebalancing 이 되지 않아 성능상 이점이 있다.

3. JPA 에 UUID version7 을 적용.
implementation 'com.fasterxml.uuid:java-uuid-generator:4.3.0'
// UUID Version 7: 01870603-f211-7b9a-a7ea-4a98f5320ff8
System.out.println("UUID Version 7: " + UuidCreator.getTimeOrderedEpoch());
[1] Spring Boot 2.x
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import com.github.f4b6a3.uuid.UuidCreator;
public class UuidV7Generator implements IdentifierGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object o)
throws HibernateException {
return UuidCreator.getTimeOrderedEpoch();
}
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(generator = "uuidV7")
@GenericGenerator(name = "uuidV7",
strategy = "com.cooper.common.data.generator.UuidV7Generator")
@Column(columnDefinition = "BINARY(16)")
private UUID id;
...
}
[2] Spring Boot 3.x
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
import java.util.EnumSet;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.EventType;
import com.github.f4b6a3.uuid.UuidCreator;
public class UnixEpochTimeOrderedIdGenerator implements BeforeExecutionGenerator {
@Override
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue,
EventType eventType) {
return UuidCreator.getTimeOrderedEpoch();
}
@Override
public EnumSet<EventType> getEventTypes() {
return INSERT_ONLY;
}
}
@IdGeneratorType(UnixEpochTimeOrderedIdGenerator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE } )
@Inherited
public @interface UnixTimeOrderedUuidGeneratedValue {
}
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@UnixTimeOrderedUuidGeneratedValue
@Column(columnDefinition = "BINARY(16)")
@Getter
private UUID id;
...
}
Reference
'spring > summary' 카테고리의 다른 글
[Spring Batch] Job 실행 프로퍼티, JobParameter, Scope (0) | 2024.08.26 |
---|---|
Spring Batch Architecture (0) | 2024.05.10 |
hibernate.query.in_clause_parameter_padding = true ? (1) | 2024.03.06 |
[Spring] Spring AOP 동작 알아보기 (0) | 2024.03.04 |
[JPA] 코드로 보는 OSIV 와 고찰 (2) | 2024.01.30 |