Skip to content
العودة إلى المدوّنة
دروس تعليمية

ما هو ULID؟ دليل المعرّف الفريد القابل للفرز

ما هو ULID؟ كيف يعمل هذا المعرّف القابل للفرز بطول 128 بت: بنية الطابع الزمني مع العشوائية، وترميز Crockford Base32، ومتى تختاره بدلاً من UUID.

12 دقيقة للقراءة

ما هو ULID؟ شرح المعرّف الفريد القابل للفرز

كل معرّف UUIDv4 عشوائي تُدرجه كمفتاح أساسي (primary key) يحطّ في موضع غير متوقّع داخل فهرس قاعدة البيانات. كرّر ذلك بضعة ملايين من المرات وسيتجزّأ الفهرس، ويضطرب التخزين المؤقت، وتتباطأ عمليات الكتابة. يعالج ULID هذه المشكلة دون أن تفقد ما أعجبك في معرّفات UUID: ما زال بإمكانك توليد واحد في أي مكان، بلا منسّق مركزي، لكنه يحطّ مرتّباً زمنياً بدلاً من أن يتبعثر.

إذن كيف تفرز سلسلة من 26 حرفاً نفسها بحسب الزمن؟ هذه هي الحيلة كلها، ويجدر بك فهمها قبل أن تلجأ إليها.

إنّ ULID (المعرّف الفريد عالمياً القابل للفرز معجمياً) هو معرّف بطول 128 بت يُكتب كـ 26 حرفاً بترميز Crockford Base32. تُرمّز الأحرف العشرة الأولى طابعاً زمنياً بالميلّي ثانية، وتُرمّز الأحرف الستة عشر الأخيرة بتات عشوائية، لذا تأتي معرّفات ULID المُنشأة لاحقاً دائماً بعد السابقة عند مقارنتها كسلاسل نصّية عادية. إنه معرّف فريد قابل للفرز يمكنك توليده دون اتصال.

يفكّك هذا الدليل ذلك بالتفصيل: البنية مفكّكة حرفاً حرفاً، والبرهان على أنه يُفرز فعلاً، وحسابات شجرة B-tree الكامنة وراء المكسب في قاعدة البيانات، ونظرة صادقة إلى ما يُفشيه الطابع الزمني المُضمَّن. يمكنك المتابعة بقيمة حيّة في مولّد ULID — ولّد واحداً، وفُكّ ترميزه، وحوّله إلى UUID — وأنت تقرأ.

ما هو ULID؟

إنّ ULID (المعرّف الفريد عالمياً القابل للفرز معجمياً) هو معرّف بطول 128 بت مُصمَّم كبديل أكثر قابلية للفرز وأكثر إيجازاً عن UUID. يُكتب كـ 26 حرفاً بترميز Crockford Base32: تحمل الأحرف العشرة الأولى طابعاً زمنياً بطول 48 بت بالميلّي ثانية منذ حقبة Unix، وتحمل الأحرف الستة عشر المتبقية 80 بت من العشوائية. ولأن الزمن يأتي أولاً، تُفرز السلسلة ترتيباً زمنياً.

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

إليك التنسيق في لمحة:

الخاصيةالقيمة
البتات128
الترميز26 حرفاً بترميز Crockford Base32
التخطيططابع زمني بطول 48 بت + عشوائية بطول 80 بت

تشرح بقية هذه المقالة كيفية عمل كل جزء. يستحقّ الترميز والقابلية للفرز قسمين خاصّين بهما، لذا سنصل إلى Base32 وبرهان الترتيب قريباً — أولاً، التخطيط.

بنية ULID: 48 بت للزمن + 80 بت للعشوائية

تنقسم أحرف ULID الـ 26 بوضوح إلى نصفين. الأحرف العشرة الأولى هي الطابع الزمني؛ والأحرف الستة عشر الأخيرة هي الجزء العشوائي. افرد المثال القانوني وسيتّضح الحدّ الفاصل فوراً:

