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

ב-Cloud Firestore אפשר להשתמש במסנני טווח ואי-שוויון בכמה שדות בשאילתה אחת. אתם יכולים להגדיר תנאי טווח ואי-שוויון בכמה שדות, ולפשט את פיתוח האפליקציה על ידי העברת ההטמעה של לוגיקת הסינון המשני אל Cloud 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

$collection = $db->collection('samples/php/cities');
$chainedQuery = $collection
    ->where('population', '>', 1000000)
    ->where('density', '<', 10000);

C#‎

CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef
    .WhereGreaterThan("Population", 1000000)
    .WhereLessThan("Density", 10000);
QuerySnapshot querySnapshot = await query.GetSnapshotAsync();
foreach (DocumentSnapshot documentSnapshot in querySnapshot)
{
    var name = documentSnapshot.GetValue<string>("Name");
    var population = documentSnapshot.GetValue<int>("Population");
    var density = documentSnapshot.GetValue<int>("Density");
    Console.WriteLine($"City '{name}' returned by query. Population={population}; Density={density}");
}

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] ועל Cloud Firestore [מודל הנתונים][2].

ב-Cloud Firestore, הקטע ORDER BY של השאילתה קובע באילו אינדקסים אפשר להשתמש כדי להציג את השאילתה. לדוגמה, שאילתת ORDER BY a ASC, b ASC דורשת אינדקס מורכב בשדות a ASC, b ASC.

כדי לשפר את הביצועים והעלות של שאילתות Cloud 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");

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

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

סדר שדות האינדקס לפי שוויונים, ואחריהם השדה הסלקטיבי ביותר של טווח או אי-שוויון

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

מידע נוסף על יצירת אינדקסים יעילים זמין במאמר [מאפייני אינדקס][4].

סדר השדות בסדר יורד של סלקטיביות אילוצי השאילתה

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

כדי לצמצם את מספר המסמכים ש-Cloud 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, מקבלים את אותה קבוצת מסמכים ולא צריך לשנות את סדר התוצאות בלקוחות, אבל יכול להיות שהשאילתה תקרא הרבה יותר רשומות אינדקס לא רלוונטיות מהשאילתה הקודמת. הסיבה לכך היא ש-Cloud Firestore תמיד מעדיף אינדקס שהתחילית של שדות האינדקס שלו תואמת לסעיף order by של השאילתה. אם experience נוסף לסעיף order by, אז Cloud Firestore יבחר את האינדקס (experience [...], salary [...]) כדי לחשב את תוצאות השאילתה. מכיוון שאין אילוצים אחרים על experience, Cloud Firestore יקרא את כל רשומות האינדקס של האוסף employees לפני החלת המסנן salary כדי למצוא את קבוצת התוצאות הסופית. כלומר, המערכת עדיין קוראת את רשומות האינדקס שלא עומדות במסנן salary, וכך מגדילה את זמן האחזור ואת עלות השאילתה.

תמחור

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

למידע מפורט, קראו את דף [התמחור][5].

מגבלות

בנוסף ל[מגבלות על שאילתות][6], חשוב לשים לב למגבלות הבאות לפני שמשתמשים בשאילתות עם מסנני טווח ואי-שוויון בכמה שדות:

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

המאמרים הבאים

  • מידע נוסף על [אופטימיזציה של שאילתות][3].
  • [מידע נוסף על ביצוע שאילתות פשוטות ומורכבות][8]
  • [איך Cloud Firestore משתמש באינדקסים][9]

[1]: /docs/firestore/query-data/get-data [2]: /docs/firestore/data-model [3]: /docs/firestore/query-data/multiple-range-optimize-indexes [4]: /docs/firestore/concepts/index-overview#index_properties [5]: /docs/firestore/pricing [6]: /docs/firestore/query-data/queries#query_limitations [7]: https://en.wikipedia.org/wiki/Disjunctive_normal_form [8]: /docs/firestore/query-data/queries [9]: /docs/firestore/concepts/index-overview [10]: /docs/firestore/query-data/multiple-range-optimize-indexes