ایندکس‌های ترکیبی یا چندوجهی

Combined or Multidimensional Indexes

24 اردیبهشت 1401
درسنامه درس 51 از سری دوره جامع آموزش MongoDB
ایندکس های ترکیبی یا چند وجهی

اگر یادتان باشد در جلسه قبل کوئری زیر را داشتیم که برای فیلد gender (یک فیلد رشته ای) یک index می ساخت:

db.contacts.createIndex({gender: 1})

اما با اجرای کوئری زیر متوجه دو موضوع شدیم:

db.contacts.explain("executionStats").find({gender: "male"})

 اولا، این کوئری حدودا نصف کالکشن ما را برمی گرداند بنابراین داده های برگردانده شده بسیار زیاد است. دوما gender فقط دو مقدار ممکن را قبول می کند: male یا female (مذکر یا مونث). با وجود این دو نکته به این نتیجه رسیدیم که شاید تعریف index برای gender آنقدر ها کار درستی نباشد. البته اگر کسی می خواهد این کار را انجام بدهد مشکلی ندارد اما به جای عملکرد یک کوئری خاص حتما سعی کنید عملکرد کل برنامه را در نظر بگیرید چرا که index ها هزینه دارند و این هزینه باید در محلی استفاده شود که واقعا بازده مفید داشته باشد. بنابراین بحث این نیست که آیا ایجاد index برای مقادیر Boolean ضرر دارد یا نه، بلکه بحث این است که آیا index ها در مقادیر Boolean سود زیاد و قابل توجهی دارند یا خیر.

بنابراین ما نمی توانیم برای gender یک index تعریف کنیم، اما اگر بخواهیم افراد بالای 40 سال و مذکر را انتخاب کنیم چطور؟ در اینجا دو متغیر داریم که یکی سن (age) و دیگری جنسیت (gender) است. اینجاست که با مبحثی به نام compound indexes یا ایندکس های ترکیبی مواجه می شویم. ایندکس های ترکیبی دقیقا مانند ایندکس های عادی هستند با این تفاوت که به جای یک فیلد، چند فیلد دارند. نکته مهم اینجاست که ایندکس های ترکیبی دو ایندکس جداگانه نیستند بلکه یک ایندکس هستند که دو فیلد دارد. برای ساخت یک ایندکس مرکب از سن و جنسیت می توان گفت (هنوز این کوئری را اجرا نکنید):

db.contacts.createIndex({"dob.age": 1, gender: 1})

باید در اجرای کوئری بالا دقت ویژه ای داشته باشید چرا که ترتیب فیلد های مشخص شده، مهم است. اگر دستور بالا را اجرا کنیم، لیست ایندکس ما به صورت زیر می شود:

30 male

35 male

33 female

33 male

اما اگر آن را به شکل زیر بنویسیم چطور؟

db.contacts.createIndex({gender: 1, "dob.age": 1})

با این کار، لیست ایندکس ما به صورت زیر خواهد بود:

male 30
male 35
female 33
male 33

این تفاوت شاید در اینجا به چشم نیاید اما در ادامه برای کوئری های شما مهم خواهد بود. من فعلا این کوئری را اجرا می کنم:

db.contacts.createIndex({"dob.age": 1, gender: 1})

حالا ما می توانیم ایندکس ساخته شده را با دو کوئری متفاوت تست کنیم. کوئری اول به شکل زیر است:

db.contacts.explain().find({"dob.age": 35, gender: "male"})

ترتیب age و gender در این کوئری اهمیتی ندارد. اگر این کوئری را اجرا کنیم به جای collection scan از index scan استفاده خواهیم کرد (مقدار "stage" روی IXSCAN است) و سرعت آن از حالت عادی (بدون ایندکس) بیشتر خواهد بود. بنابراین همه چیز طبق انتظار ما است و چیز عجیبی ندیده ایم. در نظر داشته باشید که در این کوئری مقدار "indexName" که همان نام ایندکس ما است (به صورت خودکار توسط MongoDB ساخته می شود) روی dob.age_1_gender_1 قرار گرفته است.

حالا به کوئری دوم نگاه کنید. در این کوئری به جای جنسیت و سن، فقط سن را هدف گرفته ایم:

db.contacts.explain().find({"dob.age": 35})

در گزارش این کوئری نیز، مقدار "stage" روی "IXSCAN" قرار گرفته است بنابراین باز هم به جای collection scan از index scan استفاده کرده ایم که باعث بالا رفتن سرعت برنامه ما می شود. همچنین در این کوئری نیز از همان ایندکس قبلی (dob.age_1_gender_1) استفاده شده است. با این حساب هر دو کوئری از compound index ما استفاده کرده اند اما نکته مهم وجود دارد.

استفاده از compound index ها تنها از چپ به راست ممکن است! یعنی چه؟ بهتر است دوباره به کوئری ساخت index خودمان نگاهی بیندازیم:

db.contacts.createIndex({"dob.age": 1, gender: 1})

در این کوئری اگر از چپ به راست برویم، ابتدا age و سپس gender را مشخص کرده ایم. دو کوئری بالا تر نیز از هر دو یا فقط از age استفاده کرده بودند. بنابراین زمانی می توانیم از این index استفاده کنیم که:

  • یا به دنبال هر دو فیلد age و gender بگردیم.
  • یا به دنبال فیلد سمت چپ (age) بگردیم.

برای تست کردن این موضوع این بار یک کوئری می نویسم که فقط به دنبال مقدار سمت راست (gender) باشد:

db.contacts.explain().find({gender: "male"})

با اجرای این کوئری مثل همیشه یک گزارش می گیریم. اگر به قسمت "winningPlan" در گزارش ذکر شده توجه کنید، مقدار زیر را می بینید:

"stage" : "COLLSCAN"

یعنی stage ما collection scan بوده است و اصلا از index ها استفاده نکرده ایم! یادتان باشد که ساختار ایندکس ما به شکل زیر است:

30 male
35 male
33 female
33 male

ما می توانیم از age به صورت جداگانه استفاده کنیم اما gender وابسته به age است بنابراین نمی توانیم آن را به صورت مستقل جست و جو کنیم. مبنای این ایندکس بر اساس age می باشد و Gender یک مقدار وابسته یا شبیه به یک مقدار embedded عمل می کند که نمی تواند به صورت مستقل مبنای جست و جوی ما باشد.

نکته: حداکثر مجاز تعداد عناصر در یک ایندکس ترکیبی، 31 عنصر است. ما در ایندکس بالا 2 عنصر داشتیم: age و gender. در چنین مواقعی باز هم باید از چپ به راست بروید. مثلا اگر 8 عنصر در یک ایندکس باشند، می توانید از 7 تای اول یا 6 تای اول یا 4 تای اول یا 2 تای اول و غیره استفاده کنید اما نمی توانید از چهارمی یا 3 تای آخر استفاده نمایید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
آخرین سوالات کاربران
5451218 در 3 سال قبل پرسیده:
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو