این مقاله رو اول در Medium نوشتم و با توجه به بازخورد در Reddit و درخواست دوستان تصمیم گرفتم به زبان فارسی هم منتشر کنم.
خب قضیه اینطوریه که همین الان شما عبارت Top web stacks 2021 رو گوگل کنید چندینجا پیشنهاد میدن از دیتابیس Mongo استفاده کنید که این استک ها با اسم های MERN-MEAN-MEVN بیشتر شناخته شده هستن. قطعا Mongo کلی نکته باحال داره و اگر درجای درست استفاده بشه میتونه خیلی هم مفید باشه، اما ایراد اینجاست که اکثرا متوجه نیستن اگر این دیتابیس به عنوان دیتابیس اصلی یک برنامه استفاده بشه چه مشکلاتی میتونه ایجاد کنه.
همونطور که میدونید، Mongo یک نوع دیتابیس NOSQL مبتنی بر document هست. معنی مبتنی بر document اینه که شما لزوما نیازی نیست برای داده ها رابطه تعریف کنید. میتونید دیتای مربوط به یک موجودیت رو داخل یک json درهم ذخیره کنین. این خاصیت، که تقریبا به عنوان ذخیره سازی de-normalized هم شناخته میشه یکی از خاصیت های اصلی Mongo هست. البته Mongo به شما این اجازه رو میده که دیتا رو به صورت normalized (مثل دیتابیس های sql ای) ذخیره کنید، ولی خب این راه هم مشکلات خودش رو داره.
سوال: چرا روش denormalized میتونه بد باشه؟
معمولا هدف اصلی از ذخیره داده بصورت de-normalize بهینه سازی کوئری های خوندن با حذف کردن در خواست های join هست. اما خب این روش زمانی مناسب هست که فیلد های داخلی (مثل contact و address در مثال بالا) رو تنها زمانی نیاز داشته باشیم که کل موجودیت کاربر رو بگیریم. پس اگر بخوایم فیلد های داخلی رو جداگونه دریافت کنیم، دریافتشون کمی مشکلزا میشه.
سوال: اگه فیلد های داخلی یک موجودیت رو بصورت مجزا نیاز داشتیم چیکا کنیم؟
توی این حالت، Mongo توصیه میکنه که از روش normalized استفاده کنین، که دقیقا مثل دیتابیس های sql ای ساده شهرستانی میشه.
توی یک محیط واقعی، اکثر اوقات شما نیاز دارین به این کالکشن ها بصورت مجزا دسترسی داشته باشین، که در این حالت Mongo هیچ برتری ای نسبت به یک پایگاه داده Sql ای به شما نمیده، اما این اتمام ماجرا نیست. اگر شما از روش normalized استفاده کنین، بازدهی دیتابیس هم پایین تر میاد! چراکه استفاده از Join چیزی هست که دیتابیس های SQL ای براش ساخته شده و Mongo قابلیت $lookup رو در ورژن ۳.۲ معرفی کرده که در sharding هم محدودیت هایی داره.
خیلی از توسعه دهنده ها فکر میکنن بازدهی Mongo خیلی خیلی بالاست. هرچند که مفهوم بازدهی خودش جای بحث داره و شاید مقایسه درست نباشه، ۲ تا از benchmark های معروف رو اینجا میزارم.
اینجا arangoDB یک سری دیتابیس رو باهم مقایسه کرده:
و اینجا هم یک مقایسه دیگه از سایت enterpriseDB که بازدهی خوندن دیتا توی Mongo و Postgres رو با thread های موازی مقایسه کرده:
همونطور که میبینید، اگر بازدهی خیلی براتون مهم هست، ممکنه Mongo براتون انتخاب مناسبی نباشه.
(هرچقدر تلاش کردم عنوان بالا رو فارسی کنم نشد، به بزرگی خودتون ببخشین )
مدیریت Transaction که اجازه میده دیتا رو به حالت قبل برگردونین و از RC جلوگیری کنین و .... یکی از قابلیت های خیلی واجب برای هردیتابیسی هست که به شدت در نرمافزار های تجاری استفاده میشه و وقتی دیتا ارزشمند هست، کاملا بهش نیازمند میشیم.
دیتابیس Mongo از ورژن ۴ قابلیت Transactions API رو اضافه کرد، که در نگاه اول خیلی جذاب بود. اما خیلی هشدار بزرگ قرمز رنگ توی داکیومنت Mongo وجود داره که میگه:
مهم: در اکثر حالات، نوشتن در transaction هایی که شامل چند document میشن باعث پایین اومدن بازدهی نسب به دیتا های تک document ای میشه. همچنین نباید دردسترس بودن transaction هایی که شامل چند داکیومنت هستن برای طراحی بهینه الگو دیتا جایگزین بشه.
...
ولی این اتمام ماجرا نیست!
شما برای استفاده از Transcations API به Replicaset هم نیاز دارید !! یعنی اگر از transaction روی یک سرور از Mongo استفاده کنید به خطا میخورید ! محدودیت های زیادی هست که باعث میشه شما در استفاده از Transcations API بهکل پشیمون بشید.
یکی دیگه از مواردی که Mongo خیلی بهش مینازه، طراحی داکیومنت ها بدون ساختار محدودیت هست که خب زمانی که بخوایم از ساختار de-normalized استفاده کنیم، میتونه جذاب باشه. اما این قابلیت باعث میشه هر نوع دیتا ای خواستین بتونین وارد کنین. با این فیچر (یا باگ؟) شما صحت سنجی داده در لایه دیتابیس رو از دست میدین و هرچیزی باید دوبار د لایه اپلیکیشن چک بشه.
به ازای هر تغییر در ساختار دیتا، توصیه میشه یک migration ایجاد بشه که کل دیتا یک ساختار رو بگیره، درغیر اینصورت مجبور میشید کلی if-else کثیف توی کد جاساز کنین که یکم فاجعه میشه.
نه، Mongo هم مثل هر تکنولوژی(یا هرچیزی) معایب و مزایا خودش رو داره. نمیشه بگیم پایگاه داده بدی هست، اما بنظر من، Mongo نباید به عنوان دیتابیس اصلی یک نرم افزار استفاده بشه مگر اینکه توسعه دهنده دقیقا بدونه اپلیکیشن اش قراره چیکار کنه و از تمام نقاط ضعف Mongo آگاه باشه.
خیلی از بلاگ های خوشکل توسعه دهنده پسند، میگن عالیه و خوراکه ME*N استکه. خیلی وقتا هم میگن چون کل استک جاوا اسکریپت هست و همجا میشه جاوا اسکریپت استفاده کرد، باید دیتابیس هم جاوا اسکریپت باشه!! این حرف مثل این میمونه که بگیم چون رابطه روی تمام جنسیت ها قابل انجام هست، حتما باید داشته باشیمش.
هرچیزی جای خودش رو داره و نمیشه برای هر نرم افزاری یه نسخه پیچید. انتخاب تکنولوژی استک، حکم پی ساختمون رو داره و خیلی مهمه بر اساس چه پارامتر های تعیین بشه. هدف پروژه، نیروی انسانی موجود، بودجه، زمان پیاده سازی و ... پارامتر های مهمی هستن که حتما باید در شروع پروژه خوب بررسی بشن.
در آخر، چند تجربه از کسانی که درد مشترک استفاده از Mongo رو چشیدن رو اینجا میزارم: