مولّد ULID

ولّد ULID قابلة للفرز بطول 26 حرفًا (Crockford base32) وفكّك الطابع الزمني المضمّن عائدًا إلى تاريخ. رائعة للمفاتيح الأساسية في قواعد البيانات.

معرّفات فريدة قابلة للفرز. ULID يتكون من 26 حرفًا: أول 10 منها ترمّز وقت الإنشاء بالميلي ثانية، والـ 16 الأخيرة عشوائية. هذا يجعلها قابلة للفرز معجميًا وآمنة للاستخدام كمفاتيح. تُولَّد في متصفحك.

ULID مقابل UUID

ما هو ULID

ULID هو معرّف بعرض 128 بت، نفس عرض UUID، مقسوم إلى جزأين: طابع زمني بالميلي ثانية بعرض 48 بت تليه 80 بت عشوائية. يُعرض كـ 26 حرفًا من Crockford base32 بدلًا من 36 حرفًا سداسيًا موصولًا بشرطات كما في UUID، لذا فهو أقصر وغير حساس لحالة الأحرف وخالٍ من الأحرف الأكثر عرضة لسوء القراءة — I وL وO وU كلها مستبعدة من الأبجدية.

الفرق الجوهري ليس في الترميز، بل في الترتيب. لأن الطابع الزمني يحتل البتات العالية وbase32 يحافظ على ترتيب البايتات، فإن فرز ULID كسلاسل نصية عادية يفرزها حسب وقت الإنشاء. معرّفان وُلّدا في نفس الميلي ثانية يعودان إلى مكونهما العشوائي، لكن عبر الميلي ثوانٍ يكون الترتيب دقيقًا.

لماذا تهم القابلية للفرز في قواعد البيانات

UUIDv4 عشوائي تمامًا، وهذا بالضبط ما لا تريده في فهرس متفاوت. كل إدراج يقع في نقطة عشوائية في شجرة B، لذا تظل قاعدة البيانات تقسم الصفحات وتلمس الباردة منها. ينمو الفهرس أكبر من حاجته ويتدهور إنتاج الكتابة مع نمو الجدول. هذه مشكلة موثقة جيدًا مع مفاتيح UUID الأساسية في InnoDB في MySQL وفي SQL Server.

المعرّف المرتّب زمنيًا يُلحق قرب الحافة اليمنى للفهرس، وهو نفس نمط الوصول لعدد صحيح متزايد تلقائيًا. تحتفظ بفوائد المفتاح الفريد المولّد من العميل — لا رحلة ذهاب وعودة للحصول على معرّف، لا تنسيق بين الخدمات، دمج آمن عبر الأجزاء — دون تجزئة الفهرس.

متى تستخدم شيئًا آخر

UUIDv7، الموحّد في RFC 9562، يفعل الشيء نفسه الذي يفعله ULID في صيغة UUID المعيارية وتخطيطها. إذا كان لديك أعمدة وأدوات UUID أصلية في مجموعتك التقنية، فعادةً ما يكون UUIDv7 هو الخيار الأفضل الآن ببساطة لأنه يندمج في النظام البيئي القائم. يبقى ULID جذابًا عندما تريد الشكل النصي الأقصر والأسهل في عناوين URL أو السجلات.

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

ملاحظة مفتوحة المصدر: منفّذ بـ crypto.getRandomValues وترميز Crockford base32 مكتوب من الصفر. لا مكتبات خارجية.

الأسئلة الشائعة

كيف يختلف ULID عن UUID؟
كلاهما 128 بت، لكن ULID يضع طابعًا زمنيًا بالميلي ثانية بعرض 48 بت أولًا، لذا فرز السلاسل يفرزها حسب وقت الإنشاء. UUIDv4 عشوائي تمامًا ويُفرز عشوائيًا.
لماذا تهم القابلية للفرز في قاعدة البيانات؟
المفاتيح الأساسية العشوائية تبعثر الإدراجات عبر شجرة B وتجزّئ الفهرس. المفاتيح المرتّبة زمنيًا تُلحق قرب النهاية، ما يبقي الكتابة متسلسلة والصفحات الساخنة صغيرة.
هل تبقى المعرّفات المولّدة في نفس الميلي ثانية مرتبة؟
في الوضع الرتيب، نعم. بدلًا من إعادة رسم الجزء العشوائي تزيد الأداة منه، لذا تخرج عدة معرّفات مولّدة خلال ميلي ثانية واحدة بالترتيب.
هل من الآمن كشف ULID علنًا؟
النصف العشوائي لا يمكن تخمينه، لكن الطابع الزمني مقروء لأي شخص. إذا كان وقت إنشاء سجل حساسًا، فلا تستخدم ULID كمعرّف عام له.
هل أختار ULID أم UUIDv7؟
يحلان نفس المشكلة. UUIDv7 موحّد في RFC 9562 ويناسب أعمدة ومكتبات UUID القائمة، لذا فضّله للعمل الجديد إلا إذا أردت تحديدًا صيغة Crockford المكونة من 26 حرفًا.
لماذا 26 حرفًا؟
ترميز 128 بت في Crockford Base32 يتطلب 26 رمزًا. تستبعد الأبجدية I وL وO وU لتجنب أخطاء النقل والكلمات العرضية.