uuidv7 | rfc 9562 | 시간순 정렬 가능

> uuidv7 generator <

// 시간순으로 정렬 가능한 UUID(RFC 9562, 2024) — 48비트 Unix 밀리초 타임스탬프 + 74비트 랜덤, 로컬에서 생성

// UUIDV7 디코딩 / 검사

아래에 임의의 UUID를 붙여넣으면 내장된 타임스탬프, 버전, 변형을 추출합니다. v7과 함께 작동하며 입력이 다른 UUID 버전인 경우 이를 보고합니다.

타임스탬프 (ms): // 디코딩된 필드가 여기에 표시됩니다
ISO 8601 UTC: // 디코딩된 필드가 여기에 표시됩니다
경과 시간: // 디코딩된 필드가 여기에 표시됩니다
버전: // 디코딩된 필드가 여기에 표시됩니다
변형: // 디코딩된 필드가 여기에 표시됩니다
rand_a (12비트): // 디코딩된 필드가 여기에 표시됩니다
rand_b (62비트): // 디코딩된 필드가 여기에 표시됩니다
[RFC 9562]

사양 준수 UUIDv7

RFC 9562(2024년 5월)의 시간순 정렬 UUID 형식을 구현합니다: 48비트 Unix 밀리초 타임스탬프, 4비트 버전 7, 12비트 rand_a, 2비트 변형, 62비트 rand_b. 사양의 테스트 벡터에 대해 검증되었습니다.

[SORTABLE]

시간순 정렬 순서

숫자 또는 사전순으로 정렬하면 삽입 순서가 나옵니다 — B-트리 기본 키, 시계열 인덱스, 로그 상관관계에 완벽합니다. 더 이상 무작위 v4 페이지 분할이나 단편화된 인덱스가 없습니다.

[MONOTONIC]

동일 밀리초 내 단조성

여러 UUID가 한 밀리초에 몰릴 때, 출력이 그 ms 내에서 정렬된 상태를 유지하도록 랜덤 부분이 엄격하게 증가됩니다. 원하시면 일반 RFC 9562 방법 1(랜덤 채우기)을 위해 끌 수 있습니다.

[DECODER]

임의의 UUIDv7 검사

v7 UUID를 붙여넣으면 디코더가 내장된 타임스탬프(ms + ISO 8601), 버전 비트, 변형 비트, rand_a / rand_b 필드를 추출합니다. 디버깅, 로그 분석, 감사 추적에 유용합니다.

// UUIDV7 정보

UUIDv7 작동 방식:

UUIDv7은 unix_ts_ms (48) | ver (4) | rand_a (12) | var (2) | rand_b (62) 형태로 배치된 128비트 식별자입니다. 처음 48비트는 밀리초 단위의 현재 Unix 타임스탬프(빅엔디언)로, 이로 인해 UUID는 시간에 따라 단조 증가합니다. 다음 4비트는 버전을 인코딩하며(2진수 0111 = 10진수 7), 따라서 하이픈으로 구분된 세 번째 그룹은 항상 숫자 7로 시작합니다. rand_a는 서브 밀리초 해상도 또는 추가 엔트로피로 사용되는 12개의 랜덤 비트입니다. 2비트 변형 필드는 10으로 고정됩니다(따라서 네 번째 그룹의 첫 문자는 항상 8, 9, a, b 중 하나입니다). 나머지 62비트(rand_b)는 생성할 때마다 crypto.getRandomValues()에서 나옵니다. UUID당 총 엔트로피는 74개의 랜덤 비트로, 어떤 현실적인 생성 속도에서도 충돌에 강합니다.

예시:

018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55 (ts=2024-05-08T15:00:00.000Z)

표준 및 참고 자료:

  • >RFC 9562 — Universally Unique IDentifiers (UUIDs), 2024년 5월(RFC 4122를 대체, v6/v7/v8 정의)
  • >RFC 4122 — 2005년의 원래 UUID 사양(v1~v5에 대해서는 여전히 권위 있음)
  • >Web Crypto API(W3C) — 74개의 랜덤 비트에 사용되는 crypto.getRandomValues() CSPRNG
  • >PostgreSQL gen_random_uuid() 동작(기본값은 v4, pgcrypto 확장 / 포크에서는 v7)
  • >draft-peabody-dispatch-new-uuid-format — RFC 9562이 된 원래 v6/v7/v8 제안

