במאמר הקודם דיברנו על Embedded Documents והאימפלמנטציה שלהם ב-MongoDB. דיברנו גם מעט על מתי משתמשים ב-Embedded Documents ומתי משתמשים ב-reference כאשר חלק מהשיקולים צריכים להיות בנושא מהירות. דבר מאוד חשוב שתורם למהירות הוא כל נושא האינדקס.
אינדקס במסד נתונים מתנהג בדיוק כמו אינדקס שאנחנו מכירים מילדותינו באנציקלופדיה. כלומר – לכל אנציקלופדיה היה כרך נוסף בשם 'אינדקס'. כשהייתי צריך לחפש ערך, הייתי משתמש באינדקס על מנת לאתר את מספר הכרך והעמוד המדויקים ורק אז הולך לאנציקלופדיה. האינדקס איפשר לי למצוא את הערכים במהירות גדולה הרבה יותר כיוון שהוא ל וקומפקטי יותר.
אותו הדבר עם אינדקס במסד נתונים (גם MongoDB וגם אחרים). הוא אמור לסייע לי למצוא את הערך הנכון במהירות. זה לא אומר שצריך להפעיל אינדקס על כל חלק ב-document. הרבה אינדקסים הם מיותרים ועלולים לגרום לבעיות ביצועים כיוון שבכל עדכון או הוספה מסד הנתונים יעבוד מאוד קשה בלעדכן את כל האינדקסים – אבל אינדקסים במקומות ספציפיים, במקומות שמחפשים בהם הרבה יכול מאוד לעזור.
למשל, אם יש לנו document של משתמשים, כדאי להפוך את שם המשתמש לאינדקס – כיוון שזו שאילתה שמריצים המון. ובנוסף שם המשתמש הוא ייחודי. לא כדאי להפוך את הכינוי של המשתמש (nickname או display name) לאינדקס בדרך כלל כי אין המון שאילתות שמתבצעות על הכינוי. אינדקס על 'תיאור המשתמש' בכלל לא יהיה רלוונטי כי גם אין הרבה שאילתות עליו וגם לא יעיל לבחור כאינדקס שדה שיש בו המון טקסט.
אחריי שהבנו את המפתח לבחירת אינדקס נכון, נשאלת השאלה איך יוצרים אינדקס? לשם הדוגמה אפשר ליצור collection חביב של 100,000 רשומות שנוכל להתאמן עליו.
for (i = 0; i < 100000; i++) {var title="number "+i;var body = "Page Body Number "+i; db.pages.insert({"title":title,"body":body});}
אפשר לראות שה-title הוא נהדר בתור משהו שאפשר לבחור בתור אינדקס -בהנחה והאפליקציה שלנו משתמשת בו כנתון לשליפות (בואו נדמיין שכן). איך אני הופך את ה-title ל-index?
db.pages.ensureIndex({"title":1})
זה הכל. צריך לחכות מעט זמן (כמה שניות) עד ש-MongoDB נכנס לפעולה. אם אנו רוצים, אנו יכולים לגרום לפעולה הזו לרוץ ברקע על ידי:
db.pages.ensureIndex({"title":1},{"background":1})
ואיך אנו יודעים שיש אינדקס? הרצה פשוטה של getIndexes על ה-collection.
> db.pages.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.pages"
},
{
"v" : 1,
"key" : {
"title" : 1
},
"name" : "title_1",
"ns" : "test.pages"
}
]
אפשר לראות שבנוסף לאינדקס של ה-title, שלו ציפינו, יש לכל collection גם אינדקס אוטומטי של ה-id. כלומר שאם אנו משתמשים ב-ObjectId על מנת למצוא דברים, אז כבר יש לנו את האינדקס בחינם.
על מנת למחוק את האינדקס שבנינו – למשל אם אנו רוצים ליצור אחד חדש עם אפשרויות או שסתם לא צריך אותו – אפשר להשתמש במתודה dropIndex:
db.pages.dropIndex({"title":1})
אפשר לגרום לאינדקס גם להיות Unique – או ייחודי. מה זאת אומרת? ש-MongoDB יגרום לכל שדה ב-document שהכרזנו עליו כאינדקס ייחודי להיות ייחודי – כלומר אין שניים עם אותו שם. איך עושים את זה?
db.pages.ensureIndex({"title":1},{"unique":1})
ואם נעשה describe אנו נראה ש:
> db.pages.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.pages"
},
{
"v" : 1,
"unique" : true,
"key" : {
"title" : 1
},
"name" : "title_1",
"ns" : "test.pages"
}
]
רואים את ה-unique: true? אם אני אנסה להכניס document עם אותו title, זה מה שאקבל:
> db.pages.insert({"title":"number 62","body":"some body"})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.pages.$title_1 dup key: { : \"number 62\" }"
}
})
כאשר אנו מכריזים על אינדקס, יש עוד כמה אפשרויות שאנחנו יכולים לבחור. היכן האפשרויות האלו מופיעות? בדוקומנטציה של MongoDB. אם הגעתם עד לשלב הזה במדריך, אז אין שום סיבה שלא תלמדו להכיר את הדוקומנטציה המצוינת שלהם. הדוקומנטציה הזו, שגם קופיף יוכל להסתדר איתה היטב, כוללת את כל הפקודות שאפשר להכניס בקונסולה. שם תוכלו למצוא את כל האפשרויות של ensureIndex למשל – ולא רק.
במאמר הבא אנו נדבר על GridFS – כיצד להכניס לתוך MongoDB קבצים בינאריים. יהיה באמת כיף!
2 תגובות
רן, תודה רבה.
כתבת "לא יעיל לבחור כאינדקס שדה שיש בו המון טקסט"
אני מבין שאינדקס מועיל רק במקרים שמחפשים התאמה מלאה. אבל אם יש לי הרבה חיפושים על חלקים מהמחרוזת – זה לא יעזור. זה נכון?
אני מכניס לתוך DB קבצי טקסט, וצריך לאתר את המסמכים שמכילים את המילים של החיפוש. איך אפשר לייעל את התהליך?
שאפו על כל ההשקעה רן!