Cloud Firestore 中的索引類型

索引是資料庫效能的重要因素。與 書籍索引,將書籍中的主題對應至頁碼或資料庫索引 會將資料庫中的商品對應至資料庫中的位置。查詢 資料庫,資料庫就能使用索引快速找出 您要求的商品

本頁說明 Cloud Firestore 使用的兩種索引類型: 單一欄位索引複合資料 索引

索引定義和結構

索引是由指定文件的欄位清單定義, 對應每個欄位的對應索引模式

索引包含項目,適用於索引定義中的每個欄位。 索引包括所有可能符合以下查詢條件的文件 索引。文件必須含有已建立索引的值,才會納入索引中 。如果索引定義參照欄位 文件中未設定任何值,該文件便不會出現在索引中。 在這個情況下,系統一律不會將該文件做為任何基於索引的查詢結果傳回。

複合式索引會按照欄位值,依照 索引定義。

每次查詢背後的索引

如果查詢沒有索引,則大部分的資料庫都是透過其內容項目進行檢索 例如隨著資料庫成長,執行速度會變慢 Cloud Firestore 會使用以下項目的索引,保證高效能的查詢: 所有查詢。因此,查詢效能取決於 而非資料庫中的項目數量

減少索引管理,更多應用程式開發

Cloud Firestore 提供的功能可減少使用時間 也不必費心管理索引基本模型需要的索引 系統就會自動為您建立查詢當您使用及測試應用程式時 Cloud Firestore 可幫助你找出 建立應用程式需要的其他索引

索引類型

Cloud Firestore 使用兩種類型的索引:單一欄位和 「複合」。除了已建立索引、單一欄位和 複合式索引的管理方式不同。

單一欄位索引

單一欄位索引儲存了 包含特定欄位的集合單一欄位索引中的每個項目 記錄的特定欄位值及其文件位置 建立資料庫Cloud Firestore 會使用這些索引來執行多個項目 基本查詢。設定資料庫的 自動索引設定和索引豁免設定。

自動建立索引

根據預設,Cloud Firestore 會自動維護單一欄位的索引 文件中的每個欄位,以及地圖中的每個子欄位。Cloud Firestore 針對單一欄位索引使用下列預設設定:

  • 針對每個非陣列和非對應欄位,Cloud Firestore 定義了兩個 collection-scope 單一欄位索引,一個採用遞增模式 另一個則是遞減模式

  • 針對每個地圖欄位,Cloud Firestore 會建立以下項目:

    • 每個非陣列的非對應子欄位各有一個集合範圍遞增索引。
    • 每個非陣列的非對應子欄位建立一個集合範圍遞減索引。
    • 一個集合範圍陣列包含每個陣列子欄位的索引。
    • Cloud Firestore 會以遞迴方式為每個地圖子欄位建立索引。
  • 對於文件中的每個陣列欄位,Cloud Firestore 會建立和 維護集合範圍陣列包含索引。

  • 系統不會維護設有集合群組範圍的單一欄位索引 預設值。

單一欄位索引豁免設定

您可以將特定欄位從自動索引中排除 來建立單一欄位索引豁免設定 索引豁免設定會覆寫整個資料庫的自動索引設定。一個 豁免項目可以啟用自動索引設定的單一欄位索引 否則,系統會停用或停用自動建立索引的單一欄位索引 否則就會啟用如需豁免情況適用的情況,請參閱 建立索引的最佳做法

使用 * 欄位路徑值,針對全部的產品新增集合層級索引豁免設定 集合群組中的多個欄位舉例來說,如果是集合群組 comments,請設定 欄位路徑為 * 以符合 comments 集合群組中的所有欄位, 停用集合群組下所有欄位的索引功能。然後您可以新增 豁免項目,即可只為查詢所需的欄位建立索引。降低 已建立索引的欄位數量會降低儲存空間成本,並可提高寫入效率 才需進行

