بلاگز / UUID Primary Key کے بہترین طریقے

UUID Primary Key کے بہترین طریقے

شائع ہوا
3 اگست، 2026
مصنف
Faizan Nadeem
ٹیگز
Python Database Design Backend Development UUID
منفرد database keys کی نمائندگی کرنے والی hexadecimal شناختی strings
Unsplash پر Artturi Jalli کی تصویر

زیادہ تر backend developers سے پوچھیں کہ UUID کیا ہوتا ہے تو آپ کو تقریباً ایک ہی جواب ملے گا: “یہ ایک random string ہے جو بنیادی طور پر unique ہوتی ہے، اس لیے مجھے اس بارے میں سوچنے کی ضرورت نہیں۔” یہی عام غلطی ہے — UUID کو ایک ہی، باہم قابلِ تبادلہ چیز سمجھنا، بجائے اس کے کہ اسے مختلف generation strategies کے ایک خاندان کے طور پر دیکھا جائے جن کے tradeoffs واقعی مختلف ہوتے ہیں۔ UUID ایک نہیں ہوتا۔ ایک random ہوتا ہے، ایک timestamp-based، دو deterministic hash-based، اور — RFC 9562 spec کے final ہونے کے بعد — نئے time-sortable versions بھی ہیں جنہیں زیادہ تر teams اب بھی default کے طور پر استعمال نہیں کر رہیں، حالانکہ دلیل کے لحاظ سے انہیں کرنا چاہیے۔

یہ خلا جتنا نظر آتا ہے، اس سے زیادہ اہم ہے۔ اگر آپ primary key کے لیے غلط version منتخب کر لیں تو آپ کو کوئی error نہیں ملے گا — آپ کو ایک ایسا database ملے گا جو بڑھنے کے ساتھ خاموشی سے write کرنے میں سست ہوتا جائے گا، کیونکہ کسی نے یہ نہیں سوچا کہ 128-bit random number، B-tree indexes کے اصل کام کرنے کے طریقے کے ساتھ کیسے تعامل کرتا ہے۔ یہ post بتاتی ہے کہ UUID میں حقیقتاً کیا encode ہوتا ہے، ہر version اپنے bits کیسے بناتا ہے، دو UUIDs کے collide ہونے کے امکان کے پیچھے اصل math کیا ہے، اور کیوں “بس uuid4() استعمال کر لو” بالکل وہی قسم کی مختصر سوچ ہے جو ایک سال بعد production میں دردِ سر بنتی ہے۔

آپ یہ سیکھیں گے:

  • ہر UUID کے 128 bits میں حقیقتاً کیا encode ہوتا ہے — ان version اور variant nibbles سمیت جنہیں آپ ایک نظر میں پڑھ سکتے ہیں
  • UUID v1، v4، v3/v5، اور نئے time-sortable v6/v7/v8 کے درمیان اصل فرق
  • UUID collision probability کے پیچھے اصل math، اور کیوں حقیقی دنیا میں duplicate UUIDs تقریباً کبھی بھی اس math کی وجہ سے نہیں بنتے
  • کیوں random UUIDs (v4) جب primary keys کے طور پر استعمال ہوں تو خاموشی سے B-tree index performance کو نقصان پہنچاتے ہیں
  • کیوں UUIDv7 primary keys کے لیے default choice بنتا جا رہا ہے، اور Python میں اسے کیسے generate کیا جائے
  • موجودہ UUID-keyed schema کو بغیر کسی خطرناک big-bang rewrite کے کیسے migrate کیا جائے

فہرستِ مضامین

  1. بنیادی باتیں
  2. مکمل ساخت
  3. بنیادی تہوں کی وضاحت
  4. شروع سے آخر تک جائزہ
  5. خاص صورتیں
  6. Scaling اور Production Challenges
  7. Code Examples
  8. عام غلطیاں
  9. Production Best Practices

بنیادی باتیں

UUID دراصل کیا ہوتا ہے

