盡可能提高查詢效能

如要排解查詢速度緩慢的問題,請使用查詢說明取得查詢執行計畫和執行階段執行設定檔。以下各節說明如何根據執行設定檔,採取步驟最佳化查詢效能:

限制結果數量

請使用執行樹狀結構中的「傳回的記錄」欄位,判斷查詢是否傳回多份文件。建議使用 limit(...) 階段,限制傳回的文件數量。這樣一來,結果透過網路傳回用戶端時,序列化位元組大小就會減少。如果 Limit 節點前面有 MajorSort 節點,查詢引擎可以合併 Limit 和 MajorSort 節點,並以 TopN 排序取代完整的記憶體內具體化和排序,減少查詢的記憶體需求。

限制結果文件大小

建議使用 select(...) 僅傳回必要欄位,或使用 remove_fields(...) 捨棄過大的欄位,藉此限制傳回的文件大小。這有助於降低處理中繼結果的運算和記憶體成本,以及透過網路將結果傳回用戶端時的序列化位元組大小。如果查詢中參照的所有欄位都包含在一般索引中,則查詢也會完全包含在索引掃描中,不需要從主要儲存空間擷取文件。

使用索引

請按照下列操作說明設定及最佳化索引。

判斷查詢是否使用索引

您可以檢查執行樹狀結構中的葉節點,判斷查詢是否使用索引。如果執行樹狀結構的葉節點是資料表掃描節點,表示查詢未使用索引,而是從主要儲存空間掃描文件。如果正在使用索引,執行樹狀結構的葉節點會顯示索引的索引 ID 和索引欄位。

找出更合適的索引

如果索引能減少查詢引擎需要從主要儲存空間擷取的文件數量,或其欄位排序能滿足查詢的排序需求,則該索引對查詢很有幫助。

如果查詢使用索引,但查詢引擎仍擷取並捨棄許多文件 (由傳回許多記錄的掃描節點,以及傳回少量記錄的篩選器節點識別),這表示使用索引滿足的查詢述詞不具選擇性。如要建立更合適的索引,請參閱「建立索引」。

如果查詢使用索引,但查詢引擎仍在對結果集執行記憶體內重新排序 (由查詢執行樹狀結構中的 MajorSort 節點識別),這表示所用索引無法用於提供查詢的排序需求。如要建立更合適的索引,請參閱下一節。

建立索引

按照索引管理說明文件建立索引。為確保查詢可以使用索引,請建立一般 (非多鍵) 索引,並依下列順序排列欄位:

  1. 所有會用於等式運算子的欄位。如要盡可能提高跨查詢重複使用的機率,請按照查詢中等號運算子欄位出現次數的遞減順序排列欄位。
  2. 所有要排序的欄位 (順序相同)。
  3. 將用於範圍或不等式運算子的欄位,依查詢限制選擇性遞減排序。
  4. 在索引中,會做為查詢結果傳回的欄位:在索引中加入這類欄位,可讓索引涵蓋查詢,避免從主要儲存空間擷取文件。

強制執行索引或資料表掃描

查詢 Cloud Firestore 時,系統會自動使用任何可能提高查詢效率的索引。因此,您不需要為查詢指定索引。不過,如果查詢對工作負載至關重要,建議您使用 forceIndex 選項,確保效能更穩定。

在少數情況下,Cloud Firestore 可能會選擇導致查詢延遲時間增加的索引。如果您已按照效能迴歸的疑難排解步驟操作,並確認嘗試使用其他索引進行查詢是合理的做法,則可以使用 forceIndex 選項指定索引。

您可以在管道作業的任何輸入階段使用 forceIndex 選項,覆寫 Cloud Firestore 的預設查詢計畫,並指定要使用的索引,或強制執行資料表掃描。

強制使用特定索引

如要強制查詢使用特定索引,請將索引 ID 做為字串提供給 forceIndex 選項。您可以在控制台或錯誤訊息中找到索引 ID。

以下範例會強制規劃器使用 ID 為 CICAgOi36pgK 的索引:

Node.js
// Force Planner to use Index ID CICAgOi36pgK
await db.pipeline()
  .collectionGroup({ collectionId: "customers", forceIndex: "CICAgOi36pgK" })
  .limit(100)
  .execute();
Java
// Force Planner to use Index ID CICAgOi36pgK
Pipeline.Snapshot results1 =
    firestore.pipeline()
      .collectionGroup("customers", new CollectionGroupOptions()
          .withHints(new CollectionHints().withForceIndex("CICAgOi36pgK")))
      .limit(100)
      .execute().get();
Go
// Force Planner to use Index ID CICAgOi36pgK
snapshot1 := client.Pipeline().
	CollectionGroup("customers", firestore.WithForceIndex("CICAgOi36pgK")).
	Limit(100).
	Execute(ctx)

以下是強制使用特定索引的幾個用途:

  • 測試不同索引的效能。
  • 確保查詢使用特定且已知的最佳索引。
  • 當最佳化工具的預設選擇不適合特定查詢時,覆寫最佳化工具。

如果找不到指定索引,查詢就會失敗。

強制掃描資料表

資料表掃描會讀取集合或集合群組中的文件,不使用任何次要索引。如要強制執行資料表掃描,請將 forceIndex 設為 primary。

以下範例會強制執行資料表掃描:

// Force Planner to only do a Full-Table Scan
db.pipeline()
  .collectionGroup({ collectionId: "customers", forceIndex: "primary" })
  .limit(100)

您可以在下列情況使用資料表掃描:

  • 不適合建立索引的小型集合。
  • 查詢會存取集合中的大部分文件。
  • 用於偵錯和比較成效。

搭配使用 forceIndex 和查詢說明

您可以在 explain 或 analyze 模式中使用查詢說明,觀察 forceIndex 的效果:

  • 檢查執行樹狀結構的葉節點,確認 Cloud Firestore 在 forceIndex 中使用指定的索引。
  • 確認使用 forceIndex: "primary" 時,計畫中會顯示 TableScan 節點。
  • 在 analyze 模式下,比較啟用和停用 forceIndex 時的成效指標 (例如延遲時間、掃描的文件和掃描的索引項目),微調查詢效能。

forceIndex最佳做法

雖然 forceIndex 可讓您進一步控管查詢執行,但 Cloud Firestore 的查詢最佳化工具通常能有效處理大多數用途。使用 forceIndex 時,請考慮下列最佳做法:

  • 請謹慎使用 forceIndex。如果發現預設查詢計畫的效能不佳,請先使用查詢說明診斷問題,再強制使用索引。
  • 使用 forceIndex 時,請務必以實際資料量測試查詢,瞭解其效能和成本特性。
  • 在正式環境中,請避免對大型集合使用 forceIndex: "primary"。

如要進一步瞭解使用查詢說明功能執行的查詢輸出內容,請參閱「查詢執行參考資料」。