本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
僅限索引掃描 (涵蓋的查詢)
僅索引掃描 (也稱為涵蓋查詢) 是一種最佳化,其中 Amazon DocumentDB 完全從儲存在索引中的欄位回答查詢,而無需讀取基礎文件。由於查詢所需的值已存在於索引中,Amazon DocumentDB 可以略過擷取每個相符的文件,避免讀取完整文件的隨機 I/O 和解碼成本。在查詢計畫中,僅索引掃描會顯示為IXONLYSCAN階段,而不是 IXSCAN(索引掃描) 或 COLLSCAN(集合掃描)。這可減少 I/O,並可大幅降低支援查詢的查詢延遲。
當查詢只接觸單一索引中存在的一小部分欄位時,特別是當文件本身很大時,查詢是純索引掃描的理想候選項目。常見的範例是儀表板、分析彙總和查詢,從更廣泛的複合索引讀取幾個欄位。
無論是否使用僅索引掃描,查詢的結果都相同。只有查詢計畫及其執行的 I/O 數量會變更。
注意
僅索引掃描支援取決於您的 Amazon DocumentDB 引擎版本:
-
包含多個非
_id欄位的涵蓋find投影需要引擎版本 8.0.2 或更新版本。在舊版中,涵蓋的find投影最多可包含一個非_id欄位。具有兩個或多個欄位的投影會回到正常索引掃描或集合掃描。 -
純索引掃描是否有彙總管道,例如涵蓋的
$group,需要引擎版本 8.0.2 或更新版本。
當 Amazon DocumentDB 使用僅限索引掃描時
當單一索引包含操作讀取的每個欄位時,Amazon DocumentDB 會考慮下列操作的僅索引掃描。
涵蓋的find投影
當find查詢的投影簡單地包含一或多個頂層欄位,且每個投影欄位都存在於單一索引中時,查詢即符合資格。例如,假設 上有複合索引{ customerId: 1, status: 1, total: 1 },則會涵蓋下列查詢。所有三個投影欄位都存在於索引中,_id並明確排除。(使用多個非_id 欄位覆蓋投影需要引擎版本 8.0.2 或更新版本。)
db.orders.createIndex({ customerId: 1, status: 1, total: 1 }) db.orders.find( { customerId: 42 }, { _id: 0, customerId: 1, status: 1, total: 1 } )
獲勝計劃使用 IXONLYSCAN階段,絕不會從儲存體擷取相符的文件:
{ "stage": "IXONLYSCAN", "indexName": "customerId_1_status_1_total_1", "direction": "forward", "indexCond": { "$and": [ { "customerId": { "$eq": 42 } } ] } }
注意
在涵蓋的find查詢中,結果中的欄位會以索引順序傳回 (欄位在索引定義中出現的順序),而不是在投影中列出的順序或存放在文件中的順序。這符合涵蓋查詢的 MongoDB 行為。由集合掃描回答的查詢會改為以預存文件順序傳回欄位。
涵蓋的$group彙總
$group 階段通常只會讀取幾個欄位 (群組索引鍵及其累積器的輸入),但通常會在沒有前置 的情況下執行$match。如果沒有涵蓋索引,Amazon DocumentDB 會讀取和解碼集合中的每個完整文件,只將這幾個欄位饋送至分組。
引擎版本 8.0.2 和更新版本中提供了彙總管道的索引限定掃描,包括涵蓋的$group階段。
當單一索引包含管道字首讀取的每個欄位時,Amazon DocumentDB 可以將僅索引掃描放在群組下方,並直接從索引讀取這些欄位。考慮將訂單依狀態分組的管道,並加總其總計,並在 上有複合索引{ status: 1, total: 1 }:
db.orders.createIndex({ status: 1, total: 1 }) db.orders.aggregate([ { $group: { _id: "$status", revenue: { $sum: "$total" } } } ])
管道只會讀取 status和 total,兩者都位於索引中,因此會從 饋送群組,IXONLYSCAN而不是集合掃描:
// Without a covering index $group <- COLLSCAN (reads and decodes every full document) // With a covering index on { status, total } $group <- IXONLYSCAN over { status, total } (reads only the referenced fields)
在$group支援 $limit之前領導 $skip、、 $match $sort或 。不過,這些階段參考的每個欄位 (例如$match篩選欄位或$sort索引鍵) 也必須存在於相同的索引中,才能涵蓋管道。如果索引中缺少任何參考欄位,Amazon DocumentDB 會回到集合或索引掃描。
注意
與find投影不同, $group不會隱含包含文件 _id。_id 中的 $group是群組索引鍵,而不是文件識別符,因此索引不需要包含文件_id來涵蓋管道。
涵蓋查詢的需求
若要讓 Amazon DocumentDB 使用僅限索引掃描,必須保留下列所有項目:
-
單一索引包含查詢讀取的每個欄位。這包括 的投影欄位
find,以及群組索引鍵、累積器輸入,以及涵蓋$group管道的任何篩選條件或排序欄位。如果索引中遺失一個欄位,則無法涵蓋查詢。 -
投影包含最上層欄位 (適用於
find)。排除投影、運算欄位和投影運算子,例如$slice和$elemMatch不符合資格。 -
_id欄位會計入 (適用於find)。因為 預設_id包含 ,所以常見的複合索引{ a: 1, b: 1 }不包含find({}, { a: 1, b: 1 }):隱含_id不在索引中。從投影中排除_id({ _id: 0, a: 1, b: 1 }) 或_id新增至索引。 -
索引完全滿足篩選條件。如果 Amazon DocumentDB 無法將部分查詢述詞轉換為索引繫結,則會將該部分保留為剩餘篩選條件、讀取文件以評估它,而且不會將掃描轉換為僅索引掃描。
$mod、$ne、$nin和 等運算子會$exists保留剩餘的篩選條件。 -
沒有投影欄位是多重索引鍵 (陣列) 資料欄。請參閱 限制。
限制
下列案例無法使用僅索引掃描,並回到正常的索引掃描或集合掃描。這是預期的行為,絕不會影響結果的正確性。
-
多重索引鍵 (陣列) 欄位。如果欄位曾在任何文件中保留陣列值,則其索引欄為多索引鍵。多索引鍵索引會為每個陣列元素存放一個項目,因此無法從索引重建原始陣列。不會涵蓋讀取此類欄位的任何查詢。
-
虛線或巢狀路徑。巢狀路徑 上的投影或欄位參考
"address.city"不符合資格,即使索引包含該路徑。 -
排除、計算或運算子投影。
{ b: 0 }、{ total: { $add: ["$price", "$tax"] } }或 等投影{ a: { $slice: 5 } }需要完整文件,且不涵蓋在內。 -
彙總中的完整文件參考。
$group參考整個文件 (例如{ $push: "$$ROOT" }) 的 無法涵蓋,因為沒有任何索引可以重建整個文件。 -
在 之前重塑階段
$group。重塑文件 (例如$project、$unwind、$addFields或$lookup) 的階段,在管道$group不符合涵蓋資格之前出現。 -
字串述詞上的定序不相符。如果查詢的定序與索引的定序不同,則索引無法提供字串述詞,並留下剩餘篩選條件,強制文件擷取。數值和類型型述詞不受影響。
確認僅限索引掃描
使用explain("executionStats")輸出來確認查詢是由僅索引掃描提供,且不會接觸文件。尋找兩件事:
-
獲勝計劃使用
IXONLYSCAN階段。 -
該階段
docsExamined的值為0(且totalDocsExamined為0),這表示查詢完全從索引中回答,而不讀取任何文件。
db.orders.find( { customerId: 42 }, { _id: 0, customerId: 1, status: 1, total: 1 } ).explain("executionStats").executionStats
{ "executionSuccess": true, "nReturned": "2", "executionTimeMillis": "0.714", "totalDocsExamined": "0", "executionStages": { "stage": "IXONLYSCAN", "nReturned": "2", "indexName": "customerId_1_status_1_total_1", "direction": "forward", "docsExamined": "0" } }
注意
IXONLYSCAN 階段上的非零docsExamined值表示索引包含資料,但 Amazon DocumentDB 仍會檢查儲存體,以確認每個文件版本都可見。當集合最近有已淘汰的文件版本垃圾回收尚未回收的寫入時,可能會發生這種情況。垃圾回收處理這些文件後, 會docsExamined捨棄至 0。此時,查詢會實現涵蓋掃描的完整優點。如需垃圾回收的詳細資訊,請參閱 Amazon DocumentDB 中的垃圾回收。如需關於 docsExamined 指標的詳細資訊,請參閱查詢計畫分析。
最佳實務
-
設計複合索引,其中包含您最常查詢專案或群組的欄位,因此可以涵蓋這些查詢。
-
_id從find投影中排除 ({ _id: 0, ... }),除非_id是覆蓋索引的一部分。 -
當您想要涵蓋查詢時,請避免索引陣列 (多索引鍵) 欄位,因為多索引鍵資料欄不符合僅索引路徑的資格。
-
允許垃圾收集與您的寫入工作負載保持同步,讓涵蓋的掃描略過文件存取並
docsExamined保持在0。如需詳細資訊,請參閱Amazon DocumentDB 中的垃圾回收。