सबक्वेरी के साथ JOIN ऑपरेशन करना

खास जानकारी

Firestore Enterprise वर्शन, कोरिलेटेड सबक्वेरी की मदद से रिलेशनल-स्टाइल जॉइन के साथ काम करता है. कई NoSQL डेटाबेस में, डेटा को डीनॉर्मलाइज़ करने या क्लाइंट-साइड पर कई अनुरोध करने की ज़रूरत होती है. हालांकि, सबक्वेरी की मदद से, मिलते-जुलते कलेक्शन या सब-कलेक्शन के डेटा को सीधे सर्वर पर जोड़ा और एग्रीगेट किया जा सकता है.

सबक्वेरी ऐसे एक्सप्रेशन होते हैं जो बाहरी क्वेरी से प्रोसेस किए गए हर दस्तावेज़ के लिए, नेस्ट की गई पाइपलाइन को एक्ज़ीक्यूट करते हैं. इससे डेटा को वापस पाने के जटिल पैटर्न चालू हो जाते हैं. जैसे, किसी दस्तावेज़ को उसके सब-कलेक्शन के आइटम के साथ फ़ेच करना या अलग-अलग रूट कलेक्शन में मौजूद, लॉजिक के हिसाब से लिंक किए गए डेटा को जोड़ना.

कॉन्सेप्ट

इस सेक्शन में, पाइपलाइन ऑपरेशन में जॉइन करने के लिए सबक्वेरी इस्तेमाल करने के मुख्य कॉन्सेप्ट के बारे में बताया गया है.

एक्सप्रेशन के तौर पर सबक्वेरी

सबक्वेरी, टॉप-लेवल स्टेज नहीं है. इसके बजाय, यह एक ऐसा एक्सप्रेशन है जिसका इस्तेमाल, एक्सप्रेशन स्वीकार करने वाली किसी भी स्टेज में किया जा सकता है. जैसे, select(...), add_fields(...), where(...) या sort(...).

Cloud Firestore में तीन तरह की सबक्वेरी इस्तेमाल की जा सकती हैं:

  • अरे सबक्वेरी: सबक्वेरी के पूरे नतीजे को दस्तावेज़ों के अरे के तौर पर सेव करें.
  • स्केलर सबक्वेरी: ये क्वेरी, किसी एक वैल्यू का आकलन करती हैं. जैसे, किसी संबंधित दस्तावेज़ से मिली संख्या, औसत या कोई खास फ़ील्ड.
  • subcollection(...) सबक्वेरी: वन-टू-मेनी पैरंट-चाइल्ड रिलेशन के लिए, आसान जॉइन.

दायरा और वैरिएबल

जॉइन लिखते समय, नेस्ट की गई सबक्वेरी को अक्सर "बाहरी" दस्तावेज़ (पैरंट) के फ़ील्ड का रेफ़रंस देना पड़ता है. इन स्कोप को जोड़ने के लिए, let(...) स्टेज (कुछ एसडीके में इसे define(...) कहा जाता है) का इस्तेमाल करें. इससे पैरंट स्कोप में वैरिएबल तय किए जा सकते हैं. इसके बाद, variable(...) फ़ंक्शन का इस्तेमाल करके, सबक्वेरी में उन्हें रेफ़रंस के तौर पर इस्तेमाल किया जा सकता है.

सिंटैक्स

यहां दिए गए सेक्शन में, जॉइन करने के लिए सिंटैक्स की खास जानकारी दी गई है.

let(...) स्टेज

let(...) स्टेज (कुछ एसडीके में इसे define(...) कहा जाता है) एक ऐसी स्टेज है जिसमें डेटा को फ़िल्टर नहीं किया जाता. यह साफ़ तौर पर पैरंट स्कोप से डेटा को किसी नाम वाले वैरिएबल में लाता है, ताकि बाद के नेस्ट किए गए स्कोप में इसका इस्तेमाल किया जा सके.

ऐरे सबक्वेरी

अरे सबक्वेरी, एक्सप्रेशन सबक्वेरी का एक खास केस है. यह सबक्वेरी के पूरे नतीजे को एक अरे में बदल देती है. अगर सबक्वेरी से कोई पंक्ति नहीं मिलती है, तो यह खाली कलेक्शन के तौर पर दिखता है. यह कभी भी null अरे नहीं दिखाता. इस तरह की क्वेरी तब काम आती हैं, जब फ़ाइनल रिज़ल्ट में पूरे नतीजे चाहिए हों. जैसे, नेस्ट किए गए या कोरिलेटेड कलेक्शन को मटीरियलाइज़ करते समय.

