ویرگول
ورودثبت نام
Setare Behzadi
Setare Behzadiمهندسی نرم افزار و توسعه دهنده وب | نکاتی در مورد وب که فکر میکنم میتونه واسه خیلی ها مناسب باشد رو منتشر میکنم.
Setare Behzadi
Setare Behzadi
خواندن ۷ دقیقه·۱ ماه پیش

Designing Data-Intensive Applicationsخلاصه کتاب

فصل ۲- Data Models and Query Language- قسمت۱

Relational Model vs Document Model

1️⃣ Relational Model (مدل رابطه‌ای)

  • ساختار: داده‌ها در جدول‌ها (tables) با ردیف (row) و ستون (column) ذخیره می‌شوند.

  • Schema: حتماً schema ثابت دارد؛ یعنی قبل از ذخیره‌سازی، باید ساختار جدول‌ها مشخص باشد.

  • Query: با SQL می‌گیریم: SELECT * FROM users WHERE age > 30

  • ACID: تراکنش‌ها قوی هستند؛ یک رکورد یا چند رکورد با اطمینان کامل update/delete می‌شوند.

مثال عملی:

  • بانک، سیستم حسابداری، ERP

  • هر جایی که داده‌ها مرتب، دقیق، و تراکنش محور هستند

نکته:

وقتی consistency مهم است و روابط بین موجودیت‌ها زیاد است، relational بهترین گزینه است.


2️⃣ Document Model (مدل سندی)

  • ساختار: داده‌ها به صورت اسناد (documents) ذخیره می‌شوند، معمولاً JSON یا BSON.

  • Schema: schema می‌تواند dynamic باشد؛ هر سند می‌تواند فیلدهای متفاوت داشته باشد.

  • Query: با query مخصوص DB:

db.users.find({ age: { $gt: 30 } })
  • ACID: معمولاً تراکنش‌ها محدود به یک سند هستند (MongoDB recent versions چند سند را هم پشتیبانی می‌کند)

مثال عملی:

  • اپلیکیشن وب با داده‌های user-generated مثل پروفایل، پست، کامنت

  • سیستم‌هایی که تغییرات schema زیاد است و انعطاف می‌خواهند

نکته :

وقتی سرعت read/write مهم است، یا schema مدام تغییر می‌کند، document model راحت‌تر و سریع‌تر است.


3️⃣ تفاوت کلیدی به زبان ساده

ویژگیRelationalDocumentSchemaثابت انعطاف‌پذیرRelationstable join embedded یا reference Query SQL JSON-like query Use Caseتراکنش حساس اپلیکیشن web/mobile


4️⃣ مثال واقعی برای یک پروژه

فرض کن داری سیستم رزرو کلاس آنلاین می‌سازی:

  • Relational:

    • جدول users, courses, enrollments

    • join‌ها زیاد، query پیچیده اما تراکنش‌ها امن هستند

  • Document:

    • collection users با embed کردن enrollments

    • راحت read/write، schema تغییر می‌کند (مثلاً اضافه شدن field جدید در enrollments)


💡 نکته حرفه‌ای:

هیچ وقت “یک مدل برای همه پروژه‌ها” نیست. اگر داده‌ها transactional و مرتب هستند → relational. اگر سریع، flexible و JSON-friendly هستند → document.

The Birth of NoSQL

1️⃣ چی شد که NoSQL به وجود آمد؟

  • در دهه ۲۰۱۰، بعضی شرکت‌ها به مقیاس‌پذیری خیلی بالا نیاز داشتند، چیزی که relational DBها به سختی می‌توانستند بدهند.

  • همچنین خیلی‌ها می‌خواستند schema انعطاف‌پذیر داشته باشند تا با تغییرات سریع اپلیکیشن هماهنگ شوند.

  • نام NoSQL در اصل یک هشتگ توییتر بود، ولی بعداً معنای واقعی آن شد: Not Only SQL → یعنی فقط SQL نیست!