如果您為某個地圖欄位建立了單一欄位索引豁免設定,則地圖的 子欄位會沿用這些設定。不過,您可以定義單一欄位索引 排除特定子欄位。如果您刪除子欄位的豁免項目 子欄位會沿用父項的豁免設定 (如果有的話),或 如果沒有父項豁免項目,則設為適用於整個資料庫的設定。

如要建立及管理單一欄位索引豁免設定,請參閱 管理索引

複合式索引

複合式索引會儲存集合中所有文件的排序對應關係。 並排序這些欄位

Cloud Firestore 會使用複合式索引支援 單一欄位索引尚未支援的查詢。

Cloud Firestore 不會自動建立類似的複合式索引 因為含有大量可能欄位 組合。但 Cloud Firestore 改為協助您識別及建立 您需要的複合式索引

當您嘗試的查詢不受索引支援時,Cloud Firestore 會傳回錯誤訊息,其中包含一個連結,您可以點選連結以建立缺少的 索引。

您也可以手動定義及管理複合式索引 設定管理員、管理 CLI。如需進一步瞭解如何建立及管理 如果是複合式索引,請參閱管理索引

索引模式與查詢範圍

單一欄位和複合式索引的設定方式不同,但兩者都需要 您可以為索引設定索引模式和查詢範圍。

索引模式

定義索引時,您必須為每個已建立索引的欄位選取索引模式。每項 欄位的索引模式支援該欄位的特定查詢子句。個人中心 可從下列索引模式選取:

索引模式 說明
遞增 支援針對欄位的 <<===>=>!=innot-in 查詢子句,並支援根據這個欄位值遞增排序結果。
遞減 支援欄位的 <<===>=>!=innot-in 查詢子句,並支援根據這個欄位值以遞減方式排序結果。
陣列-包含 支援欄位的 array-containsarray-contains-any 查詢子句。
向量 支援欄位的 FindNearest 查詢子句。

查詢範圍

每個索引的範圍都是一個集合或集合群組。已知 做為索引的查詢範圍:

集合範圍
Cloud Firestore 預設會建立含有集合範圍的索引。 這些索引支援只傳回單一集合結果的查詢。

集合群組範圍
集合群組包含 ID 相同的所有集合。目的地: 執行集合群組查詢, 或經過排序的結果,您必須建立與 含有集合群組範圍的索引

預設順序和 __name__ 欄位

除了按照索引模式排序文件之外 每個欄位所指定的值 (遞增或遞減) ,索引會套用最終 依每份文件的 __name__ 欄位排序。__name__ 的值 欄位設為完整的文件路徑。這表示 系統會將結果集中,具有相同欄位值的結果按照文件路徑排序。

根據預設,__name__ 欄位的排序方向與最後一個欄位相同 已排序的欄位例如:

集合 已建立索引的欄位 查詢範圍
城市 姓名,__name__ () 集合
城市 個州/省,__name__ () 集合
城市 國家/地區,人口, __name__ 集合

如要按非預設的 __name__ 方向排序結果,您必須 建立該索引

索引屬性

下列屬性定義了允許查詢執行效率最高的索引:

  • 等式篩選器中使用的欄位
  • 用於排序順序的欄位
  • 用於「範圍」和「不等式」篩選器的欄位 (尚未納入排序順序)
  • 匯總作業中使用的欄位 (尚未納入排序順序、範圍和不相等篩選器)

Cloud Firestore 計算查詢結果的結果如下:

  1. 找出查詢集合、篩選器屬性、篩選器運算子和排序順序對應的索引。
  2. 識別掃描作業的起始索引位置。起始位置的前置字串為查詢的相等篩選器,結尾則會在第一個 orderBy 欄位中的範圍和不等式篩選器結束。
  3. 開始掃描索引,並傳回符合所有篩選器的文件,直到掃描程序執行下列任一操作:
    • 遇到不符合篩選條件的文件,並確認後續的文件一律不會完全符合篩選條件。
    • 達到索引的結尾。
    • 收集查詢要求的結果上限。

