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