如要排解查詢速度緩慢的問題,請使用查詢說明取得查詢執行計畫和執行階段執行設定檔。以下各節說明如何根據執行設定檔,採取步驟最佳化查詢效能:
限制結果數量
請使用執行樹狀結構中的「傳回的記錄」欄位,判斷查詢是否傳回多份文件。建議使用 limit(...) 階段,限制傳回的文件數量。這樣一來,結果透過網路傳回用戶端時,序列化位元組大小就會減少。如果 Limit 節點前面有 MajorSort 節點,查詢引擎可以合併 Limit 和 MajorSort 節點,並以 TopN 排序取代完整的記憶體內具體化和排序,減少查詢的記憶體需求。
限制結果文件大小
建議使用 select(...) 僅傳回必要欄位,或使用 remove_fields(...) 捨棄過大的欄位,藉此限制傳回的文件大小。這有助於降低處理中繼結果的運算和記憶體成本,以及透過網路將結果傳回用戶端時的序列化位元組大小。如果查詢中參照的所有欄位都包含在一般索引中,則查詢也會完全包含在索引掃描中,不需要從主要儲存空間擷取文件。
使用索引
請按照下列操作說明設定及最佳化索引。
判斷查詢是否使用索引
您可以檢查執行樹狀結構中的葉節點,判斷查詢是否使用索引。如果執行樹狀結構的葉節點是資料表掃描節點,表示查詢未使用索引,而是從主要儲存空間掃描文件。如果正在使用索引,執行樹狀結構的葉節點會顯示索引的索引 ID 和索引欄位。
找出更合適的索引
如果索引能減少查詢引擎需要從主要儲存空間擷取的文件數量,或其欄位排序能滿足查詢的排序需求,則該索引對查詢很有幫助。
如果查詢使用索引,但查詢引擎仍擷取並捨棄許多文件 (由傳回許多記錄的掃描節點,以及傳回少量記錄的篩選器節點識別),這表示使用索引滿足的查詢述詞不具選擇性。如要建立更合適的索引,請參閱「建立索引」。
如果查詢使用索引,但查詢引擎仍在對結果集執行記憶體內重新排序 (由查詢執行樹狀結構中的 MajorSort 節點識別),這表示所用索引無法用於提供查詢的排序需求。如要建立更合適的索引,請參閱下一節。
建立索引
按照索引管理說明文件建立索引。為確保查詢可以使用索引,請建立一般 (非多鍵) 索引,並依下列順序排列欄位:
- 所有會用於等式運算子的欄位。如要盡可能提高跨查詢重複使用的機率,請按照查詢中等號運算子欄位出現次數的遞減順序排列欄位。
- 所有要排序的欄位 (順序相同)。
- 將用於範圍或不等式運算子的欄位,依查詢限制選擇性遞減排序。
- 在索引中,會做為查詢結果傳回的欄位:在索引中加入這類欄位,可讓索引涵蓋查詢,避免從主要儲存空間擷取文件。
強制執行索引或資料表掃描
查詢 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"。
如要進一步瞭解使用查詢說明功能執行的查詢輸出內容,請參閱「查詢執行參考資料」。