UUIDv7을 사용하는 이유:

  • >삽입 지역성을 가진 데이터베이스 기본 키 — 페이지가 빽빽하게 유지되고 인덱스가 단편화되지 않습니다
  • >시퀀스 + UUID 쌍을 대체: 하나의 열로 정렬 가능하면서 전역적으로 고유
  • >쓰기가 많은 테이블의 v4 기본 키를 대체하여 무작위 삽입 페이지 분할 문제를 해결합니다
  • >별도의 타임스탬프 열 없이 생성 시간순으로 정렬되는 로그 상관관계 ID
  • >여러 작성자가 코디네이터 없이 순서가 있는 ID를 필요로 하는 분산 시스템
  • >시간순이 자연스러운 인덱스가 되는 이벤트 소싱 / 추가 전용 로그
  • >접두사 정렬이 삽입 순서와 일치하는 S3 / 객체 스토리지 키
  • >표준 형식이 선호되는 경우 Snowflake / KSUID / ULID을 대체

관련 도구:

// 출력 예시

지금 생성된 단일 UUIDv7

config: count=1, format=standard, timestamp=current

output:

018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55

동일 밀리초 내 단조성을 가진 대량 배치

config: count=5, format=standard, monotonic=on

output:

018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55
018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a56
018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a57
018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a58
018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a59

사용자 지정 과거 타임스탬프 — 마이그레이션 백필

config: count=1, timestamp=custom, value=1577836800000 (2020-01-01)

output:

016f5e66-e800-7c9a-b403-2f1d4a7c91ee

URL / 파일 이름용 압축 형식

config: count=1, format=no-hyphens

output:

018f5c2e90c07a4fb6ee8dfe3c2b0a55

디코딩된 UUIDv7 — 내장 필드 검사

config: input = 018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55

output:

ts_ms = 1715180400000
ISO   = 2024-05-08T15:00:00.000Z
ver   = 7
var   = 10 (RFC 4122)
rand_a = 0xa4f
rand_b = 0x36ee8dfe3c2b0a55

// 직접 구현하기

2024년에 RFC 9562이 등장한 이후 대부분의 언어에는 UUIDv7을 위한 표준 라이브러리 헬퍼나 단일 파일 구현이 있습니다. 아래는 코드베이스에 그대로 넣을 수 있는 표준 레시피입니다 — 브라우저 JS, Node.js, Go, Python, PostgreSQL에서.

[JavaScript]

순수 브라우저/Node JS에서의 UUIDv7 — RFC 9562 레이아웃

function uuidv7() {
  const ts = BigInt(Date.now());
  const rand = new Uint8Array(10);
  crypto.getRandomValues(rand);
  const b = new Uint8Array(16);
  b[0] = Number((ts >> 40n) & 0xFFn);
  b[1] = Number((ts >> 32n) & 0xFFn);
  b[2] = Number((ts >> 24n) & 0xFFn);
  b[3] = Number((ts >> 16n) & 0xFFn);
  b[4] = Number((ts >> 8n)  & 0xFFn);
  b[5] = Number( ts          & 0xFFn);
  b[6] = (rand[0] & 0x0F) | 0x70;   // version = 7
  b[7] =  rand[1];
  b[8] = (rand[2] & 0x3F) | 0x80;   // variant = RFC 4122
  for (let i = 9; i < 16; i++) b[i] = rand[i - 6];
  const h = Array.from(b, x => x.toString(16).padStart(2,'0')).join('');
  return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}

// usage:
const id = uuidv7();
console.log(id);   // -> '018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55'

// generate a batch and verify chronological sort:
const batch = Array.from({ length: 5 }, uuidv7);
batch.sort();      // sorts by creation time without a separate timestamp
[Node.js]

Node.js v26.1.0+ — 내장 crypto.randomUUIDv7()

import { randomUUIDv7 } from 'node:crypto';