01ARYZ6S41   TSV4RRFFQ69G5FAV
└────────┘   └──────────────┘
 10 chars        16 chars
48-bit ms      80-bit random
timestamp

مكوّنان، ووظيفتان. أحدهما يسجّل متى؛ والآخر يضمن التفرّد. لنفكّ ترميز كلٍّ منهما.

الطابع الزمني بطول 48 بت (الأحرف العشرة الأولى)

تُرمّز الأحرف العشرة الأولى عدداً صحيحاً بطول 48 بت: عدد الميلّي ثوانٍ منذ حقبة Unix في اللحظة التي أُنشئ فيها ULID. خذ المثال القانوني مباشرةً من المواصفة:

01ARYZ6S41  ->  1469918176385 ms  ->  2016-07-30T22:36:16.385Z

هذا فكّ ترميز حقيقي وقابل للعكس — الصق 01ARYZ6S41TSV4RRFFQ69G5FAV في أداة فكّ الترميز وستحصل على 2016-07-30T22:36:16.385Z بالضبط. مكوّن الزمن هو بيانات صريحة، وليس قيمة تجزئة (hash)، لذا فقراءته لا تكلّف شيئاً.

تفصيل صغير يربك الناس: الحرف الأول من أي ULID يقع دائماً بين 0 و7. يحمل حرف Crockford خمسة بتات، و48 بت ليست من مضاعفات 5 — يشغل الطابع الزمني البتات الـ 48 الدنيا من البتات الخمسين التي تستطيع 10 أحرف حملها، تاركاً أعلى بتّين من الحرف الأول صفرين دائماً. والبتّان الصفريان يحدّان قيمة ذلك الحرف عند 7. فإذا رأيت يوماً ULID يبدأ بـ 8 أو أعلى، فهو مشوّه.

الـ 80 بت من العشوائية (الأحرف الستة عشر الأخيرة)

تحمل الأحرف الستة عشر المتبقية 80 بت من العشوائية، وهذا النصف هو مصدر التفرّد. ينبغي أن تأتي البتات من مصدر آمن تشفيرياً — crypto.getRandomValues في المتصفّح، لا Math.random. والفرق مهمّ: Math.random قابل للتنبّؤ بدرجة كافية لأن يخمّن مهاجم القيم أو يصطدم بها، أما مولّد الأرقام العشوائية الآمن تشفيرياً (CSPRNG) فلا.

كم تتّسع 80 بت؟ نحو 1.2 × 10²⁴ قيمة ممكنة، وذلك في كل ميلّي ثانية. وحتى لو ولّدت ملايين معرّفات ULID داخل ميلّي ثانية واحدة، تبقى احتمالات أن يسحب اثنان منها البتات الثمانين نفسها ضئيلة جداً. وعلى خلاف الطابع الزمني، لا يحمل هذا النصف أي معنى قابل لفكّ الترميز — إنه ضجيج هدفه الوحيد جعل كل ULID متميّزاً.

ترميز Crockford Base32: لماذا تسقط معرّفات ULID الأحرف I وL وO وU

تُرمّز معرّفات ULID بترميز Crockford Base32، وهو أبجدية من 32 رمزاً: الأرقام 09 والأحرف AZ مع حذف أربعة أحرف.

0123456789ABCDEFGHJKMNPQRSTVWXYZ

الأحرف المحذوفة هي I وL وO وU. حُذفت ثلاثة منها لأنها تشبه الأرقام — يشبه I وL الرقم 1، ويشبه O الرقم 0 — حتى لا يخلط إنسان يقرأ ULID من على شاشة بين حرف ورقم. والوجه الآخر هو تساهل الإدخال: تعيد أداة فكّ ترميز متوافقة الحرفين I وL إلى 1 والحرف O إلى 0، وتعامل السلسلة كلها دون تمييز بين حالة الأحرف الكبيرة والصغيرة. أما U فاستُبعد على حدة، تفادياً للتهجئة العرضية لكلمات مسيئة.

