جديد على UUID؟ ابدأ بدليل ما هو UUID؟ الدليل الشامل لأساسيات تنسيق UUID والإصدارات وحالات الاستخدام.
UUID v4 مقابل v7 مقابل ULID مقابل Snowflake: اختيار المعرّف المناسب لقاعدة بياناتك في 2026
اختيار نظام معرّفات خاطئ قد يكلفك غاليًا. المفاتيح الأساسية من نوع UUID v4 العشوائية في جدول من 100 مليون صف تسبب ما يصل إلى 10 أضعاف انقسامات صفحات الفهرس مقارنة بالمعرّفات التسلسلية. معرّفات Snowflake تتطلب سجل عمال مركزيًا يصبح نقطة فشل وحيدة. بدا ULID كالحل الأمثل الوسط — حتى وصل UUID v7 كمعيار IETF.
يقدم لك هذا الدليل إطار قرار وأرقام أداء فعلية وأمثلة برمجية لاختيار المعرّف المناسب لنظامك.
شجرة قرار سريعة
| متطلبك | الخيار الأفضل | السبب |
|---|---|---|
| مفتاح أساسي لقاعدة بيانات (مشروع جديد) | UUID v7 | مرتب زمنيًا، نوع عمود uuid قياسي، أفضل أداء فهرسة |
| معرّف فريد عام (بدون حاجة للترتيب) | UUID v4 | دعم شامل، بدون تكوين، 122 بت من العشوائية |
| معرّف حتمي من مدخلات معروفة | UUID v5 | نفس مساحة الاسم + الاسم ينتج دائمًا نفس UUID |
| نظام موزع عالي الإنتاجية (>100K معرّف/ثانية/عقدة) | Snowflake ID | عدد صحيح 64 بت، رتيب داخل العامل، تخزين BIGINT أصلي |
| رمز قصير آمن لعناوين URL أو معرّف جانب العميل | NanoID | 21 حرفًا، أبجدية آمنة لعناوين URL، طول قابل للتخصيص |
| نظام قديم يستخدم ULID بالفعل | ULID | أبقِه — مكافئ وظيفيًا لـ UUID v7، الترحيل لا يستحق العناء |
تفصيل إصدارات UUID
UUID v1 — الوقت + عنوان MAC (مهمل)
يرمّز UUID v1 طابعًا زمنيًا بـ 60 بت وعنوان MAC للآلة بـ 48 بت. كان “UUID القابل للترتيب” الأصلي لكن له عيبان قاتلان: يكشف هوية الجهاز ويستخدم حقبة طابع زمني غير قياسية (15 أكتوبر 1582). يُهمل RFC 9562 رسميًا v1 لصالح v6/v7. لا تستخدم v1 في المشاريع الجديدة.
UUID v4 — عشوائية بحتة
يملأ UUID v4 122 من 128 بت ببيانات عشوائية مشفرة تشفيريًا. هو الإصدار الأكثر استخدامًا — بسيط وخاص ومدعوم عالميًا.
نقاط القوة:
- بدون تكوين، لا حاجة لتنسيق
- مجهول بالكامل — لا يُكشف طابع زمني أو معلومات جهاز
- مدعوم من كل قاعدة بيانات ولغة وإطار عمل
نقطة الضعف:
- التوزيع العشوائي يسبب تجزئة فهرس B-tree. في الجداول كثيفة الكتابة بملايين الصفوف، يمكن لمفاتيح v4 الأساسية إبطاء أداء الإدراج بـ 2-10 أضعاف مقارنة بالمعرّفات التسلسلية بسبب انقسامات الصفحات المفرطة.
// Generate UUID v4 — built-in in all modern browsers and Node.js
const id = crypto.randomUUID();
// → "550e8400-e29b-41d4-a716-446655440000"
UUID v5 — تجزئة حتمية
يجزّئ UUID v5 معرّف مساحة اسم UUID وسلسلة نصية باستخدام SHA-1 لإنتاج UUID حتمي. نفس المدخلات تنتج دائمًا نفس المخرجات.
حالات الاستخدام: توليد معرّفات مستقرة من عناوين URL أو أسماء DNS أو أي مدخل قابل للتكرار. فضّل v5 على v3 (الذي يستخدم MD5 الأضعف).
import uuid
# Same inputs → same UUID, every time
id = uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17"
UUID v7 — عشوائي مرتب زمنيًا (موصى به)
يضمّن UUID v7 (RFC 9562، مايو 2024) طابعًا زمنيًا بـ 48 بت بالملي ثانية في البتات الأكثر أهمية، متبوعًا بـ 74 بت من العشوائية المشفرة.
لماذا v7 هو الافتراضي الجديد لمفاتيح قواعد البيانات:
- إدراجات تسلسلية: المعرّفات الجديدة دائمًا أكبر من السابقة (ضمن دقة الملي ثانية)، فتُلحق إدراجات B-tree دائمًا بنهاية الفهرس
- انقسامات صفحات أقل بنسبة تصل إلى 90% مقارنة بـ v4 في أعباء العمل كثيفة الكتابة
- ترتيب زمني طبيعي بدون عمود
created_atإضافي - نوع عمود
uuidقياسي — لا تغييرات مخطط مطلوبة عند الترحيل من v4 - 74 بت من العشوائية — كافية لجميع التطبيقات تقريبًا (v4 لديه 122 بت)
المقايضة: الطابع الزمني للإنشاء مضمّن في المعرّف. إذا كنت بحاجة لمعرّفات معتمة لا تكشف وقت الإنشاء، التزم بـ v4.
// UUID v7 generation (Node.js 20+)
import { v7 as uuidv7 } from "uuid";
const id = uuidv7();
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// Older IDs always sort before newer ones
أداء PostgreSQL و MySQL: v4 مقابل v7
اختبارات أداء على جدول PostgreSQL 16 بـ 50 مليون صف (مفتاح أساسي B-tree):
| المقياس | UUID v4 | UUID v7 | التحسن |
|---|---|---|---|
| إنتاجية الإدراج (صف/ثانية) | 12,400 | 28,600 | أسرع 2.3 مرة |
| حجم الفهرس بعد 50 مليون صف | 4.2 GB | 2.8 GB | أصغر 33% |
| انقسامات الصفحات أثناء الإدراج المجمّع | 1.2M | 84K | أقل 93% |
| الفحص التسلسلي بعد الإدراج | 320 ms | 180 ms | أسرع 44% |
في MySQL/InnoDB، التأثير أكثر دراماتيكية لأن المفتاح الأساسي هو الفهرس المتجمّع — معرّفات v4 العشوائية تفرض إعادة تنظيم مستمرة للصفحات، بينما يتصرف v7 كمعرّف تلقائي متزايد.
أنظمة المعرّفات البديلة
ULID — البطل قبل v7
أُنشئ ULID (معرّف فريد عالميًا قابل للترتيب معجميًا) في 2016 لحل مشكلة عدم قابلية ترتيب UUID v4. يرمّز طابعًا زمنيًا بـ 48 بت بالملي ثانية متبوعًا بـ 80 بت من العشوائية في سلسلة نصية Crockford Base32 من 26 حرفًا.
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Randomness
48 bits 80 bits
ULID مقابل UUID v7 — هل يجب التبديل؟
| الجانب | ULID | UUID v7 |
|---|---|---|
| قابل للترتيب | نعم | نعم |
| طول السلسلة | 26 حرفًا | 36 حرفًا |
| التخزين | 16 بايت | 16 بايت |
| المعيار | مواصفة مجتمعية | IETF RFC 9562 |
| نوع قاعدة بيانات أصلي | لا (CHAR(26) أو BYTEA) | نعم (uuid) |
| دعم اللغات | npm، PyPI، crates.io | مدمج في معظم المكتبات القياسية |
الحكم: إذا كنت تبدأ من الصفر، استخدم UUID v7 — يتمتع بنفس القابلية للترتيب مع دعم نظام بيئي أفضل بكثير وأنواع قواعد بيانات أصلية. إذا كنت تستخدم ULID بالفعل، فهو يعمل بشكل جيد — لا حاجة عاجلة للترحيل؛ الاثنان مكافئان وظيفيًا.
Snowflake ID — الأنظمة الموزعة عالية الإنتاجية
أنشأت Twitter معرّف Snowflake في 2010، يحزم عددًا صحيحًا بـ 64 بت مع:
0 | 41 bits timestamp | 10 bits worker ID | 12 bits sequence
- طابع زمني 41 بت: ملي ثانية منذ حقبة مخصصة (~69 سنة من النطاق)
- معرّف عامل 10 بت: يدعم 1,024 عاملًا فريدًا
- تسلسل 12 بت: حتى 4,096 معرّفًا في الملي ثانية لكل عامل
نقاط القوة:
- 8 بايت — نصف حجم UUID/ULID، يتسع في عمود
BIGINT - رتيب داخل العامل — ترتيب مضمون لكل عقدة
- 4.096 مليون معرّف/ثانية إنتاجية نظرية لكل عامل
- مقروء بشريًا كعدد صحيح عادي
نقاط الضعف:
- يتطلب تنسيقًا مركزيًا — يجب تعيين وإدارة معرّفات العمال (عادة عبر ZooKeeper أو etcd أو خدمة تكوين)
- حساسية انحراف الساعة — إذا انحرفت ساعات النظام، يمكن أن تتصادم المعرّفات أو تعود للوراء
- حقبة مخصصة — كل تطبيق يختار حقبته، مما يصعّب التوافق بين الأنظمة
- ليس معيارًا — عشرات المتغيرات غير المتوافقة (Twitter، Discord، Instagram، إلخ)
// Snowflake ID generation (using sony/sonyflake)
package main
import (
"fmt"
"github.com/sony/sonyflake"
)
func main() {
sf := sonyflake.NewSonyflake(sonyflake.Settings{})
id, _ := sf.NextID()
fmt.Println(id) // → 175928847299543040
}
متى تختار Snowflake: نظامك يولّد >100K معرّف/ثانية، وتحتاج أعدادًا صحيحة مدمجة بـ 64 بت، ولديك بالفعل بنية تحتية لتعيين معرّفات العمال (مثلًا ترتيبيات حاضنات Kubernetes).
NanoID — معرّفات مدمجة آمنة لعناوين URL
يولّد NanoID معرّفات قصيرة (افتراضيًا 21 حرفًا) وآمنة لعناوين URL باستخدام الأبجدية A-Za-z0-9_-. يستخدم crypto.getRandomValues() للأمان.
import { nanoid } from "nanoid";
const id = nanoid(); // → "V1StGXR8_Z5jdHi6B-myT"
const short = nanoid(10); // → "IRFa-VaY2b"
الأفضل لـ: عناوين URL القصيرة، مفاتيح مكونات الواجهة الأمامية، رموز الدعوة، أسماء الملفات — في أي مكان يهم فيه طول السلسلة النصية ولا تحتاج لترتيب على مستوى قاعدة البيانات أو توافق بين الأنظمة.
غير مثالي لـ: مفاتيح قواعد البيانات الأساسية (لا نوع قاعدة بيانات أصلي، لا قابلية ترتيب، لا طابع زمني).
CUID2 — مقاوم للتصادمات على نطاق واسع
يولّد CUID2 معرّفات بطول متغير مصممة للتوسع الأفقي. يدمج عدادًا وطابعًا زمنيًا وبصمة وعشوائية.
حالة استخدام متخصصة: أنظمة تحتاج مقاومة التصادم عبر مولّدات مستقلة عديدة بدون تنسيق. عمليًا، يغطي UUID v7 هذه الحاجة بتوحيد معايير أفضل.
جدول مقارنة شامل
| الميزة | UUID v4 | UUID v7 | ULID | Snowflake | NanoID |
|---|---|---|---|---|---|
| الطول | 36 حرفًا | 36 حرفًا | 26 حرفًا | 15–20 رقمًا | 21 حرفًا (افتراضي) |
| التخزين | 16 بايت | 16 بايت | 16 بايت | 8 بايت | ~21 بايت |
| قابل للترتيب | لا | نعم (زمنيًا) | نعم (زمنيًا) | نعم (زمنيًا) | لا |
| طابع زمني | لا | 48 بت ms | 48 بت ms | 41 بت ms | لا |
| العشوائية | 122 بت | 74 بت | 80 بت | 12 بت تسلسل | ~126 بت |
| المعيار | RFC 9562 | RFC 9562 | مجتمعي | ملكي | مجتمعي |
| نوع قاعدة بيانات أصلي | uuid | uuid | لا | BIGINT | لا |
| التنسيق | لا شيء | لا شيء | لا شيء | سجل عمال | لا شيء |
| آمن لعناوين URL | لا (شرطات) | لا (شرطات) | نعم | نعم (عدد صحيح) | نعم |
| التصادم عند مليون معرّف | ~10⁻²² | ~10⁻¹⁸ | ~10⁻²⁰ | صفر (رتيب) | ~10⁻²¹ |
أمثلة برمجية: توليد كل نوع معرّف
JavaScript / TypeScript
import { v4 as uuidv4, v7 as uuidv7 } from "uuid";
import { ulid } from "ulid";
import { nanoid } from "nanoid";
// UUID v4
console.log(uuidv4());
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
console.log(uuidv7());
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
console.log(ulid());
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
console.log(nanoid());
// → "V1StGXR8_Z5jdHi6B-myT"
Python
import uuid
from ulid import ULID
from nanoid import generate
# UUID v4
print(uuid.uuid4())
# → "a8098c1a-f86e-11da-bd1a-00112444be1e"
# UUID v7 (Python 3.14+ planned, or use uuid7 package)
from uuid_extensions import uuid7
print(uuid7())
# → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
# ULID
print(ULID())
# → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
# NanoID
print(generate(size=21))
# → "V1StGXR8_Z5jdHi6B-myT"
Go
package main
import (
"fmt"
"github.com/google/uuid" // UUID v4 & v7
"github.com/oklog/ulid/v2" // ULID
gonanoid "github.com/matoous/go-nanoid/v2" // NanoID
)
func main() {
// UUID v4
fmt.Println(uuid.New())
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
fmt.Println(uuid.Must(uuid.NewV7()))
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
fmt.Println(ulid.Make())
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
id, _ := gonanoid.New()
fmt.Println(id)
// → "V1StGXR8_Z5jdHi6B-myT"
}
الترحيل من UUID v4 إلى v7
إذا كان نظامك يستخدم بالفعل مفاتيح UUID v4 الأساسية وتريد مزايا أداء v7، إليك الخبر السار: v4 وv7 يتشاركان نفس التنسيق بـ 128 بت ويُخزّنان في نفس نوع عمود uuid. لا حاجة لترحيل المخطط.
استراتيجية الترحيل
- السجلات الجديدة تستخدم v7، القديمة تبقى v4. كلاهما يتعايشان في نفس العمود. الاستعلامات والربطات تعمل بشكل متطابق.
- حدّث كود توليد المعرّفات — استبدل
uuidv4()بـuuidv7()في طبقة التطبيق. - لا تعد كتابة معرّفات v4 الموجودة. هذا سيكسر المفاتيح الأجنبية والمراجع الخارجية وعناوين URL المخزنة مؤقتًا.
- راقب أداء الفهرس. مع تحول نسبة v4/v7 نحو v7، ستنخفض تجزئة الفهرس تدريجيًا.
فحص التوافق
-- Both v4 and v7 coexist in the same uuid column
SELECT id, version FROM (
SELECT id,
CASE get_byte(id::bytea, 6) >> 4
WHEN 4 THEN 'v4'
WHEN 7 THEN 'v7'
ELSE 'other'
END AS version
FROM your_table
) t
GROUP BY version;
الأسئلة الشائعة
هل أستخدم UUID v7 أم أعدادًا صحيحة تلقائية التزايد؟
الأعداد الصحيحة التلقائية أبسط وأصغر (4-8 بايت مقابل 16 بايت)، لكنها تتطلب تسلسلًا مركزيًا — فقط قاعدة البيانات يمكنها توليدها. يمكن توليد UUID v7 في أي مكان (العميل، الحافة، الخدمة المصغرة) بدون رحلة ذهاب وإياب لقاعدة البيانات. استخدم التزايد التلقائي للتطبيقات البسيطة بقاعدة بيانات واحدة؛ استخدم UUID v7 للأنظمة الموزعة والبنيات متعددة المستأجرين أو عندما تحتاج لتوليد المعرّفات من جانب العميل.
هل 74 بت من العشوائية في UUID v7 كافية؟
نعم. 74 بت عشوائية تعطي 2⁷⁴ ≈ 1.9 × 10²² قيمة ممكنة لكل ملي ثانية. حتى مع توليد مليون معرّف في الملي ثانية، احتمال التصادم حوالي 10⁻¹⁰ — أقل بكثير من أي قلق عملي. 122 بت عشوائية في UUID v4 مبالغ فيها لمعظم التطبيقات.
هل يمكنني استخراج الطابع الزمني من UUID v7؟
نعم. أول 48 بت ترمّز طابعًا زمنيًا بالملي ثانية:
function extractTimestamp(uuidv7) {
const hex = uuidv7.replace(/-/g, "").slice(0, 12);
const ms = parseInt(hex, 16);
return new Date(ms);
}
extractTimestamp("01906b5e-4a3e-7234-8f56-b8c12d4e5678");
// → 2024-07-01T12:34:56.000Z
هذه ميزة وليست عيبًا — لكن إذا كنت بحاجة لمعرّفات معتمة، استخدم v4.
هل يدعم PostgreSQL 18 نظام UUID v7 أصليًا؟
يضيف PostgreSQL 18 (صدر 2025) دالة uuidv7() مدمجة، مما يلغي الحاجة لامتدادات مثل pgcrypto أو pg_uuidv7. لا يمتلك MySQL بعد توليدًا أصليًا لـ v7 — ولّد في طبقة التطبيق.
لماذا لا أستخدم ULID فحسب؟
سبق ULID ظهور UUID v7 ويحل نفس المشكلة. الآن وقد أصبح v7 معيار IETF (RFC 9562)، يتمتع بمزايا رئيسية: نوع قاعدة بيانات uuid أصلي (16 بايت، مفهرس بكفاءة)، ودعم أوسع من اللغات/أطر العمل، وتوحيد معايير رسمي. إذا كنت تستخدم ULID بالفعل، فهو يعمل بشكل جيد — لا حاجة للترحيل. للمشاريع الجديدة، فضّل UUID v7.
متى يكون Snowflake ID الخيار الأفضل؟
عندما تحتاج معرّفات مدمجة بـ 64 بت بإنتاجية متطرفة (>100K معرّف/ثانية لكل عقدة) ولديك بالفعل بنية تحتية لتعيين معرّفات العمال. تخزين Snowflake بـ 8 بايت BIGINT هو نصف حجم UUID، وهو مهم عند مليارات الصفوف. المقايضة هي التعقيد التشغيلي: يجب عليك إدارة تخصيص معرّفات العمال والتعامل مع انحراف الساعة.
تحتاج لتوليد UUIDs الآن؟ جرّب مولّد UUID — يدعم v1 وv4 وv5 وv7 مع التوليد بالجملة وفك الترميز، 100% في متصفحك.