סוגי אינדקסים ב-Cloud Firestore

אינדקסים הם גורם חשוב בביצועים של מסד נתונים. בדומה לאינדקס של ספר שממפה נושאים בספר למספרי דפים, אינדקס של מסד נתונים ממפה את הפריטים במסד הנתונים למיקומים שלהם במסד הנתונים. כששולחים שאילתה למסד נתונים, הוא יכול להשתמש במדד כדי לזהות במהירות את המיקומים של הפריטים שביקשת.

בדף הזה מתוארים שני הסוגים של אינדקסים שבהם Cloud Firestore משתמש: אינדקסים של שדה יחיד ואינדקסים מורכבים.

ההגדרה והמבנה של האינדקס

אינדקס מוגדר על רשימה של שדות במסמך נתון, עם מצב אינדקס תואם לכל שדה.

אינדקס מכיל רשומה לכל שדה שצוין בהגדרת האינדקס. האינדקס כולל את כל המסמכים שיכולים להיות תוצאות של שאילתות שמבוססות על האינדקס. מסמך נכלל באינדקס רק אם הוגדר לו ערך שנוסף לאינדקס לכל שדה שנעשה בו שימוש באינדקס. אם הגדרת האינדקס מתייחסת לשדה שלא הוגדר לו ערך במסמך, המסמך לא יופיע באינדקס. במקרה כזה, המסמך אף פעם לא יוחזר כתוצאה של שאילתות שמבוססות על האינדקס.

האינדקס המורכב ממוין לפי ערכי השדות, לפי הסדר שצוין בהגדרת האינדקס.

אינדקס שמאחורי כל שאילתה

אם אין אינדקס לשאילתה, רוב מסדי הנתונים סרקים את התוכן שלהם פריט אחרי פריט. זהו תהליך איטי שמאט עוד יותר ככל שמסד הנתונים גדל. Cloud Firestore מבטיח ביצועים גבוהים של שאילתות באמצעות שימוש באינדקסים לכל השאילתות. כתוצאה מכך, ביצועי השאילתה תלויים בגודל של קבוצת התוצאות ולא במספר הפריטים במסד הנתונים.

פחות ניהול של אינדקסים, יותר פיתוח אפליקציות

Cloud Firestore כולל תכונות שמקצרות את משך הזמן הנדרש לניהול האינדקס. האינדקסים הנדרשים לשאילתות הבסיסיות ביותר נוצרים באופן אוטומטי. כשאתם משתמשים באפליקציה ובודקים אותה, Cloud Firestore עוזר לכם לזהות וליצור אינדקסים נוספים שנדרשים לאפליקציה.

סוגי מדדים

ב-Cloud Firestore נעשה שימוש בשני סוגי אינדקסים: שדה יחיד ומורכב. בנוסף למספר השדות שנוספו לאינדקס, יש הבדלים בין אינדקסים של שדה יחיד לאינדקסים מורכבים גם באופן הניהול שלהם.

אינדקסים של שדה יחיד

אינדקס של שדה יחיד מאחסן מיפוי ממוין של כל המסמכים באוסף שמכילים שדה ספציפי. כל רשומה באינדקס של שדה יחיד מתעדת את הערך של מסמך בשדה ספציפי ואת המיקום של המסמך במסד הנתונים. Cloud Firestore משתמש באינדקסים האלה כדי לבצע הרבה שאילתות בסיסיות. כדי לנהל אינדקסים של שדה יחיד, צריך להגדיר את ההגדרות של ההוספה האוטומטית לאינדקס ואת ההחרגות מהוספה לאינדקס של מסד הנתונים.

הוספה אוטומטית לאינדקס

כברירת מחדל, Cloud Firestore שומרת באופן אוטומטי אינדקסים של שדה יחיד לכל שדה במסמך וכל שדה משנה במפה. Cloud Firestore משתמש בהגדרות ברירת המחדל הבאות למפתחות של שדה יחיד:

  • לכל שדה שאינו מערך או מפה, Cloud Firestore מגדיר שני אינדקסים של שדה יחיד ברמת האוסף, אחד במצב עולה ואחד במצב יורד.

  • לכל שדה מפה, Cloud Firestore יוצר את הפריטים הבאים:

    • אינדקס עולה אחד ברמת האוסף לכל שדה משנה שאינו מערך או מפה.
    • אינדקס יורד אחד ברמת האוסף לכל שדה משנה שאינו מערך או מפה.
    • אינדקס אחד של מערך-מכיל ברמת האוסף לכל שדה משנה של מערך.
    • Cloud Firestore יוצר אינדקס באופן רפלקסיבי לכל שדה משנה של המפה.
  • לכל שדה מערך במסמך, Cloud Firestore יוצר ומנהל אינדקס של מערך שמכיל אוסף.

  • אינדקסים של שדה יחיד ברמת קבוצת האוספים לא מתוחזקים כברירת מחדל.

החרגות באינדקס של שדה יחיד

כדי לפטור שדה מההגדרות של הוספה אוטומטית לאינדקס, יוצרים החרגה של שדה יחיד מהאינדקס. החרגה מהוספה לאינדקס מבטלת את הגדרות האינדקס האוטומטיות ברמת מסד הנתונים. באמצעות החרגה אפשר להפעיל אינדקס של שדה יחיד שההגדרות של ההוספה האוטומטית לאינדקס היו משביתות אותו, או להשבית אינדקס של שדה יחיד שההוספה האוטומטית לאינדקס הייתה מפעילה אותו. במאמר שיטות מומלצות להוספה לאינדקס מפורטות דוגמאות למקרים שבהם החרגות יכולות להיות שימושיות.

אפשר להשתמש בערך הנתיב של השדה * כדי להוסיף החרגות מהאינדקס ברמת הקולקציה לכל השדות בקבוצת הקולקציות. לדוגמה, בקבוצת האוספים comments, מגדירים את נתיב השדה כ-* כדי להתאים לכל השדות בקבוצת האוספים comments, ומשביתים את ההוספה לאינדקס של כל השדות בקבוצת האוספים. לאחר מכן תוכלו להוסיף החרגות כדי להוסיף לאינדקס רק את השדות הנדרשים לשאילתות שלכם. הפחתת מספר השדות שנוספו לאינדקס מפחיתה את עלויות האחסון ויכולה לשפר את ביצועי הכתיבה.

אם יוצרים החרגה של שדה יחיד מהאינדקס בשדה מפה, השדות המשניים של המפה יורשים את ההגדרות האלה. עם זאת, אפשר להגדיר החרגות של שדות בודדים לאינדקס בשדות משנה ספציפיים. אם מוחקים פטור בשדה משנה, השדה המשנה יקבל בירושה את הגדרות הפטור של השדה ההורה, אם הן קיימות, או את ההגדרות ברמת מסד הנתונים, אם אין פטורים ברמת ההורה.

במאמר ניהול אינדקסים מוסבר איך יוצרים ומנהלים החרגות של אינדקס עם שדה יחיד.

אינדקסים מורכבים

אינדקס מורכב מאחסן מיפוי ממוין של כל המסמכים באוסף, על סמך רשימה מסודרת של שדות להוספה לאינדקס.

ב-Cloud Firestore נעשה שימוש באינדקסים מורכבים כדי לתמוך בשאילתות שעדיין אין להן תמיכה באינדקסים של שדה יחיד.

Cloud Firestore לא יוצרת באופן אוטומטי אינדקסים מורכבים כמו שהיא עושה באינדקסים של שדה יחיד, בגלל המספר הגדול של שילובי השדות האפשריים. במקום זאת, Cloud Firestore עוזר לכם לזהות וליצור את המדדים המשולבים הנדרשים בזמן פיתוח האפליקציה.

בכל פעם שמנסים להריץ שאילתה שלא נתמכת על ידי אינדקס, הפונקציה Cloud Firestore מחזירה הודעת שגיאה עם קישור ליצירת האינדקס החסר.

אפשר גם להגדיר ולנהל באופן ידני אינדקסים מורכבים באמצעות המסוף או באמצעות CLI של Firebase. מידע נוסף על יצירה וניהול של אינדקסים מורכבים זמין במאמר ניהול אינדקסים.

מצבי הוספה לאינדקס והיקפי שאילתות

ההגדרה של אינדקסים של שדה יחיד ושל אינדקסים מורכבים שונה, אבל בשני המקרים צריך להגדיר את המצבים של האינדקסים ואת היקפי השאילתות שלהם.