حساب البتات هو السبب الآخر. يرمّز كل حرف من Base32 خمسة بتات، بينما يرمّز الحرف السّت عشري أربعة بتات فقط. عبّئ 128 بت بمعدّل 5 بتات لكل حرف وستحتاج إلى 26؛ وعبّئ الـ 128 بت ذاتها بمعدّل 4 بتات لكل حرف — كما تفعل UUID — وستحتاج إلى 32، إضافة إلى أربع شَرَطات، أي 36 حرفاً. لذا فإن ULID أقصر بوضوح من UUID، وبلا شَرَطات، يندرج مباشرةً في عنوان URL أو اسم ملف أو ترويسة (header) دون الحاجة إلى أحرف هروب (escaping).

إنّ Crockford Base32 أبجدية من 32 رمزاً (09 وAZ ناقص I وL وO وU) تُرمّز خمسة بتات لكل حرف. تستخدمها معرّفات ULID لتعبئة 128 بت في 26 حرفاً غير حسّاسة لحالة الأحرف وآمنة في عناوين URL، والأهم — أن الأبجدية مرتّبة تصاعدياً، وهذا ما يجعل السلسلة المُرمّزة تُفرز بالطريقة نفسها التي تُفرز بها البتات الخام.

لماذا تُفرز معرّفات ULID بحسب الزمن

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

اجمع الاثنين وستحصل على سلسلة من التكافؤات:

string compare  ==  128-bit integer compare  ==  creation-time compare

اقرأها من اليسار إلى اليمين. مقارنة معرّفي ULID حرفاً حرفاً (الطريقة التي يعمل بها فرز السلاسل) تعطي الإجابة نفسها التي تعطيها مقارنة عددَيهما الصحيحين بطول 128 بت، لأن الأبجدية تحفظ الترتيب — فالحرف «الأعلى» يعني دائماً قيمة أعلى. ومقارنة العددين الصحيحين بطول 128 بت تعطي الإجابة نفسها التي تعطيها مقارنة أوقات الإنشاء، لأن الطابع الزمني يقع في البتات الأهمّ، فيهيمن على المقارنة؛ ولا يفصل الذيل العشوائي إلا التعادلات ضمن الميلّي ثانية نفسها. ترتيب السلسلة، وترتيب البتات، وترتيب الزمن هي الترتيب نفسه.

خذ معرّفين من ULID مُولَّدين بفارق ميلّي ثانية واحدة:

01ARYZ6S41...   (created at T)
01ARYZ6S42...   (created at T + 1 ms)

ينتقل الحرف العاشر من 1 إلى 2، وفرز نصّي عادي يضع الثاني بعد الأول — بلا عمود طابع زمني، وبلا مقارِن خاص. والمكسب العملي، الذي يوسّعه القسم التالي، سطر واحد: ORDER BY id يُرجع الصفوف بترتيب زمني دون أي فهرس إضافي.

معرّفات ULID كمفاتيح أساسية في قواعد البيانات: محلّية شجرة B-tree

هنا تثبت معرّفات ULID جدارتها. تخزّن معظم قواعد البيانات العلائقية فهرس المفتاح الأساسي كشجرة B-tree، وموضع حطّ المفتاح الجديد في تلك الشجرة هو ما يحدّد تكلفة الإدراج.

يحطّ معرّف UUIDv4 العشوائي في موضع غير متوقّع عند كل إدراج:

UUIDv4: كل مفتاح جديد يستهدف صفحة ورقية عشوائية. وغالباً ما تكون الصفحة ممتلئة، فيقسمها المحرّك، وينسخ نصف الصفوف إلى مكان آخر، ويلوّث صفحات في أرجاء الشجرة. وعبر ملايين الصفوف يجزّئ هذا الفهرس، ويطرد صفحات مفيدة من ذاكرة المخزن المؤقت، ويقلّص معدّل نفاذ الإدراج. (للاطّلاع على أرقام انقسام صفحات الفهرس الدقيقة — وهي عادةً فارق 2–10× في الجداول كثيفة الكتابة — انظر دليل المقارنة.)