क्वेरी, सबक्वेरी में डेटा को फ़िल्टर, क्रम से, और एग्रीगेट कर सकती हैं. इससे फ़ेच और रिटर्न किए जाने वाले डेटा की मात्रा कम हो जाती है. साथ ही, क्वेरी की लागत कम करने में मदद मिलती है. सबक्वेरी के क्रम का पालन किया जाता है. इसका मतलब है कि सबक्वेरी में sort(...) स्टेज, फ़ाइनल कलेक्शन में नतीजों के क्रम को कंट्रोल करता है.

किसी क्वेरी को कलेक्शन में बदलने के लिए, toArrayExpression() SDK रैपर का इस्तेमाल करें.

स्केलर सबक्वेरी

स्केलर सबक्वेरी का इस्तेमाल अक्सर select(...) या where(...) स्टेज में किया जाता है. ऐसा इसलिए, क्योंकि ये फ़िल्टर करने की अनुमति देती हैं या पूरी क्वेरी को सीधे तौर पर लागू किए बिना, सबक्वेरी का नतीजा देती हैं.

एक स्केलर सबक्वेरी जो शून्य नतीजे देती है, उसका आकलन null के तौर पर किया जाएगा. वहीं, एक से ज़्यादा एलिमेंट का आकलन करने वाली सबक्वेरी के नतीजे में, रनटाइम से जुड़ी गड़बड़ी होगी.

जब स्केलर सबक्वेरी, हर नतीजे के लिए सिर्फ़ एक फ़ील्ड जनरेट करती है, तो उस फ़ील्ड को सबक्वेरी के लिए टॉप-लेवल के नतीजे के तौर पर अपग्रेड किया जाता है. आम तौर पर, ऐसा तब होता है, जब सबक्वेरी select(field("user_name")) या aggregate(countAll().as("total")) पर खत्म होती है. यहां सबक्वेरी का स्कीमा सिर्फ़ एक फ़ील्ड होता है. अगर कोई सबक्वेरी कई फ़ील्ड जनरेट कर सकती है, तो उन्हें मैप में रैप किया जाता है.

किसी क्वेरी को स्केलर एक्सप्रेशन में बदलने के लिए, toScalarExpression() SDK टूल रैपर का इस्तेमाल करें.

subcollection(...) सबक्वेरी

subcollection(...) इनपुट स्टेज, एक स्टेज के तौर पर उपलब्ध होता है. इसकी मदद से, Cloud Firestore के हैरारकी वाले डेटा मॉडल पर जॉइन किए जा सकते हैं. सबसे ज़रूरी कॉन्टेंट को पहले दिखाने वाले मॉडल में, क्वेरी को अक्सर किसी दस्तावेज़ के साथ-साथ उसके सब-कलेक्शन से डेटा को वापस पाने की ज़रूरत होती है. हालांकि, collection_group(...) इनपुट स्टेज और पैरंट रेफ़रंस पर फ़िल्टर का इस्तेमाल करके भी ऐसा किया जा सकता है, लेकिन subcollection(...) ज़्यादा सटीक सिंटैक्स उपलब्ध कराता है.

इंप्लिसिट जॉइन कंडीशन के अलावा, यह अरे सबक्वेरी की तरह काम करता है. अगर कोई दस्तावेज़ मैच नहीं होता है, तो यह खाली नतीजा दिखाता है. भले ही, नेस्ट किया गया कलेक्शन मौजूद न हो.

यह मुख्य रूप से सिंटैक्टिक शुगर है: यह हैरारकी वाले संबंध को हल करने के लिए, बाहरी स्कोप में दस्तावेज़ के __name__ को जॉइन कुंजी के तौर पर अपने-आप इस्तेमाल करता है. इस वजह से, पैरंट-चाइल्ड रिलेशनशिप में लिंक किए गए कलेक्शन में लुकअप करने के लिए, यह सबसे सही तरीका है.

उदाहरण

डेटा का उदाहरण