// Added in Node.js v26.1.0 (2026-05-07).
// Returns an RFC 9562 version 7 UUID. The first 48 bits encode a
// millisecond Unix timestamp; the rest is CSPRNG output.
const id = randomUUIDv7();
// -> '018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55'

// The CSPRNG output is cached for performance: Node generates enough
// entropy upfront for the next ~128 UUIDs. Pass disableEntropyCache: true
// when you need each call to draw fresh randomness, e.g. directly after
// a fork() or in tight high-security loops.
const freshId = randomUUIDv7({ disableEntropyCache: true });

// IMPORTANT: per the Node docs, "the embedded timestamp relies on a
// non-monotonic clock and is not guaranteed to be strictly increasing."
// If two UUIDs land in the same millisecond OR the system clock steps
// backwards, the IDs may not sort in creation order. Use a userland
// monotonic-v7 library (e.g. uuidv7 on npm) when strict ordering matters.
[Go]

Go — google/uuid v1.6+가 UUIDv7을 기본 제공

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func newID() uuid.UUID {
    id, err := uuid.NewV7()
    if err != nil {
        panic(err)
    }
    return id
}

func main() {
    id := newID()
    fmt.Println(id.String())  // 018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55
    fmt.Println(id.Time())    // embedded creation timestamp
}
[Python]

Python 3.13+ — 표준 라이브러리 uuid.uuid7()

import uuid

# Python 3.13 added uuid7() and uuid8() to the standard library.
uid = uuid.uuid7()
print(uid)            # 018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55
print(uid.version)    # 7

# For older Python use the 'uuid7' or 'uuid-utils' PyPI packages, or:
# from uuid_extensions import uuid7
[PostgreSQL]

PostgreSQL 18+ — 기본 제공 uuidv7() 함수

-- PG 18 ships uuidv7() natively. Use it as a primary key default:
CREATE TABLE events (
    id   uuid PRIMARY KEY DEFAULT uuidv7(),
    body jsonb,
    ts   timestamptz NOT NULL DEFAULT now()
);

-- For older Postgres, install the pg_uuidv7 extension or generate client-side.
-- Migration tip: keep INDEX on (id) only — v7 already sorts chronologically,
-- so a separate (created_at) index is usually redundant.

// 흔한 함정

> UUIDv7은 생성 시간을 노출합니다 — 불투명 토큰에는 사용하지 마세요

모든 v7의 처음 48비트는 Unix 밀리초 타임스탬프입니다. UUID를 보는 사람은 누구나 레코드가 언제 생성되었는지, ID가 발급되는 속도를 디코딩할 수 있고, (여러 샘플이 있으면) 서버 시계를 근사할 수 있습니다. 내부 데이터베이스 기본 키와 로그 ID에는 괜찮지만, 비밀번호 재설정 URL, 공유 링크, 세션 ID, 초대 코드에는 대신 UUIDv4 또는 CSPRNG로 생성된 무작위 문자열을 사용하세요.

> 시계 역행은 단조성을 깨뜨립니다

시스템 시계가 뒤로 점프하면(NTP 스텝, VM 마이그레이션, 윤초), 순진하게 생성된 v7 UUID는 이전에 발급된 ID보다 앞에 정렬되는 값을 만들 수 있습니다. RFC 9562 §6.2는 방법 2(단조 랜덤)를 권장합니다: 마지막으로 생성된 UUID를 추적하고, 타임스탬프가 진행되지 않으면 대신 랜덤 부분을 증가시킵니다. 이 도구의 단조 토글이 바로 그 일을 합니다.

> v7은 보안에 민감한 맥락에서 v4의 즉시 대체재가 아닙니다

무작위로 보이는 ID(v4)는 종종 실수로 베어러 토큰으로 사용됩니다: 「UUID를 알면 그 행을 읽을 수 있다」. v7은 랜덤 비트가 74비트뿐이고 예측 가능한 타임스탬프 접두사를 가지므로, 여전히 충돌에는 강하지만 v4의 122비트 랜덤보다 훨씬 적은 예측 불가능성을 제공합니다. 무언가가 권한(capability)으로 취급된다면, v7 기본 키를 재사용하는 대신 별도의 암호화 토큰을 생성하세요.