UUID (Universally Unique Identifier) ایک 128-bit value ہوتی ہے، جسے عموماً 32 hex characters کی صورت میں لکھا جاتا ہے، اور انہیں 8-4-4-4-12 pattern میں پانچ groups میں تقسیم کیا جاتا ہے:

550e8400-e29b-41d4-a716-446655440000

ان hex digits میں سے دو random یا timestamp data نہیں ہوتے — وہ metadata ہوتے ہیں جو خود UUID کی وضاحت کرتے ہیں۔ version nibble یہ بتاتی ہے کہ اسے کیسے generate کیا گیا (timestamp-based، random، hash-based، یا نئے time-ordered schemes)، اور variant field یہ بتاتی ہے کہ کون سا layout standard استعمال ہو رہا ہے — آپ جو کچھ بھی دیکھیں گے، اس میں تقریباً سب RFC 9562 کے معیار پر چلتے ہیں، جو 2024 کی update ہے جس نے اصل RFC 4122 کے اوپر نئے versions کو باقاعدہ شامل کیا۔ ڈیزائن کی خوبصورت بات یہی ہے: آپ کسی بھی UUID کو دیکھ کر صرف چند characters سے اس کی “recipe” جان سکتے ہیں، بغیر کسی lookup table کے۔

درست Version منتخب کرنا کیوں بہت اہم فیصلہ ہے

  • UUIDs ہر جگہ نظر آتے ہیں — primary keys، session tokens، request IDs، S3 object keys، idempotency keys — اس لیے ایک use case کے بارے میں غلط مفروضہ عموماً copy-paste ہو کر باقی سب جگہ بھی پہنچ جاتا ہے۔
  • primary key کے طور پر غلط version کی حقیقی، قابلِ پیمائش performance cost ہوتی ہے۔ B-tree index میں insert کیے گئے random UUIDs صرف “تھوڑا آہستہ” کام نہیں کرتے — بڑے scale پر یہ insert latency اور index size کو معنی خیز حد تک بڑھا سکتے ہیں، اور اس کی وجہ collision risk نہیں ہوتی۔
  • ہر use case randomness نہیں چاہتا۔ کچھ کو reproducibility چاہیے ہوتی ہے (یعنی وہی input ہمیشہ وہی ID دے)، اور وہاں غلط tool استعمال کرنے سے duplicates رکنے کے بجائے بننے لگتے ہیں۔

مکمل ساخت

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
   │        │    │   │        │
 time/random   version  variant   time/random/node
              (how built)  (layout std)

بنیادی اصول یہ ہے: version nibble خود UUID کے اندر موجود instruction label ہے، جو بتاتی ہے کہ اس کے باقی تمام bits کی تشریح کیسے کی جانی چاہیے۔ UUID کی uniqueness یا sortability میں کچھ بھی ایسی چیز نہیں جو صرف “UUID ہونے” کی وجہ سے ہو — یہ مکمل طور پر اس version-specific recipe کا نتیجہ ہے جس نے اسے generate کیا۔

بنیادی تہوں کی وضاحت

1. UUID1 — Timestamp + Node

یہ کیا ہے: یہ موجودہ timestamp کو ایک node identifier (تاریخی طور پر MAC address) اور clock sequence کے ساتھ ملاتا ہے تاکہ clock rollback کے خلاف تحفظ رہے۔

یہ کیوں اہم ہے: یہاں uniqueness probability سے نہیں بلکہ structure سے آتی ہے — اگر دو machines ایک ہی لمحے میں UUID1 generate کریں تب بھی انہیں مختلف values ملتی ہیں کیونکہ node identifier مختلف ہوتا ہے۔

Production tip: UUID1 میں ایک حقیقی timestamp اور ممکنہ طور پر ایک حقیقی hardware identifier شامل ہوتا ہے۔ اگر آپ یہ IDs externally expose کر رہے ہیں تو اسے ہلکی privacy اور security leak سمجھیں، اور user-facing چیزوں کے لیے اس سے گریز کریں۔

2. UUID4 — تقریباً مکمل طور پر Random