أما معرّف ULID المسبوق بطابع زمني فيحطّ في النهاية في كل مرة:

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

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

نصيحة للتخزين: خزّن الـ 128 بت كـ 16 بايتاً ثنائياً — عمود uuid في PostgreSQL، وBINARY(16) في MySQL — لا كحقل نصّي من 26 حرفاً، فهذا يهدر المساحة وينتفخ به الفهرس. رمّز إلى سلسلة Base32 فقط عند الأطراف حيث يراها إنسان أو عنوان URL. ستقوم لسان «التحويل» في المولّد بـتحويل ULID إلى UUID لهذا الغرض تحديداً، لأن الشكلين هما الـ 128 بت ذاتها.

معرّفات ULID الرتيبة: ترتيب صارم ضمن الميلّي ثانية

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

يسدّ التوليد الرتيب (monotonic) الثغرة. القاعدة بسيطة: يحصل أول ULID في ميلّي ثانية معيّنة على عشوائية جديدة كالمعتاد، وكل ULID لاحق في الميلّي ثانية ذاتها يُنتَج بأخذ القيمة العشوائية السابقة بطول 80 بت وزيادتها بمقدار واحد (تُعامَل كعدد صحيح كبير الترتيب البايتي، مع الترحيل إلى البتات الأعلى عند اللزوم). وهكذا تكون كل قيمة أكبر تماماً من سابقتها.

يمكنك أن ترى ذلك في دفعة مُولَّدة داخل ميلّي ثانية واحدة — يتحرّك الحرف الأخير وحده:

01KVT0F720ZK9N4T2QX7VR8WMC
01KVT0F720ZK9N4T2QX7VR8WMD
01KVT0F720ZK9N4T2QX7VR8WME

…WMC < …WMD < …WME، مضمون. وهذا يهمّ كلما أمكن إنشاء الصفوف أسرع من نبضة ساعة الميلّي ثانية: عمليات الإدراج عالية المعدّل، وسجلّات الأحداث، ومعرّفات الرسائل في حلقة مُحكمة. وحين تتقدّم الساعة إلى الميلّي ثانية التالية، يعود التوليد إلى عشوائية جديدة وتتكرّر الدورة.

ULID مقابل UUID: متى تستخدم أيّاً منهما

السؤال الذي يطرحه معظم الناس هو ULID مقابل UUID. إليك المقارنة المركّزة — ULID في مواجهة إصداري UUID اللذين قد توازنه بهما واقعياً. (للاطّلاع على مصفوفة القرار الخماسية الكاملة بما فيها Snowflake وNanoID، انظر المقارنة الكاملة بين ULID وUUID وSnowflake.)

الخاصيةULIDUUIDv4UUIDv7
الطول26 حرفاً36 حرفاً36 حرفاً
الترميزCrockford Base32سّت عشري بشَرَطاتسّت عشري بشَرَطات
قابل للفرز بحسب الزمن؟نعملانعم
يضمّن طابعاً زمنياً؟نعم (48 بت بالميلّي ثانية)لانعم (48 بت بالميلّي ثانية)
موحّد قياسياً؟مواصفة مجتمعيةRFC 9562RFC 9562
الأنسب لـمعرّفات قصيرة قابلة للفرزمعرّفات عشوائية معتمةمعرّفات قابلة للفرز بتنسيق UUID

وبالكلام: الجأ إلى ULID حين تريد أقصر سلسلة آمنة في URL وقابلة للفرز. والجأ إلى UUIDv4 حين تريد معرّفاً معتماً عشوائياً بالكامل بلا زمن مُضمَّن — مثلاً رمز عام تفضّل ألا تكشف فيه متى أُنشئ. والجأ إلى UUIDv7 حين تحتاج إلى الترتيب الزمني لكن يلزمك البقاء داخل تنسيق UUID القياسي، ببتات الإصدار والمتغيّر في مواضعها الثابتة وعمود uuid أصيل تُدرجه فيه.