מצבי אינדקס

כשמגדירים אינדקס, בוחרים מצב אינדקס לכל שדה שנוסף לאינדקס. כל מצב של אינדקס בשדה תומך בתנאי שאילתות ספציפיים בשדה הזה. אפשר לבחור מבין מצבי האינדקס הבאים:

מצב אינדקס תיאור
עלייה השדה תומך בתנאי שאילתות <,‏ <=,‏ ==,‏ >=,‏ >,‏ !=,‏ in ו-not-in, ותומך במיון התוצאות בסדר עולה על סמך ערך השדה הזה.
יורד השדה תומך בתנאי השאילתה <, ‏ <=, ‏ ==, ‏ >=, ‏ >, ‏ !=, ‏ in ו-not-in, ותומך במיון התוצאות בסדר יורד על סמך ערך השדה הזה.
Array‑contains השדה תומך בתנאי שאילתות מסוג array-contains ו-array-contains-any.
Vector תמיכה בתנאי שאילתות של FindNearest בשדה.

היקפי שאילתות

כל אינדקס מוגדר לאוסף או לקבוצת אוספים. זה נקרא היקף השאילתה של האינדקס:

היקף האוסף
כברירת מחדל,
Cloud Firestore יוצרת אינדקסים ברמת האוסף. המדדים האלה תומכים בשאילתות שמחזירות תוצאות מתוך אוסף יחיד.

היקף קבוצת האוספים
קבוצת קולקציות כוללת את כל הקולקציות עם אותו מזהה קולקציה. כדי להריץ שאילתת קבוצת אוספים שמציגה תוצאות מסוננות או מסודרות מקבוצת אוספים, צריך ליצור אינדקס תואם ברמת קבוצת האוספים.

סדר ברירת המחדל והשדה __name__

בנוסף למיון המסמכים לפי מצבי האינדקס שצוינו לכל שדה (עולה או יורד) , האינדקסים מחילים מיון סופי לפי השדה __name__ של כל מסמך. הערך של השדה __name__ מוגדר לנתיב המלא של המסמך. כלומר, מסמכים בקבוצת התוצאות עם אותם ערכי שדות ממוינים לפי נתיב המסמך.

כברירת מחדל, השדה __name__ ממוין באותו כיוון של השדה הממוין האחרון בהגדרת האינדקס. לדוגמה:

איסוף שדות שנוספו לאינדקס היקף השאילתה
ערים name, ‏ __name__ איסוף
ערים המצב , __name__ איסוף
ערים country, ‏ population, ‏ __name__ איסוף

כדי למיין את התוצאות לפי כיוון __name__ שאינו ברירת המחדל, צריך ליצור את האינדקס הזה.

מאפייני אינדקס

אינדקס שמאפשר לבצע את השאילתה בצורה היעילה ביותר מוגדר לפי המאפיינים הבאים:

  • שדות שמשמשים במסנני שוויון
  • שדות שמשמשים בסדרי מיון
  • שדות שמשמשים במסנני טווחים ובמסנני אי-שוויון (שעדיין לא נכללים בסדרי המיון)
  • שדות שמשמשים בצבירה (שעדיין לא נכללים בסדרי מיון ובמסנני טווחים וחוסר שוויון)

Cloud Firestore מחשב את התוצאות של השאילתות באופן הבא:

  1. מזהה את האינדקס התואם לאוסף, למאפייני המסנן, למפעילי המסנן ולסדרי המיון של השאילתה.
  2. מזהה את מיקום האינדקס שממנו מתחילה הסריקה. תחילת המיקום מתחילה במסנני השוויון של השאילתה ומסתיימת במסנני הטווח והאי-שוויון בשדה orderBy הראשון.
  3. התהליך מתחיל לסרוק את האינדקס, ומחזיר כל מסמך שעונה על כל המסננים, עד שתהליך הסריקה יבצע אחת מהפעולות הבאות:
    • נתקל במסמך שלא עומד בתנאי הסינון ומאשר שמסמך נוסף לא יעמוד לעולם בתנאי הסינון במלואם.
    • מגיעים לסוף האינדקס.
    • איסוף של מספר התוצאות המקסימלי המבוקש על ידי השאילתה.

דוגמה להוספה לאינדקס

