SQL یا NoSQL مسئله این است !

NoSQL

توی این مطلب قرار نیست بگم NoSQL خوبه، قیمت سرور ارزون تر در میاد و از این جور مقایسه‌ها؛ بلکه می‌خوام کمی درمورد این که “چطور بفهمیم که برای پروژه باید از NoSQL استفاده کنیم یا نه” صحبت کنم.

خب SQL طبیعتا برای موجودیت ها و مقادیری خوبه که تعداد [فیلد ها] و گستردگی اونها دقیقا مشخص شده.
ولی درکنارش NoSQL برای مواقعی مناسبه که موجودیت ها و تعداد فیلد ها دسته بندی مشخصی نداره مثلا شبکه های اجتماعی و سیستم های آمارگیری.

یا به تعبیر دیگه تفاوت کلیدی پایگاه داده های رابطه ای (RDBMS) و NoSQL توی نحوه پاسخ دادن به مشکلاته. توی RDBMS برای هر مشکلی فقط یک راه حل وجود داره (جدول بساز) ولی NoSQL راه حل‌‎های بیشتری برای حل مشکلات ارائه میده (document, key-value, graph).

مثال اول) دفترچه مخاطبین

دفترچه مخاطبین همیشه یه مثال ساده و قابل فهمه که توی اون به راحتی میشه تفاوت های SQL و NoSQL رو درک کرد، پس بیاید باهم فیلدهای این دفترچه رو تصور کنیم:

  • شناسه
  • نام
  • نام خانوادگی
  • جنسیت
  • شماره تلفن
  • ایمیل
  • آدرس
  • شهر
  • کد پستی
  • کشور

مشکل اول: خیلی از افراد فقط یک شماره تلفن دارن. ولی ممکنه ما نیاز داشته باشیم شماره تلفن منزل، محل کار و شماره موبایل رو ذخیره کنیم، بالاخره هرطور شده ما ممکنه به یه موردی بربخوریم که شماره بیشتری ازش بخوایم. پس باید یه جدول دیگه به اسم تلفن بسازیم (با این کار نرمال سازی هم انجام می‌شه) که بتونیم N شماره برای یک مخاطب ذخیره کنیم.

  • شناسه (contact_id)
  • نوع (type – مثل موبایل، محل کار، خط ثابت)
  • شماره (number)

مشکل دوم: طبیعتا مخاطبی که N شماره داره ممکنه N تا آدرس ایمیل هم داشته باشه پس یه جدول هم برای ایمیل نیاز داریم

  • شناسه (contact_id)
  • نوع (type – مثل ایمیل شخصی، ایمیل کاری و…)
  • آدرس (address)

مشکل سوم: ممکنه برای یک مخاطب اصلا آدرس جغرافیایی وارد نکنیم در کنارش ممکنه یه مخاطب داشته باشیم که پول زیادی قرض گرفته درنتیجه ما خیلی دوسش داریم و باید کلی آدرس ازش ذخیره کنیم. پس یه جدول آدرس هم نیاز داریم.

خب حالا فرض کنیم دفترچه مخاطبین ساخته شد و نرمال سازی های لازم رو هم انجام دادیم حالا می‌شه هر تعداد آدرس جغرافیایی، ایمیل و شماره تلفن که تمایل داشتیم وارد کنیم ولی متاسفانه:

این ساختار انعطاف پذیر نیست

شاید من دلم خواست اکانت توییتر یک نفر رو اضافه کنم، یا تاریخ تولدش یا شغلی که داره؛ به هرحال هرچند تا فیلد که باشه مشکل اینجاست که غیرممکنه من اونها رو فقط به یه شخص خاص اختصاص بدم. پس لازم میشه یه جدول دیگه به اسم otherData بسازم.

داده ها تکه تکه شدن

بررسی پایگاه داده برای توسعه دهنده و حتی کسی که می‌خواد با این دفترچه کار کنه اونقدر هام آسون نیست. بعلاوه این پایگاه داده پیچیدگی زیادی پیدا میکنه و سرعتش هم به همین دلیل کم میشه.

نمیشه داده های یک مخاطب رو با یک SELECT و استفاده مکرر دستور JOIN بیرون کشید (در حقیقت میشه ولی نتیجه شامل همه ی شماره تلفن ها و … میشه، اگرکه یک نفر ۳ شماره تلفن، ۵ آدرس ایمیل و ۲ آدرس جغرافیایی ثبت کنه کوئری ما نهایتا ۳۰ نتیجه برگشت میده).

و مهمتر از همه جستجوی متنی طول می‌کشه، اگر کسی رشته “شریف” رو وارد کنه باید تمام جداول بررسی بشه تا مشخص بشه این رشته اسمه، ایمیله، بخشی از یه آدرسه و یا شماره تلفنه.

راه حل جایگزین

نگرانی ما توی این مورد فیلد های مربوط به افراد هستن. علاوه بر غیرقابل پیش بینی بودن اونها، هرشخص فیلدهای مخصوص به خودش رو داره که با بقیه مشترک نیست. برای این مورد استفاده از NoSQL به نعف ماست چون می‌تونیم اطلاعات تمامی افراد رو در یک سند با قالب Json ذخیره کنیم و به هر شخص فیلد های مخصوص خودش رو اضافه کنیم.

{
name: [
"Billy", "Bob", "Jones"
],
company: "Fake Goods Corp",
jobtitle: "Vice President of Data Management",
telephone: {
home: "0123456789",
mobile: "9876543210",
work: "2244668800"
},
email: {
personal: "bob@myhomeemail.net",
work: "bob@myworkemail.com"
},
address: {
home: {
line1: "10 Non-Existent Street",
city: "Nowhere",
country: "Australia"
}
},
birthdate: ISODate("1980-01-01T00:00:00.000Z"),
twitter: '@bobsfakeaccount',
note: "Don't trust this guy",
weight: "200lb",
photo: "52e86ad749e0b817d25c8892.jpg"
}

به خاطر اینکه تمام اطلاعات توی یک سند ذخیره شدن حالا می‌شه بخشی از اطلاعات یا تمامی اونها رو با یک کوئری به دست آورد. جستجوی متنی هم ساده تر شده چون توی MongoDB می‌تونیم یه ایندکس برای همه‌ی فیلدهای رشته‌ای مشخص کنیم:


db.contact.createIndex({"$**":"text"});

و بعد جستجو برای رشته “شریف” رو به این صورت انجام بدیم:

مثال دوم) سیستم مدیریت انبار

موجودیت های یک انبار مشخص هستن و همچنین فیلدهای مربوط به هر محصول قابل پیش بینی هست. به طور خلاصه سیستم این امکانات رو داره:

  • ثبت محصولاتی که به تازگی وارد انبار شدن و در بخش خاصی قرار دارن
  • ثبت جابجایی مربوط به هر محصول
  • ثبت و تحویل سفارشات و حذف محصول از انبار

و توی پیاده سازی این سیستم باید این موارد رو حتما لحاظ کرد:

  • اطلاعات هر جعبه باید به صورت دقیق ثبت بشه
  • کاهش خطا خیلی مهمه نمیشه یک محصول یهویی ناپدید بشه یا جایی ذخیره بشه که از قبل محصول دیگه ای اونجا قرار داره.
  • این عملیات پیچیدگی خاصی نداره ما دراصل داریم موارد مشخصی رو اضافه یا حذف می‌کنیم یا اونها رو از نقطه a به نقطه b انتقال میدیم

قطعا یک فروشگاه بدون انباری منسجم نمیتونه کار کنه و پیاده کردن این ساختار با استفاده از SQL مقرون به صرفه تره.

مثال سوم) سیستم جمع‌سپاری

در مثال اول چون مقیاس پروژه خیلی کوچیک بود می شد از یک دیتابیس استفاده کرد، و در مثال دوم چون موجودیت ها و مقادیر از یک چهارچوب پیروی می‎کرد انتخاب SQL مقرون به صرفه بود.

حالا بیاید یه سیستم جمع‌سپاری رو درنظر بگیریم:

نمودار ER موجودیت های یک سیستم جمع سپاری
نمودار ER یک سیستم جمع‌سپاری

همونطور که از تصویر پیداست سه مورد کلیدی (حامی – پروژه گذار – پروژه) توی هر سیستم جمع‌سپاری وجود داره که با در نظر گرفتن شرایط زیر قصد داریم نوع پایگاه داده رو مشخص کنیم:

  • فیلد های مربوط به کاربر ثابت و قابل پیش‌بینی هستن.
  • کاربر یا پروژه گذاره و یا حامی، حجم خواندن و نوشتن چندان مورد اهمیت قرار نداره.
  • میزان بازدید کمپین (خواندن) از میزان ویرایش اطلاعات (نوشتن) اون کمپین بیشتره، حجم خواندن و نوشتن مورد اهمیته.