यहां दिए गए उदाहरणों में इस्तेमाल करने के लिए, टेस्ट डेटा का एक सेट लोड किया गया है.

Node.js

// Load set of cities.
const cities = db.collection("cities");

await cities.doc("SF").set({
  name: "San Francisco",
  state: "CA",
  country: "USA",
});
await cities.doc("LA").set({
  name: "Los Angeles",
  state: "CA",
  country: "USA"
});
await cities.doc("DC").set({
  name: "Washington, D.C.",
  state: null,
  country: "USA"
});
await cities.doc("TOK").set({
  name: "Tokyo",
  state: null,
  country: "Japan"
});

// Load restaurants in various cities.
const sfRestaurants = db.collection("cities/SF/restaurants");
const laRestaurants = db.collection("cities/LA/restaurants");
const dcRestaurants = db.collection("cities/DC/restaurants");

const rest1 = await sfRestaurants.add({
  name: "Golden Gate Pizza",
  type: "pizza",
  owner_id: "Mario Rossi"
});
const rest2 = await sfRestaurants.add({
  name: "Bay Area Burger",
  type: "burger",
  owner_id: "Sarah Jenkins"
});
const rest3 = await sfRestaurants.add({
  name: "Sunset Taco",
  type: "mexican",
  owner_id: "Edward"
});

const rest4 = await laRestaurants.add({
  name: "Hollywood Sushi",
  type: "sushi",
  owner_id: "Ken Kenji"
});
const rest5 = await laRestaurants.add({
  name: "Venice Pizza",
  type: "pizza",
  owner_id: "Luigi Romano"
});

const rest6 = await dcRestaurants.add({
  name: "Capitol Tacos",
  type: "mexican",
  owner_id: "Maria Garcia"
});
const rest7 = await dcRestaurants.add({
  name: "Georgetown Coffee",
  type: "cafe",
  owner_id: "David Kim"
});

// Load collection of reviews.
const reviews = db.collection("reviews");

await reviews.add({ restaurant: rest1, rating: 5, reviewer_id: "Alice" });
await reviews.add({ restaurant: rest1, rating: 4, reviewer_id: "Bob" });
await reviews.add({ restaurant: rest2, rating: 4, reviewer_id: "Charlie" });
await reviews.add({ restaurant: rest3, rating: 5, reviewer_id: "Diana" });
await reviews.add({ restaurant: rest3, rating: 4, reviewer_id: "Edward" });
await reviews.add({ restaurant: rest3, rating: 4, reviewer_id: "Fiona" });
// rest4 has 0 reviews
await reviews.add({ restaurant: rest5, rating: 3, reviewer_id: "George" });
await reviews.add({ restaurant: rest6, rating: 5, reviewer_id: "Hannah" });
await reviews.add({ restaurant: rest6, rating: 4, reviewer_id: "Ian" });
await reviews.add({ restaurant: rest7, rating: 5, reviewer_id: "Julia" });

किसी दूसरे कलेक्शन में दस्तावेज़ खोजना

reviews कलेक्शन ग्रुप पर मौजूद यह क्वेरी, प्राथमिक कुंजी के रेफ़रंस का इस्तेमाल करके, restaurant कलेक्शन ग्रुप में लुकअप करती है.

Node.js

let results = await db.pipeline()
  .collectionGroup("reviews")
  .define(field("restaurant").as("restaurant_name"))
  .addFields(db.pipeline()
    .collectionGroup("restaurant")
    .where(field("__name__").equal(variable("restaurant_name")))
    .select("name", "type")
    .toScalarExpression()
    .as("restaurant"))
  .execute();

जवाब