الثلاثة جميعها بطول 128 بت، لذا فإن التحويل بين ULID وUUID بلا فقدان في الاتجاهين. والعلاقة بين ULID و**ulid vs uuid v7** أوثق مما تبدو: فـ UUIDv7 هو في جوهره الصياغة المعتمدة من IETF للفكرة المسبوقة بطابع زمني نفسها التي ابتكرها ULID. وإذا كنت مبتدئاً مع معرّفات UUID أساساً، فابدأ بالأساسيات أولاً، ثم عُد إلى هذه المقارنة.

مقايضة الخصوصية: معرّفات ULID تُفشي وقت إنشائها

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

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

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

مزالق شائعة مع معرّفات ULID

معظم متاعب ULID حفنة من قرارات هندسية يمكن تفاديها، لا عيوب في التنسيق. وأكثرها تكراراً:

  • افتراض أن معرّفات ULID العادية في الميلّي ثانية نفسها مرتّبة. فهي تتشارك بادئة زمن لكن ذيولها العشوائية مستقلّة، لذا ترتيبها غير معرّف. الحلّ: استخدم الوضع الرتيب حين تحتاج إلى ترتيب صارم عند معدّلات أدقّ من الميلّي ثانية.
  • تخزين ULID كنصّ من 26 حرفاً. فهذا يهدر المساحة وينفخ الفهرس. الحلّ: خزّن الـ 128 بت كـ 16 بايتاً (uuid / BINARY(16)) ورمّز إلى Base32 فقط عند الأطراف.
  • توقّع أن يُبلَّغ عن تحويل ULIDUUID على أنه v4 أو v7. فالتحويل يعيد ترميز البتات نفسها؛ ولا يضبط حقلَي إصدار UUID ومتغيّره، لذا فإن مكتبة تفحصهما لن ترى إصداراً موسوماً. الحلّ: عامِل النتيجة كقيمة معتمة بطول 128 بت، أو ولّد UUIDv7 حقيقياً حين تحتاج إلى الوسم.
  • ملء العشوائية بـ Math.random. فهو قابل للتنبّؤ ويمكن أن يصطدم. الحلّ: استخدم دائماً مولّد أرقام عشوائية آمناً تشفيرياً مثل crypto.getRandomValues.
  • كشف معرّفات ULID علناً دون موازنة تسريب الطابع الزمني. انظر قسم الخصوصية أعلاه. الحلّ: معرّفات ULID داخلية، وUUIDv4 عشوائي للمعرّفات العامة.
  • كتابة I أو L أو O أو U يدوياً في ULID. فهذه الأحرف ليست في الأبجدية، وإعادة الكتابة تدعو إلى الأخطاء. الحلّ: انسخ معرّفات ULID، ولا تُعد كتابتها.

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

هل ULID معيار رسمي مثل UUID؟

لا. إنّ ULID مواصفة مجتمعية منشورة على GitHub، وليس RFC صادراً عن IETF. وهو مُطبَّق على نطاق واسع ومستقرّ، لكن لا تقف خلفه هيئة معايير. وإذا احتجت إلى معرّف موحّد قياسياً ومرتّب زمنياً، فإن UUIDv7 (RFC 9562) يطبّق الفكرة نفسها داخل تنسيق UUID الرسمي.

كم عدد أحرف ULID، ولماذا هو أقصر من UUID؟

26 حرفاً، مقابل 36 لـ UUID. يستخدم ULID ترميز Crockford Base32 الذي يعبّئ خمسة بتات لكل حرف؛ أما الترميز السّت عشري لـ UUID فيعبّئ أربعة بتات فقط ويضيف أربع شَرَطات. لذا تحتاج الـ 128 بت ذاتها إلى أحرف أقلّ في Base32 — ولا يحتاج أيّ منها إلى أحرف هروب في URL.