> 문자열 비교는 소문자, 하이픈 형식에서만 작동합니다

v7의 시간순 정렬은 정규 36자 소문자 문자열의 사전식 비교 — 또는 기본 16바이트 값의 바이트 단위 비교 — 에 의존합니다. 대문자와 소문자를 섞거나, 도중에 하이픈을 제거하거나, 일부 행을 {...}로 감싸고 다른 행은 그대로 저장하면, 모두 더 이상 생성 시간과 일치하지 않는 정렬 순서를 만듭니다. 열마다 하나의 정규 형식을 선택하고 CHECK 제약으로 강제하세요.

> 48비트 타임스탬프는 10889년에 순환합니다

2^48 밀리초는 Unix 에포크 이후 약 8,925년으로 — 타임스탬프 필드는 10889년 8월 2일 UTC에 오버플로됩니다. 코드가 내장된 타임스탬프가 합리적인 범위 내에 있다고 단정한다면, 한 세기 후에 틀릴 가까운 미래의 연도를 하드코딩하는 대신 상한을 281,474,976,710,655 ms(48비트 부호 없는 정수가 담을 수 있는 최댓값)로 설정하세요.

>> 자주 묻는 질문

Q: UUIDv7이란 무엇인가요?

A: UUIDv7은 RFC 9562(2024년 5월)에 정의된 128비트 식별자로, 48비트 Unix 밀리초 타임스탬프와 74비트의 무작위성, 그리고 표준 버전 + 변형 비트를 결합합니다. 그 결과 생성 시간순으로도 정렬되는 전역적으로 고유한 ID가 됩니다 — 두 마리 토끼를 잡은 셈입니다. 이는 각 삽입이 다른 B-트리 페이지에 떨어져 막대한 쓰기 증폭을 일으키는 무작위 UUIDv4 기본 키로 인한 데이터베이스 인덱스 문제를 해결하기 위해 특별히 설계되었습니다.

Q: UUIDv7은 UUIDv4와 어떻게 다른가요?

A: UUIDv4는 완전히 무작위이며(122비트 랜덤) 버전 + 변형 필드 외에는 구조가 없습니다. 1마이크로초 차이로 생성된 두 v4는 완전히 다른 위치로 정렬되는데, 이는 예측 불가능성에는 훌륭하지만 B-트리 인덱스에는 끔찍합니다. UUIDv7은 48비트 Unix 밀리초 타임스탬프를 앞에 두므로, 시간상 가까이 생성된 v7은 저장소에서도 가까이 정렬됩니다. 절충점: v7은 생성 시간을 드러내고 랜덤 비트가 122개가 아닌 74개뿐입니다 — 여전히 충돌에 강하지만 비밀 토큰으로는 부적합합니다.

Q: UUIDv4에서 UUIDv7으로 마이그레이션해야 하나요?

A: 쓰기가 많은 테이블의 내부 데이터베이스 기본 키라면 — 예, 거의 항상 그렇습니다. v4가 일으키는 인덱스 단편화는, 특히 InnoDB 클러스터형 인덱스를 사용하는 PostgreSQL이나 MySQL에서, 실제 쿼리 자체의 비용을 압도할 수 있습니다. 사용자에게 노출되거나 URL에 포함되거나 권한으로 취급되는 토큰(「UUID를 알면 리소스에 접근할 수 있다」)에는 v4를 유지하거나 별도의 무작위 토큰을 사용하세요 — v7은 생성 시간을 노출합니다. 일반적인 패턴은 내부 조인용 v7 기본 키와 공개용 URL을 위한 별도의 무작위 슬러그입니다.

Q: UUIDv7은 ULID, KSUID, Snowflake와 같은가요?

A: 개념적으로 비슷합니다 — 네 가지 모두 시간순 ID입니다 — 하지만 비트 레이아웃과 인코딩이 다릅니다. ULID는 Crockford base32와 다른 밀리초 레이아웃을 사용합니다. KSUID는 32비트 타임스탬프 + 128비트 페이로드를 27개의 base62 문자로 인코딩합니다. Snowflake는 워커 ID를 가진 64비트 트위터 전용 ID입니다. UUIDv7은 IETF 표준 등가물로, 정규 8-4-4-4-12 16진 형식으로 인코딩되어 모든 UUID 라이브러리, 데이터베이스 UUID 타입, JDBC/ODBC 드라이버가 이미 이해합니다. 2025년 이후 새로 시작한다면 v7을 선호하세요 — 그것이 표준입니다.