{
  rating: 5,
  reviewer_id "Alice",
  restaurant: { name: "Golden Gate Pizza", type: "pizza" }
},
{
  rating: 4,
  reviewer_id "Bob",
  restaurant: { name: "Golden Gate Pizza", type: "pizza" }
},
{
  rating: 4,
  reviewer_id "Charlie",
  restaurant: { name: "Bay Area Burger", type: "burger" }
},
{
  rating: 5,
  reviewer_id "Diana",
  restaurant: { name: "Sunset Taco", type: "mexican" }
},
{
  rating: 4,
  reviewer_id "Edward",
  restaurant: { name: "Sunset Taco", type: "mexican" }
},
{
  rating: 4,
  reviewer_id "Fiona",
  restaurant: { name: "Sunset Taco", type: "mexican" }
},
{
  rating: 3,
  reviewer_id "George",
  restaurant: { name: "Venice Pizza", type: "pizza" }
},
{
  rating: 5,
  reviewer_id "Hannah",
  restaurant: { name: "Capitol Tacos", type: "mexican" }
},
{
  rating: 4,
  reviewer_id "Ian",
  restaurant: { name: "Capitol Tacos", type: "mexican" }
},
{
  rating: 5,
  reviewer_id "Julia",
  restaurant: { name: "Georgetown Coffee", type: "cafe" }
}

एक से ज़्यादा कलेक्शन को मर्ज करना

यहां दी गई क्वेरी, restaurants कलेक्शन ग्रुप से पिज़्ज़ा की सभी जगहों की जानकारी फ़ेच करती है. साथ ही, अरे सबक्वेरी का इस्तेमाल करके, उनसे जुड़ी समीक्षाओं को फ़ेच करती है और उन्हें सीधे रिस्पॉन्स में एम्बेड करती है.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .where(field("type").equal("pizza"))
  .define(field("__name__").as("restaurant_name"))
  .select(
    field("name"),
    db.pipeline()
      .collectionGroup("reviews")
      .where(field("restaurant").equal(variable("restaurant_name")))
      .select("rating", "reviewer_id")
      .toArrayExpression()
      .as("reviews"))
  .execute();

जवाब

{
  name: "Golden Gate Pizza",
  reviews: [
    { rating: 5, reviewer_id "Alice" },
    { rating: 4, reviewer_id "Bob" }
  ]
},
{
  name: "Venice Pizza",
  type: "pizza",
  owner_id: "Luigi Romano",
  reviews: [
    { rating: 3, reviewer_id "George" }
  ]
}

एक से ज़्यादा कलेक्शन में एग्रीगेट करना

restaurants कलेक्शन ग्रुप पर की गई यह क्वेरी, कोरिलेटेड सबक्वेरी का इस्तेमाल करती है. इससे reviews कलेक्शन ग्रुप में मौजूद हर रेस्टोरेंट की औसत रेटिंग मिलती है.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .where(field("type").equal("pizza"))
  .define(field("__name__").as("restaurant_name"))
  .select(
    field("name"),
    db.pipeline()
      .collectionGroup("reviews")
      .where(field("restaurant").equal(variable("restaurant_name")))
      .aggregate(average("rating").as("avg_rating"))
      .toScalarExpression()
      .as("avg_rating"))
  .execute();

जवाब

{
  name: "Golden Gate Pizza",
  avg_rating: 4.5
},
{
  name: "Venice Pizza",
  avg_rating: 3.0
}

हर ग्रुप के लिए टॉप-N (सीमा के साथ सबक्वेरी)

नीचे दी गई क्वेरी, restaurants कलेक्शन ग्रुप से सभी दस्तावेज़ फ़ेच करती है. साथ ही, हर रेस्टोरेंट के लिए सबसे ज़्यादा रेटिंग वाली दो समीक्षाएं फ़ेच करने के लिए, कोरिलेटेड सबक्वेरी का इस्तेमाल करती है.

इससे यह पक्का होता है कि समीक्षाओं का कलेक्शन बहुत बड़ा न हो जाए और क्वेरी की मेमोरी की सीमा को पार न करे.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .define(field("__name__").as("restaurant_name"))
  .select(
    field("name"),
    db.pipeline()
      .collectionGroup("reviews")
      .where(field("restaurant").equal(variable("restaurant_name")))
      .sort(field("rating").descending())
      .limit(2)
      .select("rating", "reviewer_id")
      .toArrayExpression()
      .as("top_reviews"))
  .execute();

जवाब