یہ کیا ہے: 122 bits خالص randomness کے ہوتے ہیں (باقی 6 version اور variant کے لیے fixed ہوتے ہیں) — نہ timestamp، نہ machine identifier، نہ کوئی ایسی چیز جسے reverse-engineer کیا جا سکے۔

import uuid
uuid.uuid4()
# UUID('a3b8f9d2-1c4e-4b7a-9f2d-6e8c1a0b3d5f')

یہ کیوں اہم ہے: یہی وجہ ہے کہ UUID4 API tokens اور idempotency keys کے لیے default ہوتا ہے — یہ اس بارے میں کچھ ظاہر نہیں کرتا کہ یہ کب یا کہاں بنایا گیا۔

Production tip: UUID4 tokens کے لیے ایک بہترین انتخاب ہے۔ database primary key کے طور پر یہ اتنا مضبوط انتخاب نہیں جتنا زیادہ تر لوگ سمجھتے ہیں — اس کی بالکل وجہ ہم نیچے primary-key section میں دیکھیں گے۔

3. UUID3 اور UUID5 — Deterministic, Hash-Based

یہ کیا ہے: یہ بالکل random نہیں ہوتے۔ ایک namespace اور ایک name دیں، انہیں hash کریں (v3 کے لیے MD5، v5 کے لیے SHA-1)، اور وہی namespace-plus-name ہمیشہ وہی UUID پیدا کرے گا۔

uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")
# deterministic — identical input always yields identical output

یہ کیوں اہم ہے: جب آپ کو ایک stable، reproducible ID چاہیے ہو تو یہ واقعی مفید ہے — مثال کے طور پر URL یا کسی external system کے record ID سے اخذ کردہ ایک consistent identifier — بغیر اس کے کہ آپ کو lookup table رکھنی پڑے تاکہ چیک کر سکیں کہ یہ input پہلے دیکھا جا چکا ہے یا نہیں۔

Production tip: نئے code کے لیے UUID5 کو UUID3 پر ترجیح دیں۔ SHA-1 (v5)، MD5 (v3) سے زیادہ مضبوط hash ہے، اور پرانے، کمزور option کو منتخب کرنے کی شاذ ہی کوئی وجہ ہوتی ہے، جب تک آپ کسی موجودہ system کے output سے match نہ کر رہے ہوں۔

4. UUID6، UUID7، اور UUID8 — Time-Sortable UUIDs

یہ کیا ہے: یہ نئے versions ہیں جنہیں RFC 9562 میں باقاعدہ شکل دی گئی۔ خاص طور پر UUID7 ایک Unix timestamp کو اس کے بعد آنے والے random bits کے ساتھ ملاتا ہے، جس سے ایسی IDs بنتی ہیں جو unique بھی ہوتی ہیں اور creation time کے لحاظ سے قدرتی طور پر sort بھی ہوتی ہیں۔ UUID6 دراصل UUID1 کی reorder کی گئی variant ہے، اسی database-friendly sorting کے لیے؛ UUID8 custom schemes کے لیے user-defined layout ہے۔

# Python 3.13+
uuid.uuid7()
# UUID('01928a47-3b30-7c5e-9d1a-f0b8c4a7e923')

Python کے پرانے versions میں، uuid-utils package (جو Rust-backed ہے اور standard library type کے لیے drop-in ہے) uuid7() support بھی شامل کرتا ہے، اور uuid4() کے لیے بھی نمایاں speed boost دیتا ہے۔

یہ کیوں اہم ہے: Time-ordered IDs، B-tree index میں بکھرنے کے بجائے cluster ہوتی ہیں، اور یہی واحد سب سے بڑی عملی وجہ ہے کہ UUIDv7، v4 کو 2026 کے default کے طور پر replace کر رہا ہے ہر اس چیز کے لیے جو primary key بنے۔ PostgreSQL 18 native uuidv7() generation کے ساتھ آتا ہے، اور MySQL 8.4 نے helper support شامل کر دی ہے — ecosystem اب spec کے مطابق ہو چکا ہے۔

