مولّد ULID
يولد معرفات فريدة قابلة للترتيب أبجدياً
انقر على توليد لإنشاء ULIDs
ما هو ULID؟
ULID (المعرّف الفريد العالمي القابل للترتيب لغوياً) هو تنسيق معرّف 128 بت مصمَّم ليكون فريداً وقابلاً للترتيب بطبيعته. خلافاً لـ UUID v4 العشوائي كلياً، يضمّ ULID طابعاً زمنياً Unix بدقة المللي ثانية في بتاته العليا — مما يضمن أن المعرّفات المولَّدة لاحقاً تُرتَّب بعد المعرّفات المولَّدة سابقاً.
تُرمَّز ULIDs باستخدام أبجدية Crockford Base32، منتجةً سلسلة مضغوطة مكوّنة من 26 حرفاً آمنة في عناوين URL وغير حساسة لحالة الأحرف وخالية من الأحرف الملتبسة بصرياً.
أنشأ مواصفة ULID Alizain Feerasta وتُستخدَم على نطاق واسع في الأنظمة الموزّعة وتوليد الأحداث والمفاتيح الأساسية لقواعد البيانات حيث يهمّ التفرّد والترتيب الزمني معاً. ULIDs ليست معياراً IETF — إنها مواصفة مجتمعية متاحة على ulid.github.io.
بنية ULID
ULID عرضه 128 بت، مقسَّمة على مكوّنين:
| الطابع الزمني | عشوائي |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 48 بتاً — طابع زمني Unix بالمللي ثانية. يرمّز وقت التوليد بدقة 1 مللي ثانية. يغطّي التواريخ حتى عام 10889. | 80 بتاً — بيانات عشوائية آمنة تشفيرياً. تُعاد توليدها من جديد لكل ULID (ما لم يُستخدَم وضع الرتابة). |
مرمَّزة كـ 26 حرفاً من Crockford Base32: أول 10 أحرف تمثّل الطابع الزمني، آخر 16 حرفاً تمثّل المكوّن العشوائي.
أبجدية Crockford Base32
تستخدم ULIDs ترميز Crockford Base32، الذي يستخدم 32 من أصل 36 حرفاً حروفياً رقمياً. الأبجدية هي: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
أربعة أحرف مستبعَدة عمداً:
IوLمستبعَدان — يُخلَطان بسهولة بالرقم1Oمستبعَد — يُخلَط بسهولة بالرقم0Uمستبعَد — يتجنّب ظهور كلمات مسيئة بالصدفة في المعرّفات المولَّدة- الترميز
غير حساس لحالة الأحرف—01ARZ3NDEKTSV4RRFFQ69G5FAVو01arz3ndektsv4rrffq69g5favهما ULID ذاته
Crockford Base32 أكفأ من السداسي عشري (32 رمزاً مقابل 16) وأكثر قابلية للقراءة البشرية من Base64 (لا أحرف + / = وغير حساس لحالة الأحرف).
ULID مقابل UUID
كل من ULID وUUID يمثّلان معرّفات 128 بت، لكنهما يختلفان اختلافاً كبيراً في الترميز وأهداف التصميم:
| الخاصية | ULID | UUID |
|---|---|---|
| التنسيق | Crockford Base32 | سداسي عشري بواصلات |
| الطول | 26 حرفاً | 36 حرفاً |
| الطابع الزمني | 48 بت Unix ms | لا شيء (v4) أو 48 بت ms (v7) |
| قابل للترتيب | نعم — لغوي | لا (v4) / نعم (v7) |
| آمن في URL | نعم (حروفي رقمي فقط) | نعم (مع واصلات) |
| التبعيات | يتطلب مكتبة | أصيلي (crypto.randomUUID) |
| دعم قاعدة البيانات | خزّن كـ CHAR(26) أو BINARY(16) | نوع عمود UUID أصيلي |
| المواصفة | مواصفة مجتمعية (ulid.github.io) | RFC 4122 / RFC 9562 |
إذا كنت بالفعل في بيئة UUID (أعمدة uuid في PostgreSQL وواجهات برمجية وORMs بدعم UUID)، فإن UUID v7 عادةً أنسب من ULID. إذا كنت تفضّل ترميزاً أكثر ملاءمة للإنسان وتتحكّم في المكدّس الكامل، فـ ULID اختيار ممتاز.
ULID مقابل nanoid
كلٌّ من ULID وnanoid ينتجان معرّفات قصيرة آمنة في URL، لكن لكلٍّ منهما أهداف تصميم مختلفة:
| الخاصية | ULID | NanoID |
|---|---|---|
| الطابع الزمني | نعم — 48 بت Unix ms | لا |
| قابل للترتيب | نعم | لا |
| الطول الافتراضي | 26 حرفاً | 21 حرفاً |
| الإنتروبيا | 80 بتاً (المكوّن العشوائي) | ~126 بتاً |
| الأبجدية | Crockford Base32 (32 حرفاً) | Base64 آمن في URL (64 حرفاً) |
| طول قابل للتخصيص | لا | نعم (أي طول) |
| حالة الاستخدام | معرّفات مرتّبة زمنياً، مفاتيح أساسية في DB | رموز عشوائية وعناوين URL قصيرة ومفاتيح API |
اختر ULID حين تحتاج الترتيب الزمني. اختر nanoid حين تريد أقصى إنتروبيا في سلسلة قصيرة عشوائية.
استخدام ULIDs في قواعد البيانات
يمكن تخزين ULIDs في قواعد البيانات بعدة طرق حسب متطلباتك:
أمثلة الكود
يتطلب توليد ULID مكتبة ulid (متاحة لـ JavaScript وPython وGo وRust وغيرها):
// Using the 'ulid' npm package
import { ulid } from 'ulid'
const id = ulid() // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
const id2 = ulid() // "01ARZ3NDEKXXXXXXXXXXXX..." (same ms, incremented random)
// With a custom timestamp
const id3 = ulid(1469918176385) // deterministic time portion
// Extract the timestamp back out
import { decodeTime } from 'ulid'
decodeTime(id) // → 1469918176385 (Unix ms)# Using python-ulid
from ulid import ULID
uid = ULID()
str(uid) # "01ARZ3NDEKTSV4RRFFQ69G5FAV"
uid.timestamp # 1469918176.385
uid.datetime # datetime(2016, 7, 30, 23, 36, 16, 385000, tzinfo=timezone.utc)
# Parse an existing ULID string
parsed = ULID.from_str("01ARZ3NDEKTSV4RRFFQ69G5FAV")
parsed.timestamp # 1469918176.385-- Store ULIDs as TEXT or CHAR(26)
CREATE TABLE events (
id CHAR(26) PRIMARY KEY DEFAULT gen_ulid(), -- if using a PG extension
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Or pass the ULID from your application layer
INSERT INTO events (id, name, created_at)
VALUES ('01ARZ3NDEKTSV4RRFFQ69G5FAV', 'user.signup', NOW());
-- Range queries are efficient because ULIDs sort chronologically
SELECT * FROM events
WHERE id > '01ARZ3NDEKTSV4RRFFQ69G5FAV'
ORDER BY id
LIMIT 20;// Pure browser / Deno / Node.js implementation (no dependencies)
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
function encodeTime(ms) {
let result = '', n = BigInt(ms)
for (let i = 9; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function encodeRandom(bytes) {
let n = 0n
for (const b of bytes) n = (n << 8n) | BigInt(b)
let result = ''
for (let i = 15; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function generateULID() {
const randomBytes = new Uint8Array(10)
crypto.getRandomValues(randomBytes)
return encodeTime(Date.now()) + encodeRandom(randomBytes)
}