{
  name: "Golden Gate Pizza",
  top_reviews: [
    { rating: 5, reviewer_id "Alice" },
    { rating: 4, reviewer_id "Bob" }
  ]
},
{
  name: "Bay Area Burger",
  top_reviews: [
    { rating: 4, reviewer_id "Charlie" }
  ]
},
{
  name: "Sunset Taco",
  top_reviews: [
    { rating: 5, reviewer_id "Diana" },
    { rating: 4, reviewer_id "Edward" }
  ]
},
{
  name: "Hollywood Sushi",
  top_reviews: []
},
{
  name: "Venice Pizza",
  top_reviews: [
    { rating: 3, reviewer_id "George" }
  ]
},
{
  name: "Capitol Tacos",
  top_reviews: [
    { rating: 5, reviewer_id "Hannah" },
    { rating: 4, reviewer_id "Ian" }
  ]
},
{
  name: "Georgetown Coffee",
  top_reviews: [
    { rating: 5, reviewer_id "Julia" }
  ]
}

सब-कलेक्शन में शामिल होना

नीचे दी गई क्वेरी, cities कलेक्शन को स्कैन करती है. साथ ही, हर शहर में रेस्टोरेंट की संख्या का पता लगाने के लिए, नेस्ट किए गए कलेक्शन के दस्तावेज़ों को जोड़ने के लिए, subcollection(...) स्टेज का इस्तेमाल करती है.

Node.js

let results = await db.pipeline()
  .collection("cities")
  .addFields(subcollection("restaurants")
    .toArrayExpression()
    .length()
    .as("restaurant_count"))
  .execute();

जवाब

{
  __name__: cities/SF,
  name: "San Francisco",
  state: "CA",
  country: "USA",
  restaurant_count: 3
},
{
  __name__: cities/LA,
  name: "Los Angeles",
  state: "CA",
  country: "USA",
  restaurant_count: 2
},
{
  __name__: cities/DC,
  name: "Washington, D.C.",
  state: null,
  country: "USA",
  restaurant_count: 2
},
{
  __name__: cities/TOK,
  name: "Tokyo",
  state: null,
  country: "Japan",
  restaurant_count: 0
}

एक से ज़्यादा जॉइन कंडीशन को ज़ाहिर करना

नीचे दी गई क्वेरी, restaurants कलेक्शन ग्रुप को स्कैन करती है और reviews कलेक्शन ग्रुप के साथ मल्टी-फ़ील्ड जॉइन करती है. इससे उन मालिकों का पता चलता है जो अपने रेस्टोरेंट की समीक्षा कर रहे हैं.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .define(field("owner_id"), field("__name__"))
  .where(db.pipeline()
    .collectionGroup("reviews")
    .where(field("restaurant").equal(variable("__name__")))
    .where(field("author").equal(variable("owner_id")))
    .aggregate(count().as("c"))
    .toScalarExpression()
    .greaterThan(0))
  .execute();

जवाब

{
  __name__: cities/SF/restaurants/X9An0HIlx29A9GPuRthS,
  name: "Sunset Taco",
  type: "mexican",
  owner_id: "Edward"
}

एंटी-जॉइन (NOT EXISTS)

नीचे दी गई क्वेरी, restaurants कलेक्शन ग्रुप को स्कैन करती है और उन सभी रेस्टोरेंट को ढूंढती है जिनकी अब तक कोई समीक्षा नहीं की गई है.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .define(field("__name__").as("restaurant_name"))
  .where(db.pipeline()
    .collectionGroup("reviews")
    .where(field("restaurant").equal(variable("restaurant_name")))
    .aggregate(count().as("review_count"))
    .toScalarExpression()
    .equal(0))
  .execute();

जवाब

{
  __name__: "cities/LA/restaurants/X9An0HIlx29A9GPuRthS",
  name: "Hollywood Sushi",
  type: "sushi",
  owner_id: "Ken Kenji"
}

सबक्वेरी को जॉइन के तौर पर इस्तेमाल करना

नीचे दी गई क्वेरी, पिज़्ज़ा की हर जगह और उसकी समीक्षाओं के बीच के संबंध को फ़्लैट करती है. सबक्वेरी को unnest(...) स्टेज में रखकर, सर्वर हर मैच होने वाली समीक्षा के लिए, रेस्टोरेंट के बाहरी दस्तावेज़ की डुप्लीकेट कॉपी बनाता है. इससे फ़्लैट और जुड़े हुए दस्तावेज़ बनते हैं. यह एसक्यूएल INNER JOIN की तरह होता है.

Node.js

