مهندسی داده
792 subscribers
112 photos
7 videos
24 files
314 links
BigData.ir کانال رسمی وب سایت
مطالبی راجع به مهندسی داده و طراحی زیرساخت‌های پردازش دیتا و ابزارهای مدرن دیتا
ارتباط با ادمین: @smbanaei
گروه تخصصی مهندسی داده 👇
https://t.iss.one/bigdata_ir_discussions2
کانال یوتیوب 👇
https://www.youtube.com/@irbigdata
Download Telegram
چرا UUID7 و ULID گزینه‌های بهتری برای کلیدهای اصلی در پایگاه داده هستند؟
در طراحی پایگاه‌های داده، انتخاب نوع شناسه (ID) یکی از تصمیم‌های کلیدی است که می‌تواند تأثیر زیادی بر عملکرد، مقیاس‌پذیری و امنیت سیستم داشته باشد.
در سناریوهایی مثل سیستم‌های توزیع‌شده، APIهای پرترافیک یا صفحات محصول در وب‌سایت‌ها که نیاز به درج سریع داده و جلوگیری از افشای الگوی رکوردها وجود دارد، استفاده از کلیدهای auto-increment معمولاً گزینه مناسبی نیست. چون:
⛔️باعث قفل شدن جدول در شرایط همزمانی بالا می‌شود،
⛔️امکان حدس زدن تعداد یا ترتیب رکوردها را فراهم می‌کند.

💡 راه‌حل سنتی چیست؟
استفاده از UUID (نسخه ۴) به‌عنوان کلید اصلی مزایای خوبی دارد: یکتایی جهانی بدون نیاز به هماهنگی بین سرورها، مناسب برای محیط‌های توزیع‌شده، و جلوگیری از افشای الگوهای داده. اما یک مشکل جدی دارد.
🔍 چرا UUID تصادفی (مثلاً UUIDv4) در دیتابیس‌ها عملکرد خوبی ندارد؟
اکثر پایگاه‌های داده رابطه‌ای مانند PostgreSQL، MySQL و SQL Server برای ایندکس‌گذاری — مخصوصاً روی کلید اصلی — از ساختاری به‌نام B-Tree (Balanced Tree) استفاده می‌کنند.
این ساختار کمک می‌کند:
✳️جستجوی کلیدها با پیچیدگی O(log n) انجام شود (سریع و مقیاس‌پذیر)،
✳️داده‌ها به‌صورت مرتب نگه داشته شوند،
✳️ و درج، حذف یا به‌روزرسانی به‌شکل کارآمد مدیریت شود.
اما مشکل از جایی شروع می‌شود که کلیدهایی با ترتیب تصادفی (مثل UUIDv4) در جدول وارد می‌شوند.

📉 چه اتفاقی می‌افتد؟
وقتی داده‌های زیادی با کلید تصادفی وارد جدول می‌شوند:
⛔️ دیتابیس نمی‌تواند آن‌ها را در انتهای ساختار درختی اضافه کند (مثل auto-increment IDs)،
⛔️ باید آن‌ها را بین صفحات مختلف B-Tree پراکنده کند،
⛔️ این پراکندگی باعث عملیات مکرر Page Split (شکستن صفحات)، جابه‌جایی نودها و بازچینش ساختار درختی می‌شود.


🧨 نتیجه؟
🧱کند شدن محسوس عملیات درج (INSERT)،
🧱 مصرف بالای I/O و حافظه،
🧱 کاهش عملکرد کلی سیستم در سناریوهای پرترافیک.

راه‌حل‌های مدرن: UUID7 و ULID
برای رفع این مشکلات، دو استاندارد جدید معرفی شده‌اند:
🔹 استاندارد ULID (Lexicographically sortable): ترکیبی از timestamp و داده تصادفی
🔹 استاندارد UUIDv7: نسخه‌ای از UUID با ترتیب زمانی، سازگار با استاندارد UUID

مزیت اصلی این دو چیست؟

🔸 با حفظ یکتایی و امنیت، کلیدها به‌صورت ترتیبی در ایندکس درج می‌شوند.
🔸 این یعنی:
کاهش شدید Page Split و پراکندگی
بهبود درج‌های پرترافیک
جست‌وجوی سریع‌تر بر اساس بازه‌های زمانی

📊 چه زمانی از هرکدام استفاده کنیم؟
اگر خوانایی و طول کوتاه‌تر مهم است → ULID
اگر سازگاری با UUID استاندارد اهمیت دارد → UUIDv7

