סקירה כללית של שאילתות עם מסנני טווח ואי-שוויון במספר שדות
ב-Firestore אפשר להשתמש במסנני טווח ובמסנני אי-שוויון בכמה שדות בשאילתה אחת. אתם יכולים להגדיר תנאים של טווח ואי-שוויון בכמה שדות, ולפשט את פיתוח האפליקציה על ידי העברת ההטמעה של לוגיקת הסינון אל Firestore.
מסנני טווח ואי-שוויון בכמה שדות
השאילתה הבאה משתמשת במסנני טווח על אוכלוסייה וצפיפות כדי להחזיר את כל הערים שבהן האוכלוסייה גדולה מ-1,000,000 איש וצפיפות האוכלוסייה קטנה מ-10,000 איש ליחידת שטח.
גרסה 9 מודולרית לאינטרנט
const q = query(
collection(db, "cities"),
where('population', '>', 1000000),
where('density', '<', 10000),
);
Swift
let query = db.collection("cities")
.whereField("population", isGreaterThan: 1000000)
.whereField("density", isLessThan: 10000)
Objective-C
FIRQuery *query =
[[[[self.db collectionWithPath:@"cities"]
queryWhereField:@"population" isGreaterThan:@1000000]
queryWhereField:@"density" isLessThan:@10000];
Java Android
Query query = db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000);
Kotlin+KTX Android
val query = db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000)
המשך
query := client.Collection("cities").
Where("population", ">", 1000000).
Where("density", "<", 10000)
Java
db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000);
Node.js
db.collection("cities")
.where('population', '>', 1000000),
.where('density', '<', 10000)
Python
from google.cloud import firestore
db = firestore.Client()
query = db.collection("cities")
.where("population", ">", 1000000)
.where("density", "<", 10000)
PHP
C#
Ruby
query = cities_ref.where("population", ">", "1000000")
.where("density", "<", 10000)
C++
CollectionReference cities_ref = db->Collection("cities");
Query query = cities_ref.WhereGreaterThan("population", FieldValue::Integer(1000000))
.WhereLessThan("density", FieldValue::Integer(10000));
Unity
CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef.WhereGreaterThan("population", 1000000)
.WhereLessThan("density", 10000);
Dart
final citiesRef = FirebaseFirestore.instance.collection('cities')
final query = citiesRef.where("population", isGreaterThan: 1000000)
.where("density", isLessThan: 10000);
שיקולים בהוספה לאינדקס
לפני שמריצים את השאילתות, כדאי לקרוא על [שאילתות][1] ועל [מודל הנתונים][2] של Firestore.
ב-Firestore, פסוקית ה-ORDER BY של שאילתה קובעת באילו אינדקסים אפשר להשתמש כדי להציג את השאילתה. לדוגמה, שאילתת ORDER BY a ASC, b ASC דורשת אינדקס מורכב בשדות a ASC, b ASC.
כדי לשפר את הביצועים של שאילתות Firestore ולהוזיל את העלויות, כדאי לשנות את סדר השדות באינדקס. כדי לעשות את זה, צריך לוודא שהאינדקס מסודר משמאל לימין כך שהשאילתה תצמצם את מערך הנתונים ותמנע סריקה של רשומות אינדקס לא נחוצות.
נניח שרוצים לחפש באוסף של עובדים ולמצוא עובדים בארצות הברית שהמשכורת שלהם גבוהה מ-100,000 $ומספר שנות הניסיון שלהם גדול מ-0. על סמך ההבנה של מערך הנתונים, ברור שמגבלת המשכורת היא סלקטיבית יותר ממגבלת הניסיון. האינדקס האידיאלי שיצמצם את מספר הסריקות של האינדקס יהיה (salary [...], experience [...]). לכן, השאילתה שתהיה מהירה וחסכונית תסדר את salary לפני experience ותיראה כך:
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.whereGreaterThan("experience", 0)
.orderBy("salary")
.orderBy("experience");
Node.js
db.collection("employees")
.where("salary", ">", 100000)
.where("experience", ">", 0)
.orderBy("salary")
.orderBy("experience");
Python
db.collection("employees")
.where("salary", ">", 100000)
.where("experience", ">", 0)
.order_by("salary")
.order_by("experience");
שיטות מומלצות לאופטימיזציה של אינדקסים
כשמבצעים אופטימיזציה לאינדקסים, כדאי לפעול לפי השיטות המומלצות הבאות.
סידור שדות אינדקס לפי שוויון, ואחריו לפי שדה הטווח או אי-השוויון הכי סלקטיבי
Firestore משתמש בשדות הכי שמאליים של אינדקס מורכב כדי לעמוד במגבלות השוויון ובמגבלות הטווח או אי-השוויון, אם יש כאלה, בשדה הראשון של שאילתת orderBy(). ההגבלות האלה יכולות להקטין את מספר הרשומות באינדקס ש-Firestore סורק. Firestore משתמש בשדות הנותרים של האינדקס כדי לעמוד במגבלות אחרות של טווח או אי-שוויון של השאילתה. המגבלות האלה לא מפחיתות את מספר רשומות האינדקס ש-Firestore סורק, אלא מסננות מסמכים שלא תואמים כדי להקטין את מספר המסמכים שמוחזרים ללקוחות.
מידע נוסף על יצירת אינדקסים יעילים זמין במאמר [מאפייני אינדקס][4].
סידור השדות בסדר יורד של סלקטיביות אילוצי השאילתה
כדי לוודא ש-Firestore בוחר את האינדקס האופטימלי לשאילתה, צריך לציין פסקה orderBy() שמסדרת את השדות בסדר יורד של סלקטיביות אילוצי השאילתה. סלקטיביות גבוהה יותר מתאימה לקבוצת משנה קטנה יותר של מסמכים, בעוד שסלקטיביות נמוכה יותר מתאימה לקבוצת משנה גדולה יותר של מסמכים. חשוב לוודא שבוחרים שדות של טווח או אי-שוויון עם סלקטיביות גבוהה יותר מוקדם יותר בסדר האינדקס מאשר שדות עם סלקטיביות נמוכה יותר.
כדי לצמצם את מספר המסמכים ש-Firestore סורק ומחזיר ברשת, תמיד צריך לסדר את השדות בסדר יורד של סלקטיביות אילוצי השאילתה. אם קבוצת התוצאות לא מסודרת בסדר הנדרש, והיא צפויה להיות קטנה, אפשר להטמיע לוגיקה בצד הלקוח כדי לסדר אותה מחדש בהתאם לסדר הרצוי.
לדוגמה, נניח שרוצים לחפש בין עובדים כדי למצוא עובדים בארצות הברית שהמשכורת שלהם גבוהה מ-100,000 $ולסדר את התוצאות לפי שנת הניסיון של העובד. אם אתם מצפים שרק למספר קטן של עובדים יהיו משכורות גבוהות מ-100,000$, הדרך היעילה ביותר לכתוב את השאילתה היא כדלקמן:
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.orderBy("salary")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
// Order results by `experience`
}
});;
Node.js
const querySnapshot = await db.collection('employees')
.where("salary", ">", 100000)
.orderBy("salary")
.get();
// Order results by `experience`
Python
results = db.collection("employees")
.where("salary", ">", 100000)
.order_by("salary")
.stream()
// Order results by `experience`
הוספת מיון לפי experience לשאילתה תניב את אותה קבוצה של מסמכים ותמנע את הצורך לסדר מחדש את התוצאות בלקוחות, אבל יכול להיות שהשאילתה תעיין בהרבה יותר רשומות אינדקס מיותרות מאשר השאילתה הקודמת. הסיבה לכך היא ש-Firestore תמיד מעדיף אינדקס שהקידומת של שדות האינדקס שלו תואמת לסעיף order by של השאילתה. אם מוסיפים את experience לסעיף order by, Firestore בוחר את האינדקס (experience [...], salary [...]) לחישוב תוצאות השאילתה. מכיוון שאין אילוצים אחרים על experience, Firestore יקרא את כל רשומות האינדקס של האוסף employees לפני שיחיל את המסנן salary כדי למצוא את קבוצת התוצאות הסופית. המשמעות היא שרשומות באינדקס שלא עומדות בדרישות של salaryהמסנן עדיין נקראות, ולכן זמן האחזור והעלות של השאילתה גדלים.
תמחור
החיוב על שאילתות עם מסנני טווח ומסנני אי-שוויון בכמה שדות מבוסס על מספר המסמכים שנקראו ומספר רשומות האינדקס שנקראו.
מידע מפורט זמין בדף [תמחור][5].
מגבלות
בנוסף ל[מגבלות על שאילתות][6], חשוב לשים לב למגבלות הבאות לפני שמשתמשים בשאילתות עם מסנני טווח ומסנני אי-שוויון בכמה שדות:
- אין תמיכה בשאילתות עם מסנני טווח או מסנני אי-שוויון בשדות של מסמכים, ורק אילוצי שוויון במפתח המסמך
(__name__). - ב-Firestore, מספר השדות של טווח או אי-שוויון מוגבל ל-10. המטרה היא למנוע מצב שבו עלות ההרצה של שאילתות תהיה גבוהה מדי.
המאמרים הבאים
- [מידע נוסף על אופטימיזציה של שאילתות][3]
- מידע נוסף על [ביצוע שאילתות פשוטות ומורכבות][8]
- הסבר על [השימוש באינדקסים ב-Firestore][9].
[1]: /firestore/native/docs/query-data/get-data [2]: /firestore/native/docs/data-model [3]: /firestore/native/docs/query-data/multiple-range-optimize-indexes [4]: /firestore/native/docs/concepts/index-overview#index_properties [5]: /firestore/native/docs/pricing [6]: /firestore/native/docs/query-data/queries#query_limitations [7]: https://en.wikipedia.org/wiki/Disjunctive_normal_form [8]: /firestore/native/docs/query-data/queries [9]: /firestore/native/docs/concepts/index-overview [10]: /firestore/native/docs/query-data/multiple-range-optimize-indexes