Production tip: اگر کوئی UUID کبھی primary key یا clustered index بننے والا ہو، تو default کے طور پر v7 استعمال کریں جب تک اس کے خلاف کوئی خاص وجہ نہ ہو۔ اگر یہ محض ایک external token ہے جو کبھی index کو touch نہیں کرتا، تو v4 اب بھی بالکل مناسب ہے۔

5. UUID بطور Primary Key: Random UUIDs B-Tree Performance کو کیوں نقصان پہنچاتے ہیں

یہ کیا ہے: primary key کے طور پر UUID4 استعمال کرنے کی performance cost collisions کے بارے میں نہیں ہوتی — یہ اس بارے میں ہوتی ہے کہ relational databases primary keys کو جسمانی طور پر کیسے store کرتے ہیں۔ PostgreSQL، MySQL، اور SQLite سب primary key indexes کے لیے B-tree structure استعمال کرتے ہیں، اور B-trees ان values کے لیے optimize ہوتے ہیں جو تقریباً sorted order میں آئیں: نئی rows دائیں جانب کی آخری page میں append ہوتی ہیں، جو memory میں “hot” رہتی ہے اور writes کو تیز اور مقامی رکھتی ہے۔

یہ کیوں اہم ہے: ایک random UUID4 ہر insert پر اس index کی کسی random page میں جا گرتا ہے۔ بڑے scale پر اس کا مطلب ہے page splits، index fragmentation، اور cache thrashing — “hot” pages کا working set، جسے database کو memory میں رکھنا پڑتا ہے، صرف tail تک محدود رہنے کے بجائے پورے index تک پھیل جاتا ہے، اور inserts قابلِ پیمائش حد تک سست ہو جاتے ہیں جبکہ index بھی واضح طور پر بڑا ہو جاتا ہے، اس sequential-key table کے مقابلے میں جو اسی schema پر ہو۔ تقریباً ایک کروڑ rows والی tables پر public benchmarks نے دکھایا ہے کہ UUID4 inserts، auto-increment integer keys کے مقابلے میں تقریباً تین گنا سست چلتے ہیں، اور بننے والا index تقریباً 40% بڑا ہوتا ہے — اور جیسے جیسے table بڑھتی رہتی ہے، یہ فرق مزید بڑھتا ہے کیونکہ fragmentation مستقل رہنے کے بجائے جمع ہوتی رہتی ہے۔

خاص طور پر MySQL میں، یہ cost سننے سے بھی زیادہ سخت ہوتی ہے، کیونکہ InnoDB کی primary key ہی clustered index ہوتی ہے — table کے ہر دوسرے index میں primary key value کی ایک copy store ہوتی ہے، اس لیے ایک پھولا ہوا، fragmented primary key index صرف primary key lookups کو سست نہیں کرتا، بلکہ اس کے اوپر بننے والے ہر secondary index کو بھی بڑا کر دیتا ہے۔

Production tip: یہی وہ خلا ہے جسے UUID7 بند کرتا ہے — کیونکہ اس میں timestamp prefix ہوتا ہے، indexing کے لحاظ سے یہ sequential key جیسا برتاؤ کرتا ہے، جبکہ services کے درمیان zero coordination کے ساتھ generate بھی ہو جاتا ہے۔ موجودہ table کو تبدیل کرنا schema migration ہے، config flag نہیں، اس لیے اسے ایک باقاعدہ project کے طور پر budget کریں، نہ کہ one-line fix کے طور پر۔

6. جاننے کے قابل Alternatives: TSID اور ULID

یہ کیا ہے: یہ time-sortable ID formats ہیں جو UUIDs بالکل نہیں ہیں — TSID عموماً ایک compact 64-bit value ہوتا ہے، اور ULID ایک 128-bit، UUID-compatible format ہے جس کا timestamp-plus-randomness design UUID7 سے ملتا جلتا ہے۔

