ToolDeck

تولیدکننده UUID v7

تولید UUID v7 مرتب‌شده بر اساس زمان برای کلید اصلی پایگاه داده

فرمت‌بندی

تعداد:

UUID v7 چیست؟

UUID v7 یک فرمت UUID نسل بعدی است که در RFC 9562 (مه ۲۰۲۴) استانداردسازی شده است. این فرمت یک تایم‌استمپ یونیکس ۴۸ بیتی با دقت میلی‌ثانیه را در بیت‌های با اهمیت بیشتر رمزگذاری می‌کند، سپس نشانگرهای نسخه و واریانت می‌آیند، و بیت‌های باقی‌مانده با داده‌های تصادفی رمزنگاری‌شده پر می‌شوند.

چون تایم‌استمپ در بیت‌های بالا قرار دارد، مقادیر UUID v7 به‌صورت زمانی مرتب می‌شوند — هم لغت‌نگارانه و هم عددی. این ویژگی آن‌ها را برای کلیدهای اصلی پایگاه داده بسیار مناسب می‌کند، جایی که UUID‌های تصادفی (v4) باعث تکه‌تکه‌شدن ایندکس B-tree می‌شوند.

چرا UUID‌های تصادفی ایندکس‌های پایگاه داده را تکه‌تکه می‌کنند

ایندکس‌های B-tree — که توسط PostgreSQL، MySQL، SQLite و اکثر پایگاه‌های داده دیگر استفاده می‌شوند — ردیف‌ها را بر اساس مقدار کلید مرتب نگه می‌دارند. وقتی ردیف جدیدی درج می‌کنید، پایگاه داده باید آن را در موقعیت مرتب‌شده صحیح در ایندکس قرار دهد.

با UUID v4 (کاملاً تصادفی)، هر درج جدید در موقعیتی اساساً تصادفی در درخت ایندکس قرار می‌گیرد. این موضوع پایگاه داده را مجبور می‌کند صفحات ایندکس داخلی را مدام بخواند و بازنویسی کند، صفحات پر را تقسیم کند و برخی دیگر را نیمه‌خالی بگذارد. نتیجه یک ایندکس تکه‌تکه و متورم است که با رشد جدول، هم نوشتن و هم خواندن را کند می‌کند.

چیدمان بیتی UUID v7

UUID v7 دارای ۱۲۸ بیت است که به شش فیلد تقسیم می‌شود:

بیت‌هافیلدهدف
48unix_ts_msتایم‌استمپ یونیکس ۴۸ بیتی بر حسب میلی‌ثانیه — کل نیمه بالایی را اشغال می‌کند
4verشماره نسخه — همیشه 0111 (عدد صحیح ۷)
12rand_a۱۲ بیت داده تصادفی رمزنگاری‌شده
2varنشانگر واریانت — همیشه 10 (واریانت RFC 4122)
62rand_b۶۲ بیت داده تصادفی رمزنگاری‌شده

دقت تایم‌استمپ ۱ میلی‌ثانیه است. در یک میلی‌ثانیه یکسان، مقادیر UUID v7 بر اساس پسوند تصادفی‌شان مرتب می‌شوند — افزایش یکنواخت زیر میلی‌ثانیه تضمین نمی‌شود، اما k-sortable هستند: شناسه‌هایی که در زمان نزدیک به هم تولید می‌شوند در ایندکس نیز نزدیک به هم مرتب خواهند شد.

UUID v7 در مقابل UUID v1

هر دوی UUID v1 و UUID v7 یک تایم‌استمپ جاسازی می‌کنند، اما از نظر طراحی تفاوت‌های قابل توجهی دارند:

ویژگیUUID v7UUID v1
Epoch / پایه زمانیUnix epoch (۱ ژانویه ۱۹۷۰)Gregorian epoch (۱۵ اکتبر ۱۵۸۲)
دقت زمانی۱ میلی‌ثانیه۱۰۰ نانوثانیه
قابل مرتب‌سازیبله — k-sortable by designخیر — فیلدهای زمانی در چیدمان UUID درهم می‌شوند
حریم خصوصیهیچ اطلاعات میزبانی فاش نمی‌شودآدرس MAC میزبان تولیدکننده را جاسازی می‌کند
عملکرد ایندکس پایگاه دادهعالی — درج‌های ترتیبی، تکه‌تکه‌شدن حداقلضعیف — غیرترتیبی علی‌رغم وجود تایم‌استمپ
استانداردRFC 9562 (2024)RFC 4122 (2005)
پشتیبانی بومی مرورگرهنوز نه (بدون crypto.randomUUID v7)به‌صورت بومی در دسترس نیست