پس می‌تونیم برای موارد ثبتنام، ورود و تنظیمات داشبورد  از RDBMS استفاده کنیم چون میزان خواندن و نوشتن چندان اهمیتی نداره و هرچقدر هم از صفحه پروفایل کاربر بازدید بشه اهمیت اون از کمپین‌ها بالاتر نیست. هرچند هنوز هم فیلد های مشترک و غیر مشترک زیادی داریم اما به طور کلی پیچیدگی خاصی نداره.

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

شرایط و نحوه پیاده سازی این سیستم با توجه به تعریف Polyglot Persistence انتخاب شده و هنوز در “بهترین” حالت خودش قرار نداره (صرفا یک مثال معقول از پیاده کردن این روشه)، من قصد نداشتم بیشتر از این قضیه رو پیچیده کنم. مثلا اگر که سیستم پرداخت رو به موجودیت ها اضافه کنیم استفاده پایگاه داده مبتنی بر key-value برای این بخش مناسب به نظر میرسه و یا برای پیاده کردن سیستم آماری با توجه به گستردگی و مقیاس اطلاعات میشه از column یا graph استفاده کرد.

خودت رو محک بزن !

امیدوارم بعد از مقایسه این مثال ها یک دید اجمالی از کلیت کار پیدا کنید. هرچند هر پروژه شرایط خودش رو داره و نمیشه صرفا بر اساس این مطلب به این نتیجه برسید که باید توی پروژه خودتون از ترکیب MySQL و MongoDB استفاده کنید. شما باید شرایط رو بسنجید و خودتون تصمیم گیرنده باشید.

بعضیا طبق عادت همیشه از دید منفی به قضیه نگاه میکنن و میگن “متاسفانه” الگوریتمی برای تصمیم گیری وجود نداره و شما باید خودتون طبق تجربه ای که دارید قدم بردارید.

اما من میگم “خوشبختانه” هیچ الگوریتمی نیست که ذهن شما رو محدود کنه و همه چیز به خلاقیت خودتون بستگی داره و به شما این امکان داده شده که دانش خودتون رو محک بزنید.

شاید اگر از این مطلب استقبال بشه اونو ادامه بدم و توی یه مطلب دیگه بیشتر درمورد نوع های NoSQL صحبت کنم و شرایط عمده برای انتخاب نوع های مختلف رو توضیح بدم.

Author’s gravatar

عالی بود ممنون

به نظرتون برای سیستم مثل سایت دیوار که روزی بیش از یک میلیون آگهی ثبت میشه چه نوع دیتابیسی بهتره

Author’s gravatar

راستش باید درمورد موجودیت ها، بودجه، زمان پیاده سازی و خیلی چیزای دیگه تحقیق کرد تا به یه نتیجه معقول رسید. چون اینکه بازدید سایت بالاست دلیل نمیشه.

من درمورد موجودیت های سایت دیوار یا کارکرد اون از نظر فنی اطلاعات کمی دارم فکر می کنم در این مورد بهتره از طریق ایمیل گفتگو کنیم.

Author’s gravatar

چشم حتما در اولین فرصت باهاتون تماس میگیریم ، راستشو بخواید الان مشغول پیاده سازی سیستمی مثل دیوارم ، بهینه کردن دیتا بیس خیلی برام مهمه خیلی خوشحال میشم باهاتون یه مشورتی داشته باشم

ایده من واسه این کار این بوده که بخشی از اطلاعات آگهی رو مثل توضیحات به صورت جیسون دخیره کنم و مابقی هم در داخل mysql

بازم ممنون

Author’s gravatar

اقا عالی بود اگه میشه ادامه بدید این مطلب را و اینکه ما باید چه طوری query بزنیم برای این جدول را هم توضیح بدید

Author’s gravatar

ممنون. به فکر پروژه ای بودم که چطور میشه سیستمهای متنوع با ساختار مختلف توسط سیستم یکپارچه اطلاعات آنها را جستجو پذیر کرد . با nosql میشود ممنون از مقالتون

نظری در این مورد دارید؟ خوشحال می‌شم اون رو برام ارسال کنید