یہ کیوں اہم ہے: اگر آپ سب سے کم ممکنہ index footprint چاہتے ہیں اور UUID کے مخصوص 128-bit format کی ضرورت نہیں، تو 2026 کے دور کے ایک alternative کے طور پر TSID کا جائزہ لینا چاہیے۔ اگر آپ UUID-compatible رہنا چاہتے ہیں اور ساتھ ہی index locality بھی حاصل کرنا چاہتے ہیں، تو UUID7 یا ULID دونوں اس ضرورت کو پورا کرتے ہیں۔

شروع سے آخر تک جائزہ

ایک نئے user signup کو ID generation، storage، اور insert کے وقت واقعی کیا ہوتا ہے، اس زاویے سے دیکھیں:

  1. Request موصول ہوئی۔ ایک نیا user signup کرتا ہے؛ application کو نئی row کے لیے insert سے پہلے یا اسی دوران ایک primary key generate کرنی ہوتی ہے۔
  2. ID generate ہوئی۔ UUID4 strategy کے ساتھ، uuid.uuid4() ایک مکمل random 128-bit value بناتا ہے۔ UUID7 strategy کے ساتھ، uuid.uuid7() ایک ایسی value بناتا ہے جس کے شروع میں timestamp component ہوتا ہے۔
  3. Row insert ہوئی۔ database کا primary key کے لیے B-tree index نئی value وصول کرتا ہے۔ UUID4 tree کی کسی تقریباً random page میں جاتا ہے؛ UUID7 دائیں جانب کی آخری، پہلے سے hot page میں جاتا ہے، انہی دوسری recently-inserted rows کے ساتھ۔
  4. Index maintenance۔ UUID4 کے تحت، اگر random landing page بھر چکی ہو تو یہ insert page split trigger کر سکتی ہے۔ UUID7 کے تحت، append-mostly pattern یہ صورت کہیں کم پیدا کرتا ہے۔
  5. Read path۔ primary key کے ذریعے lookup دونوں صورتوں میں یکساں کام کرتی ہے — یہ پورا فرق صرف write path اور مجموعی index size میں ظاہر ہوتا ہے، single-row read performance میں نہیں۔
  6. بڑے scale پر۔ اسے لاکھوں rows پر ضرب دیں، تو UUID4 table کا index، UUID7 table کے index کے مقابلے میں بڑا اور زیادہ fragmented ہو چکا ہوگا، صرف insertion pattern کی وجہ سے — schema میں اور کچھ بھی نہیں بدلا۔

خاص صورتیں

Idempotent، reproducible resource IDs۔ جب آپ کو یہ چاہیے ہو کہ وہی external input ہمیشہ اسی internal ID سے map ہو — مثلاً کسی external system سے کھینچے گئے records کو deduplicate کرنا — تو UUID5 صحیح tool ہے، خاص طور پر اس لیے کہ یہ random نہیں ہوتا۔ اسی input کو دوبارہ process کرنے سے کبھی duplicate record نہیں بنتا۔

External-facing IDs بمقابلہ internal foreign keys۔ ایک عام hybrid pattern یہ ہے: foreign key relationships اور index-heavy joins کے لیے ایک internal، تیز، sequential key (integer یا TSID) استعمال کریں، اور external-facing identifier کے طور پر الگ UUID column expose کریں۔ اس سے sequential IDs leak ہونے سے بھی بچاؤ ہوتا ہے (IDOR risk — یہ اندازہ لگا لینا کہ /orders/1002 موجود ہے کیونکہ /orders/1001 موجود ہے) اور اندرونی طور پر ہر جگہ random UUIDs کی مکمل B-tree cost بھی ادا نہیں کرنی پڑتی۔

Offline-first اور multi-writer systems۔ UUID کے وجود میں آنے کی اصل وجہ یہی تھی: کوئی بھی node، service، یا offline client zero coordination کے ساتھ globally valid ID generate کر سکتا ہے، بغیر کسی central sequence کے round-trip کے۔ v7 کے ساتھ یہ خاصیت ختم نہیں ہوتی — آپ کو coordination-free generation بھی ملتی ہے اور بہتر index behavior بھی، ایک ہی وقت میں۔