📐 قالب ULID
قالب ULID یک رشته ۲۶ نویسه‌ای است که با Crockford’s Base32 کدگذاری می‌شود (حروف I, L, O, U حذف شده‌اند تا اشتباه نشوند).
→ طول: ۲۶ نویسه - کاراکترهای ابتدایی مهرزمان هستند.
→ مثال: 01AN4Z07BY79KA1307SR9X4MV3

📐 قالب UUIDv7
→ نمایش به‌صورت استاندارد UUID در مبنای ۱۶ (hex) با خط تیره
→ طول شامل خط تیره: ۳۶ نویسه - کاراکترهای ابتدایی مهرزمان هستند.
→ قالب: 8-4-4-4-12
→ مثال: 017f45e0-7e1a-7a3f-8bbc-4dbf7e6d9c3a
→ طول بدون خط تیره: ۳۲ نویسه hex

بنابراین UUID7 طول بیشتری نسبت به ULID دارد اما چون با استاندارد UUID سازگاراست، برای سیستم‌های موجود گزینه بهتری است.

#Database #Backend #DistributedSystems #UUID #ULID #PostgreSQL #SystemDesign #Performance #مهندسی_داده
👍81
الگوی Outbox و داستان یک راهکار هوشمندانه در پستگرس

اخیراً مقاله‌ای از صادق دوستی در Dev.to خواندم که نشان داد با تجربه و تسلط، می‌توان برای چالش‌های بزرگ، راه‌حل‌هایی هوشمندانه و ساده پیدا کرد. یعنی در دنیای فنی، گاهی غرق پیچیدگی‌ها می‌شویم و راه‌حل‌های ساده اما عمیق را نادیده می‌گیریم. این پست ادای دینی است به صادق عزیز Sadeq Dousti و مقالات ارزشمندش، و مروری بر مشکل پیاده‌سازی الگوی Outbox با PostgreSQL در حجم بالای داده و راه‌حلی خلاقانه برای آن.


https://dev.to/msdousti/postgresql-outbox-pattern-revamped-part-1-3lai/



🎯 الگوی Outbox چیست؟

در یک فروشگاه آنلاین، ثبت سفارش باید چند کار را انجام دهد:

ذخیره در پایگاه داده

ارسال ایمیل تأیید

به‌روزرسانی موجودی

اطلاع به واحد ارسال

این اکشن‌ها به بروکرهایی مثل Kafka ارسال می‌شوند تا هر واحد کار خود را انجام دهد.

اگر ارسال پیام به بروکر با خطا مواجه شود؟

Outbox وارد می‌شود! سفارش در پایگاه داده ذخیره شده و یک پیام در جدول Outbox ثبت می‌شود. یک سرویس جداگانه پیام‌ها را خوانده و به بروکر می‌فرستد. در صورت خطا، پیام در جدول باقی می‌ماند تا دوباره برای پردازش ارسال شود اما ...



🔍 چالش: حجم بالای داده‌ها

با افزایش پیام‌ها در Outbox:

⚠️کوئری‌های خواندن پیام‌های منتشرنشده کند می‌شوند.

⚠️ایندکس‌ها به دلیل آپدیت‌های مکرر غیربهینه می‌شوند.

⚠️مصرف منابع سیستم افزایش می‌یابد.



💡 راه‌حل: پارتیشن‌بندی هوشمند

صادق دوستی پیشنهاد می‌کند جدول Outbox را به دو پارتیشن تقسیم کنیم:

outbox_unpublished: پیام‌های منتشرنشده (published_at IS NULL)

outbox_published: پیام‌های منتشرشده (published_at NOT NULL)

با این کار، پیام‌های جدید به outbox_unpublished می‌روند و پس از انتشار، به‌صورت خودکار به outbox_published منتقل می‌شوند. بنابراین کوئری‌ها فقط روی پارتیشن سبک‌تر اجرا می‌شوند.



🎉 مزایا:


سرعت بالا: کوئری‌ها روی پارتیشن کوچک‌تر اجرا می‌شوند.

مدیریت آسان: حذف پیام‌های قدیمی با TRUNCATE سریع است.

بهینه‌سازی منابع: ایندکس‌ها کوچک و کارآمد می‌مانند.



🏁 جمع‌بندی


الگوی Outbox برای هماهنگی سیستم‌های توزیع‌شده عالی است، اما پیاده‌سازی نادرست آن مشکل‌ساز می‌شود. پارتیشن‌بندی هوشمند صادق دوستی این الگو را بهینه‌تر و سریع‌تر می‌کند.

🔗 برای جزئیات بیشتر، حتا مقاله صادق در Dev.to را بخوانید!

#outbox #postgres #performance #database #dataengineering

#مهندسی_داده
👍1