Q: 충돌 전에 밀리초당 몇 개의 UUIDv7을 생성할 수 있나요?

A: 단일 밀리초 내에서는 74개의 랜덤 비트(rand_a의 12비트 + rand_b의 62비트)만이 고유성을 제공합니다. 생일 충돌 한계에 따르면, 50% 충돌 확률에 도달하기 전 같은 ms 내에 약 2^37 ≈ 1,370억 개의 v7을 생성할 수 있습니다 — 어떤 현실적인 시스템에서도 사실상 무제한입니다. 밀리초를 가로지르면 타임스탬프 자체가 구별하므로, 시스템 수명 전체에 걸친 전역 충돌 위험은 무시할 수 있습니다. 단조 토글이 켜져 있으면 밀리초 내 충돌은 구조상 0입니다(랜덤 부분이 증가됩니다).

Q: UUIDv7에서 타임스탬프를 추출할 수 있나요?

A: 예 — 타임스탬프는 처음 48비트이며, 이는 하이픈을 제거한 처음 12개의 16진 문자입니다. 처음 세 개의 하이픈 그룹(8 + 4 = 12 hex digits)을 연결하고 16진 정수로 파싱하면 밀리초 단위의 Unix 타임스탬프를 얻습니다. 위의 디코더를 사용해 대화식으로 하거나 코드에서: parseInt(uuid.replace(/-/g,'').slice(0,12), 16). 결과는 UUID가 생성된 밀리초 순간으로, 그 당시 시스템 시계 정밀도까지 정확합니다.

Q: UUIDv7의 버전 숫자는 어떻게 보이나요?

A: 하이픈으로 구분된 세 번째 그룹은 항상 숫자 7로 시작합니다. 예: 018f5c2e-90c0-7a4f-b6ee-8dfe3c2b0a55. 네 번째 그룹은 항상 8, 9, a, b로 시작합니다 — 이는 상위 2비트가 10(RFC 4122 변형)일 때 가능한 네 가지 값입니다. 버전 숫자가 7이 아니면 그 UUID는 다른 버전(일반적으로 무작위용 4 또는 시간 기반 v1용 1)이며 시간순으로 정렬되지 않습니다.

Q: PostgreSQL / MySQL은 UUIDv7을 기본 지원하나요?

A: PostgreSQL 18(2025년 9월 출시)은 uuidv7()을 내장 함수로 제공합니다. 이전 버전은 pg_uuidv7 확장 또는 클라이언트 측 생성이 필요합니다. MySQL 8.x에는 기본 v7이 없습니다; UUID_TO_BIN(uuid, 1) 헬퍼(정렬 순서를 위해 타임스탬프 바이트를 교환)는 v1에만 사용하고 — v7은 클라이언트 측에서 생성하세요. SQL Server, Oracle, SQLite는 모두 클라이언트 측 v7 생성을 전제로 합니다. 대부분의 ORM(Hibernate, Entity Framework, Sequelize, Prisma, SQLAlchemy)은 이제 v7을 기본 또는 플러그인으로 지원합니다.

Q: 단조 옵션은 RFC 9562을 준수하나요?

A: 예. RFC 9562 §6.2는 밀리초 내 순서를 보장하는 세 가지 방법을 명시적으로 설명합니다: (1) 랜덤 채우기, (2) 단조 랜덤 — 타임스탬프가 진행되지 않을 때 카운터를 증가, (3) 서브 밀리초 타임스탬프 정밀도. 이 도구의 단조 체크박스는 방법 2를 구현합니다: 두 UUID가 동일한 48비트 타임스탬프를 공유하면, 두 번째의 랜덤 부분은 새로 뽑는 대신 previous_random + 1로 설정됩니다. 이는 사양을 완전히 준수하면서 배치 생성에서 엄격한 순서를 보장합니다.