Scaling اور Production Challenges

Tables کے بڑھنے کے ساتھ index bloat جمع ہوتی جاتی ہے۔ random-UUID-keyed table اور sequential یا time-ordered table کے درمیان فرق table size کے ساتھ بڑھتا ہے، صرف row count کے ساتھ نہیں — fragmentation وقت کے ساتھ بہتر نہیں، بلکہ بدتر ہوتی جاتی ہے، جتنا عرصہ table random-order inserts لیتی رہتی ہے۔

Downtime کے بغیر موجودہ UUID4 schema کو migrate کرنا۔ ایک نیا UUID7 column شامل کریں، موجودہ rows کے لیے اسے backfill کریں، transition window کے دوران دونوں columns میں dual-write کریں، پھر جب backfill مکمل طور پر verify ہو جائے تو reads اور writes کو نئے column پر cut over کریں — live primary-key format change ایسی چیز نہیں جسے ایک ہی migration step میں آزمایا جائے۔

Coordination کے بغیر cross-service ID generation۔ distributed system میں جہاں کئی services آزادانہ طور پر write کر رہی ہوں، UUID کا کوئی بھی version اب بھی “no central authority” والا مسئلہ حل کرتا ہے جس نے اصل میں UUIDs کو جنم دیا تھا — version کا انتخاب صرف index performance اور sortability بدلتا ہے، coordination-free generation کی guarantee نہیں۔

حقیقی duplicate UUIDs اصل میں کہاں سے آتے ہیں۔ نظریاتی collision math (نیچے) تقریباً کبھی بھی کسی حقیقی production duplicate کی وجہ نہیں ہوتی۔ اصل incidents کی جڑ کمزور یا قابلِ پیش گوئی random number generators، ایسے processes ہوتے ہیں جو fork ہو کر غیر ارادی طور پر ایک ہی seed share کرتے ہیں، ٹوٹی ہوئی concurrency جہاں shared state workers کے درمیان غلط طور پر reuse ہو جاتی ہے، یا سادہ implementation bugs — نہ کہ یہ کہ 128-bit space چھوٹی پڑ گئی ہو۔

Code Examples

import uuid

uuid.uuid4()      # random — 122 bits of entropy
uuid.uuid1()      # timestamp + node
uuid.uuid7()      # Python 3.13+: timestamp-prefixed, sortable
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")  # deterministic, SHA-1

آپ کے Python stdlib میں جو versions ابھی شامل نہیں، یا uuid4() پر بھی meaningful speed boost کے لیے:

# pip install uuid-utils
import uuid_utils as uuid

uuid.uuid7()  # drop-in compatible with stdlib UUID objects

v7-as-primary-key pattern کو ظاہر کرنے والی ایک کم سے کم PostgreSQL schema:

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT uuidv7(),
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now()
);

عام غلطیاں

غلطی: “UUID” کو ایک ہی قابلِ تبادلہ چیز سمجھنا۔ use case کے مطابق کون سا version مناسب ہے، یہ سوچے بغیر جو بھی uuid() helper ہاتھ کے قریب ہو اسی کو استعمال کر لینا۔ حل: کچھ بھی generate کرنے سے پہلے جان لیں کہ آپ کو randomness (v4)، reproducibility (v5)، یا sortability (v7) میں سے کیا چاہیے۔

غلطی: ہر primary key کے لیے default کے طور پر UUID4 استعمال کرنا۔ یہی “table کے بڑھنے کے ساتھ ہماری writes سست کیوں ہو گئیں” جیسے incidents کی سب سے عام وجہ ہے۔ حل: ہر اس چیز کے لیے جو clustered یا primary-key index بنے، UUID7 (یا hybrid internal/external key design) استعمال کریں۔