索引建立範例

系統會自動為您建立單一欄位索引,Cloud Firestore 可讓應用程式快速支援最基本的資料庫查詢。 單一欄位索引可讓您根據欄位值執行簡單的查詢 和比較子 <<===>=>in。如果是陣列欄位,這類欄位可讓您 即可執行 array-containsarray-contains-any 查詢。

為具體說明,請從以下觀點查看以下範例 建立索引下列程式碼片段會建立 cities 集合中的少數 city 文件,並設定 namestate、 每份文件的 countrycapitalpopulationtags 欄位:

網路
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)

這些查詢需要下列複合式索引。由於查詢使用的是 country 欄位的等式 (==in),您可以使用 這個欄位適用的遞增或遞減索引模式。根據預設 不等式子句會根據 不等式子句。

集合 已建立索引的欄位 查詢範圍
城市 (或 ) 個國家/地區, 人口 集合

如要執行相同的查詢,但採用遞減排序順序, 需要以遞減方向為 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")
集合 已建立索引的欄位 查詢範圍
城市 個國家/地區, 人口 集合
城市 國家/地區 人口 集合

如要避免索引合併造成效能損失,建議您建立 合併 array-containsarray-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 標記, (或 ) 大寫 集合

集合群組索引支援的查詢

如要示範含有集合群組範圍的索引,請新增 對部分 city 文件的 landmarks 子集合:

網路
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()

索引項目

專案設定的索引和文件結構會決定 文件的索引項目數量。索引項目會計入 索引項目數量限制

以下範例示範文件的索引項目。

文件

/cities/SF

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

單一欄位索引

  • 城市名稱 ASC
  • 城市名稱 DESC
  • 隨機性參數 (ASC)
  • 溫度 s.summer DESC
  • Winters.winter ASC
  • results.winter DESC
  • Communitys Array Contains (ASC 和 DESC)

複合式索引

  • City_name ASC,底座 ARRAY
  • City_name DESC,鄰近地區 ARRAY

索引項目

這項索引設定會產生下列索引項目 文件:

索引 已建立索引的資料
單一欄位索引項目
城市名稱 ASC City_name:「San Francisco」
城市名稱 DESC City_name:「San Francisco」
隨機性參數 (ASC) results.summer:67
溫度 s.summer DESC results.summer:67
Winters.winter ASC results.winter:55
results.winter DESC results.winter:55
Communitys Array 包含 ASC 社區:「使命」
Communitys Array 包含 DESC 社區:「使命」
Communitys Array 包含 ASC 社區:「市中心」
Communitys Array 包含 DESC 社區:「市中心」
Communitys Array 包含 ASC 社區:「小艇碼頭」
Communitys Array 包含 DESC 社區:「小艇碼頭」
複合式索引項目
City_name ASC,底座 ARRAY City_name:「舊金山」、社區:「使命」
City_name ASC,底座 ARRAY City_name:「舊金山」、社區:「市區」
City_name ASC,底座 ARRAY City_name:「舊金山」、社區:「小艇碼頭」
City_name DESC,鄰近地區 ARRAY City_name:「舊金山」、社區:「使命」
City_name DESC,鄰近地區 ARRAY City_name:「舊金山」、社區:「市區」
City_name DESC,鄰近地區 ARRAY City_name:「舊金山」、社區:「小艇碼頭」

索引與定價

索引會計入應用程式的儲存空間費用。 如要進一步瞭解如何計算索引的儲存空間大小,請參閱 索引項目大小

使用索引合併

雖然 Cloud Firestore 會使用索引進行各查詢,但實際上 每項查詢都必須有一個索引。適用於具有多個相等條件的查詢 (==) 子句,以及選用 orderBy 子句,Cloud Firestore 則可 重複使用現有的索引Cloud Firestore 可以合併索引以簡化 等式篩選器,用來建構較大等式所需的複合式索引 舉個簡單的例子,您可以定義情境 並指示 AI 如何回應服務中心查詢