2️⃣ چرا NoSQL محبوب شد؟

  • Scalability بالا: دیتاست‌های بزرگ یا write-heavy workloads راحت‌تر مدیریت می‌شوند.

  • Open-source: ترجیح شرکت‌ها به جای DBهای تجاری، DBهای رایگان و متن‌باز.

  • Query خاص: بعضی عملیات query مثل search روی JSON یا graph، در relational سخت یا کند است.

  • Flexibility: schema dynamic → راحت می‌توان فیلد جدید اضافه کرد بدون migration پیچیده.


3️⃣ کجاها کاربرد دارد؟

مثال کاربردی:

Social Media : ذخیره پست‌ها و کامنت‌ها به صورت document (MongoDB)

Analytics / Logs : ذخیره لاگ‌ها با write-heavy workload (Cassandra)

Real-time Recommendations: کش و دیتاست dynamic (Redis, DynamoDB)

Graph-like Data شبکه اجتماعی، روابط کاربران (Neo4j)

💡 نکته مهم:

NoSQL قرار نیست جای relational را بگیرد؛ بلکه مکمل آن است. ایده polyglot persistence یعنی برای هر بخش اپلیکیشن، بهترین دیتاست را انتخاب می‌کنیم.
مثال: کاربران و تراکنش‌ها → relational؛ پست‌ها و کامنت‌ها → document DB؛ لاگ‌ها → wide-column DB.


4️⃣ مثال عملی کد (Document DB)

فرض کن داری سیستم شبکه اجتماعی می‌سازی و می‌خوای پست‌ها و کامنت‌ها را ذخیره کنی:

db.posts.insertOne({ userId: "123", content: "Hello world!", comments: [ { userId: "456", text: "Nice post!" }, { userId: "789", text: "Great!" } ], tags: ["fun", "intro"], createdAt: new Date() });
  • اگر می‌خواستی همین کار را با relational انجام دهی، باید جدول‌های جداگانه بسازی و join بزنی → پیچیده و کند برای حجم بالا.


💡 جمع‌بندی :

NoSQL = ابزار مناسب برای داده‌های بزرگ، write-heavy، یا schema-dynamic.
Relational = ابزار مناسب برای تراکنش‌ها و consistency بالا.
Hybrid approach = اغلب بهترین راه.

The Object-Relational Mismatch

1️⃣ مسئله اصلی

  • تو داری اپلیکیشن با OOP می‌نویسی: کلاس‌ها و آبجکت‌ها.
    مثال:

class User: def __init__(self, id, first_name, last_name, positions): self.id = id self.first_name = first_name self.last_name = last_name self.positions = positions # لیست شغل‌ها
  • دیتابیس relational: جدول، ردیف، ستون

    • جدول users: فقط id, first_name, last_name

    • جدول positions: user_id, job_title, organization

مشکل: آبجکت تو یک ساختار tree-like (User → Positions → Education) دارد ولی relational DB flat است.
برای fetch یک user با همه positions، باید چند query یا join پیچیده انجام دهی.
این disconnect بین آبجکت و جدول را می‌گویند impedance mismatch ⚡


2️⃣ راه‌حل‌های معمول

الف) Traditional SQL (Normalized)

  • هر child object → جدول جدا

  • foreign key برای ارتباط

SELECT * FROM users u JOIN positions p ON u.id = p.user_id WHERE u.id = 251;
  • ✅ مزیت: تراکنش‌ها امن، consistency

  • ❌ عیب: query پیچیده، fetch یک آبجکت کامل سخت

ب) Structured / JSON column در SQL

  • برخی DBها مثل PostgreSQL، MySQL، SQL Server اجازه می‌دهند که ستون‌ها JSON یا XML باشند

  • می‌توان چند value را در یک row ذخیره کرد

  • query روی داخل JSON هم امکان‌پذیر است

SELECT data->'positions' FROM users WHERE id = 251;
  • ✅ ساده‌تر، locality بهتر

  • ⚠ هنوز تراکنش‌ها محدود به row، و بعضی queryها پیچیده هستند

ج) Full Document / JSON in Document DB

  • کل object → یک سند JSON

  • مثال MongoDB:

db.users.insertOne({ user_id: 251, first_name: "Bill", last_name: "Gates", positions: [ { job_title: "Co-chair", organization: "Bill & Melinda Gates Foundation" }, { job_title: "Co-founder, Chairman", organization: "Microsoft" } ], education: [ { school_name: "Harvard University", start: 1973, end: 1975 } ], contact_info: { blog: "...", twitter: "..." } });
  • ✅ یک query کافی برای fetch کل object

  • ✅ ساختار tree-like آبجکت حفظ می‌شود

  • ✅ schema flexible، می‌توان فیلد جدید اضافه کرد بدون migration

  • ⚠ تراکنش multi-document محدودتر

  • ⚠ query پیچیده نیاز به index و aggregation دارد


مثال واقعی و تصمیم‌گیری

پروژه شبکه اجتماعی:

  • کاربران و پروفایل‌ها → Document DB (MongoDB)

    • چون user → posts, comments → tree-like است

    • یک query کافی کل اطلاعات را fetch می‌کند

  • تراکنش مالی یا حسابداری → Relational DB (PostgreSQL)

    • ACID مهم است، consistency باید حفظ شود

جمع‌بندی :
وقتی داده‌ها self-contained و tree-like هستند، Document DB بهترین انتخاب است.
وقتی transaction-heavy و consistency-critical هستند → Relational DB بهترین است.
در دنیای واقعی اغلب hybrid approach یعنی ترکیب هر دو، رایج است.

Many-to-One and Many-to-Many Relationships

موضوع دربارهٔ اینه که چرا بعضی فیلدها رو به جای متن، باید به صورت ID ذخیره کنیم و این موضوع چطور باعث ایجاد رابطه‌های many-to-one و many-to-many می‌شه — و چرا این روابط در document DBها (مثل MongoDB) دردسر بیشتری دارن.


🔶 1) چرا region و industry رو به صورت ID ذخیره می‌کنیم، نه متن؟

کتاب میگه در مثال رزومه (مثل پروفایل لینکدین)، به‌جای این‌که:

"region": "Greater Seattle Area", "industry": "Philanthropy"

بیایم و ذخیره کنیم:

"region_id": 23, "industry_id": 7

❗ چرا؟ ۵ دلیل خیلی مهم:

1️⃣ یکپارچگی در املاء و ظاهر

اگر ۱۰ میلیون کاربر وجود داشته باشه، هرکی یه جور می‌نویسه:

  • seattle

  • Seattle

  • Greater Seattle Area

  • Seattle area

با ID این مشکل حل می‌شود.


2️⃣ جلوگیری از ابهام

دو تا شهر هم‌نام وجود داره:

  • Paris در فرانسه

  • Paris در تگزاس

اگر فقط string ذخیره کنیم، ambiguity داریم.
با ID هیچ ابهامی نیست.


3️⃣ تغییر نام بدون مشکل

اگر فردا به دلیل سیاسی نام منطقه عوض شود،
→ فقط یک بار در جدول region تغییر می‌دهی
→ تمام پروفایل‌ها به‌روز می‌شن

اگر متن مستقیم ذخیره شده بود؟
→ باید میلیون‌ها رکورد را update کنی
→ احتمال inconsistency خیلی زیاد می‌شه


4️⃣ امکان ترجمه‌ی اتوماتیک (localization)

وقتی عبارت "Greater Seattle Area" یک ID باشد،
→ نمایش آن در UI می‌تواند مطابق زبان کاربر نمایش داده شود.

مثلاً کاربر آلمانی:

  • „Großraum Seattle“

کاربری در ایران:

  • «منطقه بزرگ سیاتل»

بدون تغییر در دیتابیس اصلی.


5️⃣ بهبود جستجو

اگر ID باشد: دیتابیس می‌داند Seattle در Washington است.

اما اگر فقط متن باشد:
دیتابیس این معنی را نمی‌فهمد مگر خودت بنویسی.


⭐ نتیجهٔ این بخش:

استفاده از ID باعث می‌شود اطلاعات ثابت فقط در یک جا ذخیره شود
→ این همان Normalization است.


🔶 2) چرا این کار باعث ایجاد many-to-one می‌شود؟

مثال:

  • میلیون‌ها کاربر

  • ولی فقط ۲۵۰۰ شهر

  • یا فقط ۲۰۰ صنعت