غلطی: birthday-math collision odds کی فکر کرنا، اصل وجوہات کی نہیں۔ UUID4 کی collision probability حیرت انگیز طور پر کم ہے — حتیٰ کہ ایک collision کے 50% chance تک پہنچنے کے لیے بھی تقریباً 2.7 quintillion values generate کرنا ہوں گی۔ حل: اگر production میں duplicate دکھائی دے، تو اپنے random number generator اور process/concurrency model کا audit کریں — اصل duplicates یہی سے آتے ہیں، math سے نہیں۔

غلطی: نئے code کے لیے UUID3 استعمال کرنا۔ MD5، SHA-1 کے مقابلے میں کمزور hash ہے اور نئے systems کے لیے اس کا کوئی فائدہ نہیں۔ حل: جب تک آپ خاص طور پر کسی موجودہ UUID3-based system کو match نہ کر رہے ہوں، default کے طور پر UUID5 استعمال کریں۔

غلطی: ہر جگہ UUIDs کو 36-character text کے طور پر store کرنا۔ یہ storage اور index space ضائع کرتا ہے، ان native binary representations کے مقابلے میں جنہیں زیادہ تر databases support کرتے ہیں۔ حل: جہاں ممکن ہو، plain string column کے بجائے اپنے database کا native UUID type استعمال کریں (جو 16 bytes میں store ہوتا ہے)۔

Production Best Practices

  • version کو عادت کے بجائے use case سے match کریں۔ tokens کے لیے random، reproducible IDs کے لیے deterministic، اور ہر اس چیز کے لیے time-ordered جو index بننے والی ہو۔
  • نئی primary keys کے لیے default UUID4 نہیں بلکہ UUID7 رکھیں۔ index-locality کا فائدہ تقریباً مفت ہوتا ہے اور tables کے بڑھنے کے ساتھ آپ کے حق میں جمع ہوتا جاتا ہے۔
  • جہاں اہم ہو وہاں internal keys اور external identifiers کو الگ رکھیں۔ ایک تیز internal key اور UUID-based external identifier مل کر sequential IDs کے IDOR risk سے بھی بچاتے ہیں اور ہر جگہ random UUIDs کی مکمل indexing cost سے بھی۔
  • UUIDs کو ان کی native binary type میں store کریں۔ کسی بھی حقیقی scale پر سولہ bytes، چھتیس characters سے بہتر ہیں۔
  • اگر duplicate نظر آئے تو math نہیں، generator دیکھیں۔ حقیقی دنیا کی collisions تقریباً ہر بار کمزور randomness یا خراب concurrency کی وجہ سے ہوتی ہیں — اسے اس implementation bug کے طور پر دیکھیں جسے ڈھونڈ کر ٹھیک کرنا ہے، نہ کہ اس ثبوت کے طور پر کہ UUIDs “واقعی unique نہیں ہوتے”۔

خلاصہ

UUID کوئی ایک ایسی چیز نہیں جس کے بارے میں آپ عمومی انداز میں reasoning کر سکیں — یہ مختلف bit-generation strategies کا ایک خاندان ہے، اور ہر ایک کا ایک مخصوص کام ہے، جبکہ primary key کے لیے غلط strategy منتخب کرنا بالکل وہی قسم کا فیصلہ ہے جو ابتدا میں مفت لگتا ہے، یہاں تک کہ آپ کی table میں ایک کروڑ rows نہ ہو جائیں۔ collisions کے گرد موجود math ایک حل شدہ اور نہ ہونے کے برابر مسئلہ ہے؛ اصل اہم فیصلہ uniqueness نہیں بلکہ version ہے۔ tokens کے لیے default v4 رکھیں، reproducible IDs کے لیے v5، اور ہر اس چیز کے لیے v7 جو primary key بنے، اور “ہمارا database پہلے سے سست کیوں ہو گیا ہے” جیسے زیادہ تر سوالات شروع ہی نہیں ہوں گے۔

کیا آپ اب بھی primary keys کے لیے uuid4() کو default رکھے ہوئے ہیں، یا آپ پہلے ہی کسی time-ordered چیز پر منتقل ہو چکے ہیں؟

مزید مضامین