UUID — أو المعرّف الفريد العام — هو سلسلة 128 بت تُستخدم لتعريف أي شيء: مستخدم، طلب، ملف، سجل. تقابلها في كل مكان: قواعد البيانات، معرّفات الطلبات، روابط الملفات. ورغم أن كل UUID يبدو للوهلة الأولى كخيط عشوائي، إلا أن كل نوع يولّده بطريقة مختلفة، وهذا الاختلاف البسيط يغيّر سلوكه في قاعدة البيانات أكثر مما تتوقع.

بنية الـ UUID

أي UUID يُكتب بصيغة 8-4-4-4-12، أي 32 محرفاً سداسياً مفصولة بأربع شرطات. ما بين الشرطات ترميز مجرد سريع للرقم نفسه:

صيغة UUIDtext
550e8400-e29b-41d4-a716-446655440000
└─8──┘ └─4─┘ └─4─┘ └─4─┘   └────12────┘
     ↓        ↓      ↓        ↓
   time-low  time-mid  clock-seq  node
              ↑
        version  (الرقم 4 في الموضع الثالث)
                     ↑
                 variant  (يبدأ بـ 8 أو 9 أو a أو b)

الجزء الذي يهمّك عملياً هو محرف واحد فقط: الرقم الذي يشير إلى النسخة. هو الذي يحدّد كيف وُلّد هذا المعرّف، وبالتالي ما يضمنه لك.

الإصدار 1: مرتبط بالوقت

UUID v1 يولّد المعرّف من العنوان المادي لجهازك (MAC address) مضافاً إليه الطابع الزمني بدقة 100 نانوثانية. النتيجة: المعرّفات مرتّبة زمنياً، لكن جزئياً في ترتيب زمني — ويمكن التنبؤ بها. لهذا تُستخدم v1 في أنظمة مغلقة فقط، ولا تصلح لمعرّفات توضع في رابط عام.

الإصدار 4: العشوائية الكاملة

الأكثر استخداماً على الإطلاق. يولّد 122 بتاً عشوائياً من مولّد عشوائي آمن (cryptographically secure). لا يحمل أي معلومات عن وقت الإنشاء ولا عن الجهاز. بساطته هي قوته، وعشوائيته هي ضعفه:

  • لا يمكن التنبؤ بالمعرّف ولا استنتاجه — وهذا مطلوب عند كشف المعرّفات في روابط عامة.
  • لا يحمل أي معلومة زمنية، فعلى النظام أن يضيف عموداً منفصلاً للترتيب.
  • عند الإدراج في فهرس (index) عشوائي، يتوزّع على شجرة B-tree، وهذا سيّئ للأداء.

الإصدار 7: الحل الوسط

الإصدار v7 هو الأحدث عملياً، ويعتمد على فكرة بسيطة: ضع الطابع الزمني في أول المعرّف، ثم أضف عشوائية بعده. النتيجة معرّف يبدو عشوائياً لكنه مرتّب زمنياً.

مقارنة البداياتtext
v4 (عشوائي)     8f14e45f-ceea-467a-9d7e-3b2a1c0d5e6f  ← لا ترتيب
v7 (زمني)        018e4a2c-7d13-7f2b-a9e4-6c1d5b8f0a3e  ← أول 12 محرفاً زمنية
الخاصيةv4v7
الترتيب الزمنيلانعم
عشوائي البادئةنعمنعم
الأداء مع الفهرسمتفرّقمتسلسل
حجم النص (36 محرفاً)نفسهنفسه
الاعتماد التشغيليرسمي منذ سنواتأحدث نسبياً

المقارنة الحاسمة: UUID مقابل المفتاح الرقمي

أهم سؤال في هذا الموضوع ليس أي نوع تختار من UUID، بل: هل تحتاج UUID أصلاً؟ المفتاح الرقمي التلقائي (auto-increment) يفوز في كل المقاييس عدا واحد:

المعيارINTEGER (auto-increment)UUID (v4)
الحجم على القرص8 بايت16 بايت
أداء الفهرسمثاليمتفرّق
قبل الحفظغير موجودموجود
دعم التوزيعيحتاج تنسيقاً مركزياًتولّد من أي خادم
تسريب المعلوماتيكشف حجم القاعدةلا يكشف شيئاً

ULID: البديل الذي يجمع الصفتين

ULID يحلّ مشكلة v7 بطريقة أبسط: 26 محرفاً من ترميز Base32، أول 10 منها هي الوقت بالضبط متبوعةً بـ 16 محرفاً عشوائياً. النتيجة: معرّف يُقرأ بالعين، مرتّب زمنياً، ويحمل ذاكرته في أوله.

مقارنة بصريةtext
UUID v4 : 550e8400-e29b-41d4-a716-446655440000    (36 محرفاً)
ULID     : 01ARZ3NDEKTSV4RRFFQ69G5FAV             (26 محرفاً)
                 ↑ الطابع الزمني مدمج في النص

متى تستعمل كل واحد

  • v4: معرّفات تُعرض في روابط عامة أو تُسجَّل من العملاء، لأن العشوائية تمنع التخمين.
  • v7: معرّفات داخلية في جداول كبيرة تحتاج ترتيباً وأداء فهرسة — الخيار الافتراضي الحديث.
  • ULID: تريد ترتيباً ووضوحاً في السجل مع حجم أصغر، وأن تكون المقارنة النصية مطابقة للترتيب الزمني.
  • INTEGER: جدول واحد، خادم واحد، لا حاجة لتوزيع — وهذا أكثر من نصف الحالات الفعلية.

كيف تولّده

لا تحتاج مكتبة لتوليد v4 — يوفّر المتصفح ذلك بشكل أصلي وآمن:

توليد في المتصفحjavascript
// UUID v4 — مولّد عشوائي آمن مدمج في المتصفح
function uuidv4() {
  return crypto.randomUUID();
}

// لمجموعة دفعة واحدة
const ids = Array.from({ length: 100 }, () => crypto.randomUUID());

// في Node.js
// import { randomUUID } from "node:crypto";
// const id = randomUUID();

ملاحظة عن التخزين

النص الكامل (36 محرفاً) مريح للعرض، لكنه ثقيل للتخزين والفهرسة. معظم قواعد البيانات الجاهزة اليوم تدعم تخزين UUID كنوع ثنائي 16 بايت، مع دالة لتحويله عند القراءة والكتابة. هذا يوفّر حجم الفهرس ويحوّل المقارنات من نصية إلى ثنائية، وهي أسرع:

PostgreSQL — مثال عمليsql
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL
);

-- المعرّف الثنائي أصغر وأسرع في الفهرسة
ALTER TABLE users ALTER COLUMN id TYPE uuid USING id::uuid;