找出可以使用索引的時機,即可降低索引成本 合併。例如,在餐廳評分應用程式的 restaurants 集合中:

  • 間餐廳

    • 漢堡

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

這個應用程式使用的查詢如下。應用程式使用相等的組合 categorycityeditors_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")

您可以為每個查詢建立索引:

集合 已建立索引的欄位 查詢範圍
餐廳 類別, 星級評等 集合
餐廳 座城市, 星級評等 集合
餐廳 類別, 城市, 星級評等 集合
餐廳 類別, 城市, 編輯器_pick, 顆星 集合

您可以減少 利用 Cloud Firestore 的合併功能來縮減索引數量 等式子句的索引:

集合 已建立索引的欄位 查詢範圍
餐廳 類別, 星級評等 集合
餐廳 座城市, 星級評等 集合
餐廳 編輯精選,評分: 顆星 集合

不僅如此,這組索引不僅較小,還支援其他查詢:

網路
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

索引限制

以下限制適用於索引。如要進一步瞭解配額和限制,請參閱 配額與限制

限制 說明
資料庫的複合式索引數量上限
資料庫的單一欄位設定數量上限

單一欄位層級設定 同一個欄位可以包含多個設定。例如: 單一欄位的索引豁免項目和存留時間政策 只會計為一個欄位設定,計入限制。

每個文件的索引項目數量上限

40,000 個

索引項目數量是文件中下列兩種項目的總和:

  • 單一欄位索引項目的數量
  • 複合式索引項目的數量

查看 Cloud Firestore 如何轉動文件和一組文件 編入索引為索引項目,請參閱 這個索引項目計數範例

複合式索引中的欄位數量上限 100
索引項目大小上限

7.5 KiB

如要瞭解 Cloud Firestore 如何計算索引項目大小,請參閱 索引項目大小

文件的索引項目大小總和上限

8 MiB

大小總計是文件中下列兩種項目的總和:

  • 文件的單一欄位索引項目大小總和
  • 文件的複合式索引項目大小總和
  • 已建立索引的欄位值大小上限

    1500 個位元組

    超過 1500 個位元組的欄位值會遭到截斷。如果查詢中有欄位值遭截斷,系統可能會傳回不一致的結果。

    建立索引的最佳做法

    大多數應用程式都可以使用自動索引建立功能,以及錯誤訊息連結 來管理索引不過,您可能會想將單一欄位豁免項目新增至 下列情況:

    案件 說明
    大型字串欄位

    如果您的字串欄位經常包含長字串值, 無須用於查詢,只要排除該欄位即可降低儲存費用 建立索引

    集合寫入具有序列值的文件的寫入速度偏高

    如果您建立索引的欄位數量 然後是時間戳記等 集合每秒 500 次寫入如果您不根據含有序列值的欄位執行查詢,可以將該欄位豁免 藉此略過這項限制

    在寫入速率較高的 IoT 用途中,例如,含有時間戳記欄位的文件集合,可能達到每秒 500 次寫入的上限。

    存留時間欄位

    如果使用存留時間 (存留時間) 政策,請留意存留時間 欄位必須為時間戳記。存留時間欄位的索引功能預設為啟用,且 可以在流量率提高的情況下對效能造成影響最佳做法是 保留存留時間欄位的單一欄位豁免情況。

    大型陣列或對應欄位

    大型陣列或對應欄位可能會達到每份文件 40,000 個索引項目的上限。如果您不是根據大型陣列或對應欄位進行查詢,請讓索引不必進行索引。

    如果您在多個欄位使用範圍和不等式運算子的查詢,請參閱建立索引 應考量的重點 效能和 Cloud Firestore 項查詢的費用

    如要進一步瞭解如何解決索引問題 (索引擴散問題、INVALID_ARGUMENT 錯誤),請參閱疑難排解頁面