یعنی:

many users → one industry many users → one region

➡️ این خودِ many-to-one است.

در relational database → کاملاً طبیعی
در document database → مشکل‌زا، چون join سخت است و باید دستی انجام شود.


🔶 3) نقش Document DB و مشکل Join

در MongoDB:

  • join وجود ندارد

  • یا فقط aggregate lookup هست ولی ضعیف‌تر از SQL

  • بنابراین معمولاً embedding ترجیح دارد

اما در این مثال‌ها، embedding بد است چون:

  • اگر industry تغییر کند → باید همه رزومه‌ها update شوند

  • اگر اسم region عوض شود → همه را باید تغییر بدهی

  • یعنی duplication خطرناک می‌شود

این یعنی:
document model برای داده‌هایی با روابط زیاد، مناسب نیست.


🔶 4) وقتی سیستم بزرگ می‌شود، داده‌ها interconnected می‌شوند

کتاب می‌گوید:

حتی اگر اول پروژه ساده باشد، در آینده روابط زیاد می‌شود و از کنترل خارج می‌شود.

مثال‌هایی که کتاب می‌زند:


1️⃣ Company و School را از string تبدیل به entity کنیم

ابتدا ذخیره می‌کردی:

"company": "Microsoft"

ولی می‌خواهی یک صفحه برای شرکت داشته باشی
(لوگو، توضیحات، news feed و …)

پس تبدیل می‌شود به:

"company_id": 55

حالا:

  • میلیون‌ها رزومه به یک company_id وصل هستند
    → many-to-one


2️⃣ توصیه‌نامه (Recommendation)

کاربر A به کاربر B توصیه‌نامه می‌دهد.

در رزومه‌ی B نمایش داده می‌شود.

ولی اطلاعات A مثل عکس پروفایل اگر عوض شود باید همه‌جا آپدیت شود.

پس در recommendation ذخیره می‌کنی:

"author_user_id": 123

→ باز هم ID
→ باز هم join لازم
→ باز هم many-to-one

اما رزومه B شامل توصیه‌نامه‌های متفاوت از چند نفر است
→ پس می‌شود many-to-many:

User (writers) →← Recommendations →← User (receivers)

🔶 5) مثال کامل و ساده‌سازی شکل کتاب (شکل 2-4)

تصور کن رزومه مثل لینکدین است:

یک کاربر می‌تواند:

  • در چند شرکت کار کند

  • چند مدرک تحصیلی داشته باشد

  • از چند نفر توصیه‌نامه بگیرد

  • به چند نفر توصیه‌نامه بدهد

  • سازمان‌ها و مدرسه‌ها خود entity شوند

  • region / industry هم entity باشد

در نتیجه:

  • user ←→ company → many-to-many

  • user ←→ school → many-to-many

  • user ←→ recommendation ←→ user (دوربرگرد)

یعنی:

هر ویژگی جدید → یک رابطه جدید → پیچیدگی بیشتر → نیاز به join بیشتر

به همین دلیل document DBها به مشکل می‌خورند.


🔥 جمع‌بندی به زبان ساده

  1. اطلاعات انسانی تکرارشونده باید با ID ذخیره شوند

  2. این کار Normalization است

  3. این باعث Many-to-One و Many-to-Many می‌شود

  4. SQL برای join فوق‌العاده است

  5. Document DBها برای join ضعیف هستند

  6. پروژه‌ها وقتی بزرگ می‌شوند، داده‌ها interconnected می‌شوند

  7. در نهایت، مدل Document صرفاً برای موارد tree-like خوب است

    • مثل سفارش → آیتم‌های سفارش

    • پست → کامنت‌ها

  8. اما برای شبکه‌های اجتماعی، رزومه، سیستم‌های جستجو:
    Relational یا Graph DB بهتر است

خلاصه کتاب
۰
۰
Setare Behzadi
Setare Behzadi
مهندسی نرم افزار و توسعه دهنده وب | نکاتی در مورد وب که فکر میکنم میتونه واسه خیلی ها مناسب باشد رو منتشر میکنم.
شاید از این پست‌ها خوشتان بیاید