Q: 내 데이터가 어딘가로 전송되나요?

A: 아니요. 모든 UUIDv7 생성, 디코딩, 정렬, 복사, 다운로드는 순수 JavaScript로 브라우저 안에서 전부 이루어집니다. 생성, 디코딩, 복사, 다운로드를 클릭해도 페이지는 절대 네트워크 요청을 하지 않습니다 — 브라우저의 DevTools 네트워크 탭으로 확인할 수 있습니다. 타임스탬프, 사용자 지정 시드, 생성된 UUID, 디코딩된 출력을 기록하지 않습니다. 페이지 자체는 CDN에서 제공되는 정적 HTML이므로 어떤 입력도 우리 인프라에 도달하지 않습니다. 이로써 이 도구는 프로덕션 데이터베이스 ID, 내부 로그, 또는 제3자 서버를 거치지 않게 하고 싶은 기타 데이터에 안전하게 사용할 수 있습니다.

Q: UUIDv7을 Java / .NET / Rust에서 사용할 수 있나요?

A: 예. Java에는 com.fasterxml.uuid:java-uuid-generator 5.0+이 있고 JDK 21은 라이브러리 헬퍼를 통해 사용할 수 있습니다. .NET 9은 BCL에 Guid.CreateVersion7()을 제공합니다. Rust는 v7 기능 플래그 뒤에서 uuid 크레이트의 Uuid::now_v7()을 사용합니다. 대부분의 다른 생태계(Elixir, Ruby, PHP, Swift, Kotlin)에도 잘 관리되는 패키지가 있습니다 — 해당 언어의 패키지 레지스트리에서 「uuidv7」 또는 「uuid v7」을 검색하세요. 와이어 형식은 모두에서 동일하므로, Go에서 생성된 v7은 어떤 변환 없이도 JavaScript에서 파싱하고 타임스탬프를 추출할 수 있습니다.

Q: Node.js에 내장 UUIDv7 생성기가 있나요?

A: 예 — Node.js v26.1.0(2026-05-07 출시)부터 표준 라이브러리가 crypto.randomUUIDv7([options])을 노출합니다. import { randomUUIDv7 } from 'node:crypto'로 가져와 인수 없이 호출하면 RFC 9562 v7 UUID 문자열을 얻습니다. 지원되는 유일한 옵션은 disableEntropyCache(불리언, 기본값 false)입니다; 기본적으로 Node는 다음 약 128개의 UUID를 생성할 만큼의 무작위 데이터를 미리 캐싱하는데, 이는 crypto.randomUUID()가 사용하는 것과 동일한 최적화입니다. 공식 문서의 중요한 유의 사항: 「내장된 타임스탬프는 비단조 시계에 의존하며 엄격히 증가하는 것이 보장되지 않는다」. 다시 말해, 같은 밀리초에 생성된 두 UUID, 또는 NTP 스텝 / VM 시계가 뒤로 틀어지는 시점을 가로질러 생성된 UUID는 생성 순서대로 정렬되지 않을 수 있습니다. 밀리초 내에서 엄격한 단조성이 필요하다면 RFC 9562 §6.2 방법 2를 따르는 userland 구현(npm uuidv7 패키지, 또는 단조 토글을 켠 이 도구)을 사용하세요.

Q: UUIDv7을 데이터베이스에 효율적으로 저장하려면?

A: 36자 문자열이 아니라 16바이트 바이너리 타입으로 저장하세요 — 행당 20바이트를 절약하고, 인덱스 크기를 절반으로 줄이며, 더 빠른 비교 경로를 얻습니다. PostgreSQL의 uuid 타입, MySQL BINARY(16), SQL Server uniqueidentifier, 또는 SQLite BLOB을 사용하세요. 강제하려면 버전 니블이 7과 같다는 CHECK 제약을 추가하세요. v7에서는 행이 생성 시간순으로 자연스럽게 클러스터링되므로, 보통 (uuid_pk)에 대한 커버링 인덱스로 충분합니다 — 시간순 쿼리를 위한 별도의 (created_at) 인덱스는 필요 없습니다.

// OTHER LANGUAGES