هل يمكن أن يتصادم معرّفان من ULID يوماً؟

عملياً لا أبداً. ضمن ميلّي ثانية واحدة، يملك ULID 80 بت عشوائياً — نحو 1.2 × 10²⁴ احتمالاً — لذا حتى توليد ملايين في الميلّي ثانية يُبقي احتمالات التصادم ضئيلة جداً. والشرط الوحيد أن يملأ العشوائية مولّد أرقام عشوائية آمن تشفيرياً؛ فـ Math.random يُبطل الضمان.

هل يمكنني تخزين معرّفات ULID في PostgreSQL أو MySQL؟

نعم. إنّ ULID بطول 128 بت، فحوّله إلى شكل UUID وخزّنه في عمود uuid (PostgreSQL) أو BINARY(16) (MySQL)، ثم اعرض سلسلة Base32 فقط عند الأطراف. لا يوجد نوع عمود ULID أصيل، لكن تمثيل UUID يكلّف الـ 16 بايتاً نفسها ويُبقي الفهرس مضغوطاً.

هل معرّفات ULID حسّاسة لحالة الأحرف؟

الشكل القانوني بأحرف كبيرة، لكن Crockford Base32 غير حسّاس لحالة الأحرف عند الإدخال: تقرأ أداة فكّ الترميز الأحرف الصغيرة بالطريقة نفسها، وتعيد I/L إلى 1 وO إلى 0. ولتفادي المفاجآت في فحوص المساواة والفهارس، وحّد إلى حالة واحدة قبل التخزين أو المقارنة.

هل سينفد الطابع الزمني بطول 48 بت يوماً؟

ليس لزمن طويل جداً. تبلغ 48 بت من الميلّي ثوانٍ عام 10889 قبل أن يفيض العدّاد، لذا فمكوّن الطابع الزمني محصّن للمستقبل عملياً لأي تطبيق حقيقي. ستستبدل النظام واللغة وقاعدة البيانات قبل أن ينفد المتّسع من التنسيق بزمن طويل.

هل يمكنني توليد معرّفات ULID في المتصفّح أو على الجوّال دون خادم؟

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

الخلاصة

تحلّ معرّفات ULID مشكلة محدّدة وحقيقية — المفاتيح العشوائية التي تجزّئ فهرسك — دون أن تسلب التوليد اللامركزي. وتستحقّ آلياتها أن تبقى في البال:

  • إنّ ULID هو طابع زمني بطول 48 بت بالميلّي ثانية + 80 بت من العشوائية، مُرمَّز كـ 26 حرفاً بترميز Crockford Base32.
  • يُفرز بحسب الزمن لأن الطابع الزمني هو المكوّن الأهمّ والأبجدية تحفظ الترتيب — ترتيب السلسلة يساوي ترتيب الزمن.
  • يمنح هذا الترتيب شجرة B-tree محلّية الإدراج التي يفتقر إليها UUIDv4 العشوائي، فيُبقي عمليات الكتابة سريعة والفهرس مضغوطاً.
  • استخدم الوضع الرتيب حين تحتاج إلى ترتيب صارم للمعرّفات المُولَّدة في الميلّي ثانية نفسها.
  • وازِن تسريب الطابع الزمني قبل كشف معرّفات ULID على معرّفات موجّهة للعموم.
  • اختر UUIDv7 بدلاً منه حين يلزمك البقاء داخل تنسيق UUID القياسي.

حين تكون مستعدّاً لوضعه قيد العمل، افتح مولّد ULID لتوليد معرّفات ULID وفكّ ترميزها وتحويلها بالكامل في متصفّحك — بلا خادم، وبلا رفع، وبلا تخزين أي شيء.

الوسوم: ulid uuid unique-identifier database primary-key

مقالات ذات صلة

عرض جميع المقالات