برای هر پروژه جدیدی که به UUID‌های مرتب‌شده بر اساس زمان نیاز دارد، UUID v7 را به UUID v1 ترجیح دهید. UUID v1 قدیمی است و اطلاعات میزبان را فاش می‌کند.

UUID v7 در مقابل ULID

ULID (شناسه منحصربه‌فرد جهانی قابل مرتب‌سازی لغت‌نگارانه) مشکلی مشابه UUID v7 را حل می‌کند. در اینجا مقایسه آن‌ها آمده است:

UUID v7
  • از استاندارد UUID مطابق RFC 9562 پیروی می‌کند — با تمام ابزارهای UUID سازگار است
  • فرمت هگز با خط‌تیره — به‌طور جهانی شناخته‌شده
  • پشتیبانی بومی از ستون UUID در پایگاه داده
  • مجموعاً ۱۲۸ بیت
ULID
  • رمزگذاری Crockford Base32 — ۲۶ کاراکتر، کمی فشرده‌تر
  • حروف‌کوچک و بزرگ یکسان است و از کاراکترهای مبهم (I، L، O، U) اجتناب می‌کند
  • در نگاه اول خواناتر برای انسان
  • به کتابخانه نیاز دارد — پشتیبانی بومی پلتفرم وجود ندارد

اگر در اکوسیستم UUID هستید (ستون uuid در PostgreSQL، REST APIهایی که UUID برمی‌گردانند)، از UUID v7 استفاده کنید. اگر از صفر شروع می‌کنید و رمزگذاری دوستانه‌تری برای انسان ترجیح می‌دهید، ULID گزینه معقولی است.

استفاده از UUID v7 در پایگاه‌های داده

UUID v7 هنوز توسط اکثر پایگاه‌های داده به‌صورت بومی تولید نمی‌شود، اما می‌تواند در ستون‌های UUID استاندارد ذخیره شده و در کد برنامه یا از طریق افزونه‌ها تولید شود:

PostgreSQL
PostgreSQL: در ستون uuid ذخیره کنید. افزونه pg-uuidv7 یک تابع سمت سرور uuid_generate_v7() اضافه می‌کند اگر به تولید شناسه توسط پایگاه داده نیاز دارید.
MySQL / MariaDB
MySQL / MariaDB: در ستون BINARY(16) یا CHAR(36) ذخیره کنید. در کد برنامه تولید کنید. MySQL 8.0+ از طریق UUID_TO_BIN(UUID(), 1) پشتیبانی از UUID مرتب‌شده برای v1 دارد، اما v7 نیاز به تولید در سطح برنامه دارد.
SQLite
SQLite: به‌صورت TEXT (36 کاراکتر) یا BLOB (16 بایت) ذخیره کنید. در کد برنامه تولید کنید. مرتب‌سازی لغت‌نگارانه روی TEXT به درستی کار می‌کند زیرا UUID v7 از پیشوند تایم‌استمپ با عرض ثابت استفاده می‌کند.

نمونه کد

UUID v7 هنوز از طریق crypto.randomUUID() در دسترس نیست. از کتابخانه‌ای مانند uuidv7 (npm) تا رسیدن پشتیبانی بومی استفاده کنید:

JavaScript (browser / Node.js 20+)
function generateUuidV7() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())

  // Embed 48-bit Unix ms timestamp
  buf[0] = Number((ms >> 40n) & 0xFFn)
  buf[1] = Number((ms >> 32n) & 0xFFn)
  buf[2] = Number((ms >> 24n) & 0xFFn)
  buf[3] = Number((ms >> 16n) & 0xFFn)
  buf[4] = Number((ms >> 8n)  & 0xFFn)
  buf[5] = Number(ms & 0xFFn)

  // Set version 7 (0111xxxx)
  buf[6] = (buf[6] & 0x0F) | 0x70

  // Set variant (10xxxxxx)
  buf[8] = (buf[8] & 0x3F) | 0x80

  const hex = [...buf].map(b => b.toString(16).padStart(2, '0')).join('')
  return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`
}

// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto'  // v4 only — no v7 yet in stdlib
Python (uuid7 library)
# pip install uuid7
import uuid_extensions

uid = uuid_extensions.uuid7()
print(uid)                       # e.g. 018e2b3d-1a2b-7000-8000-abc123456789
print(uid.time)                  # Unix ms timestamp embedded in the UUID

# Or as a plain string
from uuid_extensions import uuid7str
print(uuid7str())
PostgreSQL — generate UUID v7
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
  SELECT encode(
    set_bit(
      set_bit(
        overlay(
          uuid_send(gen_random_uuid())
          PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
          FROM 1 FOR 6
        ),
        52, 1
      ),
      53, 1
    ),
    'hex'
  )::uuid;
$$;

-- Usage as a default primary key
CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
  payload jsonb,
  created_at timestamptz DEFAULT now()
);
TypeScript — extract timestamp from UUID v7
function extractTimestamp(uuid: string): Date {
  const hex = uuid.replace(/-/g, '')
  const ms = parseInt(hex.slice(0, 12), 16)  // first 48 bits = ms timestamp
  return new Date(ms)
}

const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"

سوالات متداول

آیا UUID v7 با UUID v4 سازگار به عقب است؟
بله. UUID v7 از همان فرمت سیمی ۱۲۸ بیتی، ۳۲ رقم هگز با خط‌تیره استفاده می‌کند که سایر نسخه‌های UUID دارند. هر سیستمی که UUID ذخیره یا منتقل می‌کند بدون تغییر UUID v7 را می‌پذیرد. نیبل نسخه (7) و بیت‌های واریانت آن را به عنوان v7 برای ابزارهایی که ساختار UUID را بررسی می‌کنند شناسایی می‌کنند.
آیا UUID v7 تایم‌استمپ تولید را فاش می‌کند؟
بله — ۴۸ بیت اول یک تایم‌استمپ یونیکس میلی‌ثانیه‌ای است، بنابراین هر کسی که UUID را داشته باشد می‌تواند تقریباً زمان تولید آن را تعیین کند (تا نزدیکترین میلی‌ثانیه). اگر فاش‌کردن زمان ایجاد برای مورد استفاده شما نگران‌کننده است، به‌جای آن از UUID v4 استفاده کنید.
آیا می‌توانم از UUID v7 به عنوان کلید اصلی پایگاه داده بدون ستون جداگانه created_at استفاده کنم؟
بله. چون UUID v7 یک تایم‌استمپ با دقت میلی‌ثانیه جاسازی می‌کند، می‌توانید آن مقدار را برای دریافت زمان تقریبی ایجاد رمزگشایی کنید. با این حال، برای وضوح و قابلیت ایندکس‌گذاری، بسیاری از تیم‌ها همچنان یک ستون created_at صریح نگه می‌دارند و UUID v7 را فقط برای ستون ID استفاده می‌کنند.
UUID v7 چقدر آنتروپی دارد؟
UUID v7 دارای ۷۴ بیت داده تصادفی است (۱۲ بیت در rand_a + ۶۲ بیت در rand_b). این کمی کمتر از ۱۲۲ بیت UUID v4 است اما همچنان فضای بدون تداخل نجومی‌بزرگی برای استفاده عملی فراهم می‌کند. کاهش تصادفی بودن، مبادله‌ای برای به‌دست آوردن قابلیت مرتب‌سازی تایم‌استمپ است.
آیا UUID v7 به‌صورت بومی در مرورگرها یا Node.js پشتیبانی می‌شود؟
هنوز نه، تا اوایل ۲۰۲۵. استاندارد RFC 9562 در مه ۲۰۲۴ منتشر شد و پشتیبانی پلتفرم هنوز در حال رسیدن است. فعلاً از پکیج npm با نام uuidv7 استفاده کنید. پشتیبانی بومی از طریق crypto.randomUUID({ version: 7 }) یا APIهای مشابه ممکن است در نسخه‌های آینده مرورگر و Node.js بیاید.