באמצעות יצירת אינדקסים של שדה יחיד באופן אוטומטי, Cloud Firestore מאפשרת לאפליקציה לתמוך במהירות בשאילתות הבסיסיות ביותר של מסדי נתונים. אינדקסים של שדה יחיד מאפשרים לבצע שאילתות פשוטות על סמך ערכי השדות והמשווים <,‏ <=,‏ ==,‏ >=,‏ > ו-in. בשדות מערך, הם מאפשרים לבצע שאילתות array-contains ו-array-contains-any.

כדי להמחיש את העניין, נבחן את הדוגמאות הבאות מנקודת המבט של יצירת אינדקס. קטע הקוד הבא יוצר כמה מסמכי city באוסף cities ומגדיר את השדות name,‏ state,‏ country,‏ capital,‏ population ו-tags לכל מסמך:

אינטרנט
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    regions: ["west_coast", "socal"] });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    regions: ["east_coast"] });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    regions: ["kanto", "honshu"] });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    regions: ["jingjinji", "hebei"] });

בהנחה שהגדרות ברירת המחדל של ההוספה האוטומטית לאינדקס מופעלות, הפונקציה Cloud Firestore מעדכנת אינדקס אחד של שדה יחיד בעל סדר עולה לכל שדה שאינו מערך, אינדקס אחד של שדה יחיד בעל סדר יורד לכל שדה שאינו מערך, ואינדקס אחד של שדה יחיד שמכיל מערך בשדה המערך. כל שורה בטבלה הבאה מייצגת רשומה במסד נתונים עם שדה יחיד:

איסוף השדה נוסף לאינדקס היקף השאילתה
ערים שם איסוף
ערים מצב איסוף
ערים מדינה אחת () איסוף
ערים גדולה איסוף
ערים אוכלוסייה איסוף
ערים שם איסוף
ערים מצב איסוף
ערים מדינה אחת () איסוף
ערים גדולה איסוף
ערים אוכלוסייה איסוף
ערים array-contains אזורים איסוף

שאילתות שנתמכות על ידי אינדקסים של שדה יחיד

בעזרת האינדקסים האלה של שדה יחיד שנוצרים באופן אוטומטי, אפשר להריץ שאילתות פשוטות כמו:

אינטרנט
const stateQuery = citiesRef.where("state", "==", "CA");
const populationQuery = citiesRef.where("population", "<", 100000);
const nameQuery = citiesRef.where("name", ">=", "San Francisco");

אפשר גם ליצור שאילתות in ושאילתות של שוויון מורכב (==):

אינטרנט
citiesRef.where('country', 'in', ["USA", "Japan", "China"])

// Compound equality queries
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA")
         .where("capital", "==", false)
         .where("state", "==", "CA")
         .where("population", "==", 860000)

אם אתם צריכים להריץ שאילתה מורכבת שמשתמשת בהשוואת טווח (<,‏ <=,‏ > או >=) או אם אתם צריכים למיין לפי שדה אחר, עליכם ליצור אינדקס מורכב לשאילתה הזו.

האינדקס array-contains מאפשר לבצע שאילתה בשדה המערך regions:

אינטרנט
citiesRef.where("regions", "array-contains", "west_coast")
// array-contains-any and array-contains use the same indexes
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])

שאילתות שנתמכות באינדקסים מורכבים

Cloud Firestore משתמש באינדקסים מורכבים כדי לתמוך בשאילתות מורכבות שלא נתמכות באינדקסים של שדה יחיד. לדוגמה, נדרש אינדקס מורכב לשאילתות הבאות:

אינטרנט
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)
// in and == clauses use the same index
citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)

השאילתות האלה מחייבות את האינדקס המשולב הבא. מכיוון שהשאילתה משתמשת בתנאי שוויון (== או in) לשדה country, אפשר להשתמש במצב אינדקס עולה או יורד בשדה הזה. כברירת מחדל, תנאי אי-שוויון מחילים סדר מיון עולה על סמך השדה בתנאי אי-השוויון.

איסוף שדות שנוספו לאינדקס היקף השאילתה
ערים (או ) מדינה, אוכלוסייה איסוף

כדי להריץ את אותן שאילתות אבל בסדר מיון יורד, צריך אינדקס מורכב נוסף בכיוון יורד עבור population:

אינטרנט
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")

citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)
         .orderBy("population", "desc")
איסוף שדות שנוספו לאינדקס היקף השאילתה
ערים country, ‏ population איסוף
cities country, ‏ population איסוף

כדי למנוע ירידה בביצועים שנגרמת כתוצאה ממיזוג של אינדקסים, מומלץ ליצור אינדקס מורכב כדי לשלב שאילתה מסוג array-contains או array-contains-any עם תנאים נוספים:

אינטרנט
citiesRef.where("regions", "array-contains", "east_coast")
         .where("capital", "==", true)

// array-contains-any and array-contains use the same index
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
         .where("capital", "==", true)
איסוף שדות שנוספו לאינדקס היקף השאילתה
ערים תגי array-contains, (או ) באותיות רישיות איסוף

שאילתות שנתמכות על ידי אינדקסים של קבוצות אוספים

כדי להדגים אינדקס ברמת קבוצת האוספים, מוסיפים אוסף משנה מסוג landmarks לחלק מהמסמכים ב-city:

אינטרנט
var citiesRef = db.collection("cities");

citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Bridge",
    category : "bridge" });
citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Park",
    category : "park" });

citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Gallery of Art",
    category : "museum" });
citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Mall",
    category : "park" });

באמצעות האינדקס הבא עם שדה יחיד ברמת הקולקציה, אפשר להריץ שאילתה על הקולקציה landmarks של עיר אחת על סמך השדה category:

איסוף שדות שנוספו לאינדקס היקף השאילתה
ציוני דרך קטגוריה (או ) איסוף
אינטרנט
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

לדוגמה, אם רוצים להריץ שאילתה על ציוני הדרך בכל הערים, צריך להריץ את השאילתה הזו על קבוצת האוספים שמכילה את כל האוספים מסוג landmarks. בנוסף, צריך להפעיל אינדקס landmarks של שדה יחיד ברמת קבוצת האוספים:

איסוף שדות שנוספו לאינדקס היקף השאילתה
ציוני דרך קטגוריה (או ) קבוצת אוספים

כשהאינדקס הזה מופעל, אפשר לשלוח שאילתה לקבוצת האוספים landmarks:

אינטרנט
var landmarksGroupRef = db.collectionGroup("landmarks");

landmarksGroupRef.where("category", "==", "park")
landmarksGroupRef.where("category", "in", ["park", "museum"])

כדי להריץ שאילתה של קבוצת אוספים שמחזירה תוצאות מסוננות או מסודרות, צריך להפעיל אינדקס מתאים של שדה יחיד או אינדקס מורכב ברמת קבוצת האוספים. עם זאת, לא נדרשות הגדרות נוספות של אינדקסים לשאילתות של קבוצות אוספים שלא מסננות או ממיינות את התוצאות.

לדוגמה, אפשר להריץ את השאילתה הבאה של קבוצת האוספים בלי להפעיל אינדקס נוסף:

אינטרנט
db.collectionGroup("landmarks").get()

רשומות אינדקס

מספר הרשומות של מסמך מסוים באינדקס נקבע על סמך האינדקסים שהוגדרו בפרויקט והמבנה של המסמך. רשומות אינדקס נספרות כחלק מהמגבלה על מספר הרשומות באינדקס.

הדוגמה הבאה ממחישה את הרשומות של המסמך ב-Index.

מסמך

/cities/SF

city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]

אינדקסים של שדה יחיד

  • city_name ASC
  • city_name DESC
  • temperatures.summer ASC
  • temperatures.summer DESC
  • temperatures.winter ASC
  • temperatures.winter DESC
  • מערך השכונות מכיל (ASC ו-DESC)

אינדקסים מורכבים

  • city_name ASC, ‏ neighborhoods ARRAY
  • city_name DESC, ‏ neighborhoods ARRAY

רשומות אינדקס

הגדרת ההוספה לאינדקס הזו מובילה לרשומות האינדקס הבאות של המסמך:

אינדקס נתונים שנוספו לאינדקס
רשומות של מדדים עם שדה יחיד
city_name ASC city_name: "San Francisco"
city_name DESC city_name: "San Francisco"
temperatures.summer ASC temperatures.summer: ‏ 67
temperatures.summer DESC temperatures.summer: ‏ 67
temperatures.winter ASC temperatures.winter: 55
temperatures.winter DESC temperatures.winter: 55
מערך השכונות מכיל ASC שכונות: "Mission"
מערך השכונות מכיל DESC שכונות: "Mission"
מערך השכונות מכיל ASC שכונות: 'מרכז העיר'
מערך השכונות מכיל DESC שכונות: 'מרכז העיר'
מערך השכונות מכיל ASC שכונות: "Marina"
מערך השכונות מכיל DESC שכונות: "Marina"
רשומות של אינדקס מורכב
city_name ASC, ‏ neighborhoods ARRAY city_name: "San Francisco", neighborhoods: "Mission"
city_name ASC, ‏ neighborhoods ARRAY city_name:‏ "San Francisco", ‏ neighborhoods:‏ "Downtown"
city_name ASC, ‏ neighborhoods ARRAY city_name:‏ "San Francisco", ‏ neighborhoods:‏ "Marina"
city_name DESC, ‏ neighborhoods ARRAY city_name: "San Francisco", neighborhoods: "Mission"
city_name DESC, ‏ neighborhoods ARRAY city_name:‏ "San Francisco", ‏ neighborhoods:‏ "Downtown"
city_name DESC, ‏ neighborhoods ARRAY city_name:‏ "San Francisco", ‏ neighborhoods:‏ "Marina"

מדדים ותמחור

אינדקסים תורמים לעלויות האחסון של האפליקציה. מידע נוסף על חישוב נפח האחסון של אינדקסים זמין במאמר גודל רשומה באינדקס.

שימוש במיזוג אינדקסים

ה-Cloud Firestore משתמש באינדקס לכל שאילתה, אבל לא חובה להשתמש באינדקס אחד לכל שאילתה. בשאילתות עם כמה תנאי שוויון (==) ואפשרות לתנאי orderBy, Cloud Firestore יכול לעשות שימוש חוזר באינדקסים קיימים. Cloud Firestore יכול למזג את האינדקסים של מסנני שוויון פשוטים כדי ליצור את האינדקסים המורכבים הנדרשים לשאילתות שוויון גדולות יותר.

כדי לצמצם את העלויות של ההוספה לאינדקס, כדאי לזהות מצבים שבהם אפשר להשתמש במיזוג אינדקסים. לדוגמה, באוסף restaurants של אפליקציה לדירוג מסעדות:

  • מסעדות

    • burgerthyme

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

האפליקציה הזו משתמשת בשאילתות כמו: האפליקציה משתמשת בשילובים של תנאי שוויון עבור category, ‏ city ו-editors_pick, ותמיד מבצעת מיון לפי star_rating עולה:

אינטרנט
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

אפשר ליצור אינדקס לכל שאילתה:

איסוף שדות שנוספו לאינדקס היקף השאילתה
מסעדות category, ‏ star_rating איסוף
מסעדות city, ‏ star_rating איסוף
מסעדות category, ‏ city, ‏ star_rating איסוף
מסעדות category, ‏ city, ‏ editors_pick, ‏ star_rating איסוף

פתרון טוב יותר הוא לצמצם את מספר האינדקסים באמצעות היכולת של Cloud Firestore למזג אינדקסים של תנאי שוויון:

איסוף שדות שנוספו לאינדקס היקף השאילתה
מסעדות category, ‏ star_rating איסוף
מסעדות city, ‏ star_rating איסוף
מסעדות editors_pick, ‏ star_rating איסוף

קבוצת האינדקסים הזו קטנה יותר, והיא תומכת גם בשאילתה נוספת:

אינטרנט
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

מגבלות על הוספה לאינדקס

המגבלות הבאות חלות על אינדקסים. מידע נוסף על מכסות ומגבלות זמין במאמר מכסות ומגבלות.

מגבלה פרטים
המספר המקסימלי של אינדקסים מורכבים במסד נתונים
המספר המקסימלי של הגדרות של שדה יחיד במסד נתונים

הגדרה אחת ברמת השדה יכולה להכיל כמה הגדרות לאותו שדה. לדוגמה, החרגה להוספה של שדה יחיד לאינדקס ומדיניות TTL באותו שדה נספרות כהגדרת שדה אחת במסגרת המגבלה.