let results = await db.pipeline()
  .collectionGroup("restaurants")
  .where(field("type").equal("pizza"))
  .define(field("__name__").as("restaurant_name"))
  .unnest(
    db.pipeline()
      .collectionGroup("reviews")
      .where(field("restaurant").equal(variable("restaurant_name")))
      .select("rating", "reviewer_id")
      .toArrayExpression()
      .as("review"))
  .execute();

जवाब

{
  __name__: "cities/SF/restaurants/xU4pu8nFpnJDPZOwcSPP",
  name: "Golden Gate Pizza",
  type: "pizza",
  owner_id: "Mario Rossi"
  review: { rating: 5, reviewer_id "Alice" }
},
{
  __name__: "cities/SF/restaurants/xU4pu8nFpnJDPZOwcSPP",
  name: "Golden Gate Pizza",
  type: "pizza",
  owner_id: "Mario Rossi",
  review: { rating: 4, reviewer_id "Bob" }
},
{
  __name__: "cities/LA/restaurants/6CYntvNgbYzgaW652Gq1",
  name: "Venice Pizza",
  type: "pizza",
  owner_id: "Luigi Romano",
  review: { rating: 3, reviewer_id "George" }
}

फ़िल्टर के तौर पर अनकोरिलेटेड सबक्वेरी

reviews कलेक्शन पर मौजूद यह क्वेरी, खुद पर एक अनकोरिलेटेड सबक्वेरी का इस्तेमाल करके फ़िल्टर करती है. इससे, औसत रेटिंग से ज़्यादा रेटिंग वाली समीक्षाएं ढूंढी जाती हैं.

Node.js

let results = await db.pipeline()
  .collection("reviews")
  // Average review rating is 4.3
  .where(field("rating").greaterThan(db.pipeline()
    .collection("reviews")
    .aggregate(average("rating").as("avg"))
    .toScalarExpression()))
  .select("rating", "reviewer_id")
  .execute();

जवाब

{
  rating: 5,
  reviewer_id "Alice"
},
{
  rating: 5,
  reviewer_id "Diana"
},
{
  rating: 5,
  reviewer_id "Hannah"
},
{
  rating: 5,
  reviewer_id "Julia"
}

सबसे सही तरीके

  • toArrayExpression() की मदद से मेमोरी मैनेज करना: toArrayExpression() सबक्वेरी का इस्तेमाल सावधानी से करें, क्योंकि बड़ी संख्या में दस्तावेज़ों को इकट्ठा करने से, क्वेरी मेमोरी की सीमा (128 MiB) खत्म हो सकती है. इस समस्या को हल करने के लिए, सबक्वेरी में select(...) का इस्तेमाल करें. इससे सिर्फ़ ज़रूरी फ़ील्ड दिखेंगे. साथ ही, where(...) फ़िल्टर लागू करें, ताकि क्वेरी से मिलने वाले दस्तावेज़ों की संख्या सीमित की जा सके. अगर ज़रूरी हो, तो सबक्वेरी से मिलने वाले दस्तावेज़ों की संख्या को सीमित करने के लिए, limit(...) का इस्तेमाल करें.
  • इंडेक्स करना: पक्का करें कि सबक्वेरी के where(...) क्लॉज़ में इस्तेमाल किए गए फ़ील्ड इंडेक्स किए गए हों. परफ़ॉर्मैंस जॉइन, पूरी टेबल को स्कैन करने के बजाय इंडेक्स को खोजने की क्षमता पर निर्भर करते हैं.

क्वेरी के सबसे सही तरीकों के बारे में ज़्यादा जानने के लिए, क्वेरी ऑप्टिमाइज़ेशन से जुड़ी हमारी गाइड देखें.

सीमाएं

  • subcollection(...) स्कोप: subcollection(...) इनपुट स्टेज सिर्फ़ सबक्वेरी में काम करता है. इसकी वजह यह है कि हैरारकी वाले संबंध को हल करने और जॉइन करने के लिए, पैरंट दस्तावेज़ के कॉन्टेक्स्ट की ज़रूरत होती है.
  • नेस्टिंग डेप्थ: सबक्वेरी को 20 लेयर तक नेस्ट किया जा सकता है.
  • मेमोरी का इस्तेमाल: मटीरियलाइज़्ड डेटा पर 128 MiB की सीमा, पूरी क्वेरी पर लागू होती है. इसमें शामिल किए गए सभी दस्तावेज़ भी शामिल हैं.