الطابع الزمني في UUIDv7 ليس كما تظن
يُقدَّم UUIDv7 عادةً بثلاث وعود: معرّفات تتزايد دائمًا، وطابع زمني يخبرك متى أُنشئ الصف، ومعرّفات لا يمكن تخمينها. في مقال بتاريخ 19 أكتوبر 2026، يرى Robert Alexander أن خاصية واحدة فقط مضمونة فعلًا، وهي التفرّد، وأن المعيار نفسه يسمح بليّ الباقي. إن كنت تستخدم HasUuids في Laravel فأنت تستخدم UUIDv7، فمن المفيد أن تعرف على أي هذه الوعود يتكئ كودك.
المعيار يسمح للطابع الزمني بالانحراف
ينص RFC 9562 على أن التطبيقات يجوز لها تعديل الطابع الزمني الفعلي، ولا يضمن مدى قرب قيمة الساعة من الوقت الحقيقي، ويسمح بزيادتها متقدمةً على الوقت الفعلي. والتوثيق في Postgres للدالة uuid_extract_timestamp يقول الشيء نفسه: القيمة المستخرجة ليست بالضرورة لحظة توليد المعرّف.
السبب مفاضلة بين إبقاء المعرّفات مرتبة وإبقاء الوقت دقيقًا. حين ترجع الساعة إلى الوراء، فإن المولّد الذي يرفض العودة بالزمن مضطر إلى الاستمرار في طابع زمني صار الآن في المستقبل.
Python يوضح إلى أي حد قد يصل ذلك
يستخدم مثال Alexander الدالة uuid.uuid7() في Python 3.14. يُرجع الساعة ساعة كاملة بينما يولّد البرنامج معرّفات في حلقة. المتوقع أن يكون الفرق بين الطابع المضمّن والساعة 3,600 ثانية ثم يتقلص. لكن مع أكثر من معرّف واحد في كل جزء من الألف من الثانية يكبر بدلًا من ذلك: طبع تشغيله نحو 3,695، ثم 3,795 و3,894 و3,994 ثانية. ونقاش المشكلة لدى Python يعدّ هذا متسقًا مع المعيار ومع تطبيقات أخرى، ويقول الكاتب إنه يرى السلوك نفسه في غيرها.
ماذا يفعل مولّد Laravel
قرأت الكود الموجود في مجلد vendor/ لهذا الموقع بدل التخمين. ينشئ HasUuids المفاتيح بالدالة Str::uuid7() التي تستدعي ramsey/uuid. والصنف UnixTimeGenerator فيها يأخذ الوقت بالأجزاء من الألف من الثانية، ويحتفظ بآخر وقت استخدمه في خاصية ساكنة. إن كان الوقت الجديد أحدث اختار بتات عشوائية جديدة. وإن لم يكن، سواء في الجزء نفسه من الثانية أو مع ساعة رجعت، أبقى آخر وقت وزاد الجزء العشوائي. وإن فاضت تلك الزيادة، قدّم الوقت المحفوظ جزءًا واحدًا من الألف من الثانية.
ومعنى ذلك عمليًا، من الكود وحده: داخل عملية PHP واحدة لا يرجع الطابع الزمني أبدًا، وبعد رجوع الساعة تحمل المعرّفات الجديدة الوقت الأقدم الذي يبدو أحدث حتى تلحق الساعة. وآخر وقت محفوظ في الذاكرة لا على القرص، فالعملية الجديدة تبدأ من الصفر، وخادمان لا يعرف أحدهما شيئًا عن ساعة الآخر. لا شيء فيه يَعِد بترتيب بين العمليات أو الأجهزة.
تحفّظان أصغر
الطابع الزمني يتسرّب. لا يمكنك مشاركة UUIDv7 دون مشاركة وقت إنشائه بدقة جزء من الألف من الثانية. يعدّ الكاتب هذا أمرًا منخفض الأهمية لمعظم التطبيقات، لكن رابط ملف شخصي يكشف وقت تسجيل الحساب مثال تهمّ فيه المسألة.
والترتيب تقريبي. لا يمكن مزامنة ساعات أجهزة مختلفة بدقة جزء من الألف من الثانية، والتطبيق الذي لا يستخدم عدّادًا قد ينتج معرّفات خارج الترتيب داخل حلقة واحدة. يبقى الترتيب التقريبي مفيدًا لتجاور البيانات في الفهرس، لكنه ليس تسلسلًا.
ما الذي تعتمد عليه في تطبيق Laravel
اعتمد على التفرّد، وعلى أن ترتيب الإدراج التقريبي مفيد للفهرس. لا تحلّل المعرّف لتعرف متى أُنشئ الصف: احتفظ بعمود created_at ورتّب به حين يهمّ الترتيب شخصًا ما. لا تستخدم المعرّف دليلًا على أي حدث وقع أولًا عبر الخوادم. وإن كان وقت الإنشاء خاصًا فلا تضع UUIDv7 في رابط عام. وإن أردت أن ترى بنية معرّف منها، فإن مولّد UUID في هذا الموقع ينشئ معرّفات v7 داخل متصفحك.
الخطوة التالية: ابحث في كودك عن أي موضع يقرأ الوقت من معرّف، أو يرتّب بالمعرّف حيث يتوقع شخصٌ ترتيبًا زمنيًا، وانقله إلى created_at. المصدر: مقال Robert Alexander عن خصائص UUIDv7.
ملاحظات القراء