המספר המקסימלי של רשומות באינדקס לכל מסמך

40,000

מספר הרשומות שנוספו לאינדקס הוא הסכום של הנתונים הבאים לגבי מסמך:

  • מספר הרשומות של אינדקס עם שדה יחיד
  • מספר הרשומות באינדקס המורכב

כדי לראות איך הפונקציה Cloud Firestore הופכת מסמך וקבוצה של אינדקסים לרשאות אינדקס, אפשר לעיין בדוגמה הזו לספירת רשומות אינדקס.

המספר המקסימלי של שדות במסד נתונים מורכב 100
הגודל המקסימלי של רשומה באינדקס

7.5 KiB

במאמר גודל רשומת האינדקס מוסבר איך Cloud Firestore מחשב את גודל רשומת האינדקס.

הסכום המקסימלי של הגדלים של רשומות האינדקס של מסמך

8 MiB

הגודל הכולל הוא הסכום של הנתונים הבאים לגבי מסמך:

  • הסכום של גודל הרשומות של מסמך באינדקס עם שדה יחיד
  • הסכום של הגודל של הרשומות של אינדקס מורכב של מסמך
  • הגודל המקסימלי של ערך שדה שנוסף לאינדקס

    1,500 בייטים

    ערכים של שדות שאורכם עולה על 1,500 בייטים מקוצרים. שאילתות שכוללות ערכי שדות חתוכים עשויות להחזיר תוצאות לא עקביות.

    שיטות מומלצות להוספה לאינדקס

    ברוב האפליקציות אפשר להסתמך על הוספה אוטומטית לאינדקס ועל הקישורים בהודעת השגיאה כדי לנהל את האינדקסים. עם זאת, כדאי להוסיף פטורים בשדה יחיד במקרים הבאים:

    נרתיק תיאור
    שדות מחרוזות גדולים

    אם יש לכם שדה מחרוזת שמכיל לעיתים קרובות ערכים ארוכים של מחרוזות שאתם לא משתמשים בהם לשליחת שאילתות, תוכלו לצמצם את עלויות האחסון על ידי החרגת השדה מהוספה לאינדקס.

    שיעורי כתיבה גבוהים לאוסף שמכיל מסמכים עם ערכים רציפים

    אם מוסיפים לאינדקס שדה שמגדיל או מקטין את הערך שלו באופן רציף בין המסמכים באוסף, כמו חותמת זמן, קצב הכתיבה המקסימלי באוסף הוא 500 פעולות כתיבה לשנייה. אם אתם לא שולחים שאילתות על סמך השדה עם הערכים הרצופיים, תוכלו לפטור את השדה מהוספה לאינדקס כדי לעקוף את המגבלה הזו.

    לדוגמה, בתרחיש שימוש ב-IoT עם קצב כתיבה גבוה, אוסף שמכיל מסמכים עם שדה חותמת זמן עשוי להתקרב למגבלה של 500 פעולות כתיבה לשנייה.

    שדות TTL

    אם אתם משתמשים במדיניות TTL (זמן חיים), חשוב לדעת ששדה ה-TTL חייב להיות חותמת זמן. ההוספה לאינדקס של שדות TTL מופעלת כברירת מחדל, ויכולה להשפיע על הביצועים בשיעורי תנועה גבוהים יותר. מומלץ להוסיף החרגות של שדה יחיד לשדות ה-TTL.

    שדות מפה או מערך גדולים

    שדות גדולים של מפות או מערכי נתונים עלולים להגיע למגבלה של 40,000 רשומות באינדקס לכל מסמך. אם אתם לא שולחים שאילתות על סמך מערך גדול או שדה מפה, כדאי לפטור אותם מהוספה לאינדקס.

    אם אתם משתמשים בשאילתות עם אופרטורים של טווחים ויחסי אי-שוויון בכמה שדות, כדאי לעיין בשיקולים לגבי הוספה לאינדקס שצריך להביא בחשבון כדי לבצע אופטימיזציה של הביצועים והעלות של שאילתות Cloud Firestore.

    מידע נוסף על פתרון בעיות בהוספה לאינדקס (הרחבת היקף האינדקס, שגיאות INVALID_ARGUMENT) זמין בדף לפתרון בעיות.