1. 程式人生 > 實用技巧 >mongo新增索引及索引相關方法

mongo新增索引及索引相關方法

目錄

  1. 索引的型別和屬性

    1. 單鍵索引
      • 普通單鍵索引
      • 索引子文件欄位
      • 唯一索引
    2. 複合索引
    3. 多鍵值索引
    4. 過期索引
    5. 雜湊索引
    6. 地理位置索引
    7. 文字索引
  2. 索引操作方法

    • 檢視現有索引
    • 列出資料庫的所有索引
    • 刪除索引
    • 重建索引
    • 建立索引的引數
  3. 索引規則

    • 查詢優化器

    • 何時查詢計劃快取才會變呢

    • 聯合索引的優化

    • 聚合管道的優化

    • 最期望看到的查詢組合

    • 最不期望看到的查詢組合

    • 最左字首原則

    • 效率極低的操作符

  4. explain

    • 介紹
    • queryPlanner返回結果的意義
    • executionStats返回結構的意義
    • stage的型別的意義
  5. 運維命令

一.索引的型別和屬性

1.單鍵索引

①普通單鍵索引

MongoDB 支援文件集合中任何欄位的索引,在預設情況下,所有集合在 _id 欄位上都有一個索引,應用程式和使用者可以新增額外的索引來支援重要的查詢操作

對於單欄位索引和排序操作,索引鍵的排序順序(即升序或降序)無關緊要,因為 MongoDB 可以在任意方向上遍歷索引。

建立單鍵索引的語法結構如下:

# 1 為升序,-1 為降序
db.collection.createlndex ( { key: 1 } )

以下示例為插入一個文件,並在 score 鍵上建立索引,具體步驟如下:

db.records.insert(
    {
        "score" : 1034,
        "location" : { state: "NY", city: "New York"}
    }
)
db.records.createTndex( { score: 1 } )

使用 score 欄位進行查詢,再使用 explain() 函式,可以檢視查詢過程:

db.records.find({score:1034}).explain()

②索引子文件欄位(或者"內嵌索引")

{
   "address": {
      "city": "Los Angeles",
      "state": "California",
      "pincode": "123"
   },
   "tags": [
      "music",
      "cricket",
      "blogs"
   ],
   "name": "Tom Benzamin"
}

假設我們需要通過city、state、pincode欄位來檢索文件,由於這些欄位是子文件的欄位,所以我們需要對子文件建立索引。

為子文件的city欄位建立索引,命令如下:

db.users.ensureIndex({"address.city":1})

對巢狀文件本身“address”建立索引,與對巢狀文件的某個欄位(address.city)建立索引是完全不相同的。
對整個文件建立索引,只有在使用文件完整匹配時才會使用到這個索引,例如建立了這樣一個索引db.personInfos.createIndex({“address”:1}),那麼只有使用db.personInfos.find({“address”:{“pincode”:”xxx”,”city”:”xxx”,""state":"xxx"}})這種完整匹配時才會使用到這個索引,使用db.personInfos.find({“address.city”:”xxx”})是不會使用到該索引的。

③唯一索引

唯一索引是索引具有的一種屬性,讓索引具備唯一性,確保這張表中,該條索引資料不會重複出現。在每一次insert和update操作時,都會進行索引的唯一性校驗,保證該索引的欄位組合在表中唯一。

db.containers.createIndex({name: 1},{unique:true, background: true})
db.packages.createIndex({ appId: 1, version: 1 },{unique:true, background: true})

Mongo提供兩種建索引的方式foreground和background。
前臺操作,它會阻塞使用者對資料的讀寫操作直到index構建完畢;
後臺模式,不阻塞資料讀寫操作,獨立的後臺執行緒非同步構建索引,此時仍然允許對資料的讀寫操作。
建立索引時一定要寫{background: true}
建立索引時一定要寫{background: true}
建立索引時一定要寫{background: true}

MongoDB中是隻有庫級鎖的,建立索引時要新增引數{background: true}。

2.複合索引

MongoDB 支援複合索引,其中複合索引結構包含多個欄位

複合索引可以支援在多個欄位上進行的匹配查詢,語法結構如下:

db.collection.createIndex ({ <key1> : <type>, <key2> : <type2>, ...})

需要注意的是,在建立複合索引的時候一定要注意順序的問題,順序不同將導致查詢的結果也不相同。

如下語句建立複合索引:

db.records.createIndex ({ "score": 1, "location.state": 1 })

檢視複合索引的查詢計劃的語法如下:

db.records.find({score:1034, "location.state" : "NY"}).explain()

3.多鍵值索引(或者"陣列索引")

若要為包含陣列的欄位建立索引,MongoDB 會為陣列中的每個元素建立索引鍵。這些多鍵值索引支援對陣列欄位的高效查詢

建多鍵值索引的語法如下:

db.collecttion.createlndex( { <key>: < 1 or -1 > })

需要注意的是,如果集合中包含多個待索引欄位是陣列,則無法建立複合多鍵索引。

以下示例程式碼展示插入文件,並建立多鍵值索引:

db.survey.insert ({item : "ABC", ratings: [ 2, 5, 9 ]})
db.survey.createIndex({ratings:1})
db.survey.find({ratings:2}).explain()

對陣列建立索引的代價是非常高的,他實際上是會對陣列中的每一項都單獨建立索引,就相當於假設陣列中有十項,那麼就會在原基礎上,多出十倍的索引大小。如果有一百個一千個呢?
所以在mongo中是禁止對兩個陣列新增複合索引的,對兩個陣列新增索引那麼索引大小將是爆炸增長,所以謹記在心。

4.過期索引(TTL)

可以針對某個時間欄位,指定文件的過期時間(經過指定時間後過期 或 在某個時間點過期)

5.雜湊索引(Hashed Index)

是指按照某個欄位的hash值來建立索引,hash索引只能滿足欄位完全匹配的查詢,不能滿足範圍查詢等

6.地理位置索引(Geospatial Index)

能很好的解決一些場景,比如『查詢附近的美食』、『查詢附近的加油站』等

7.文字索引(Text Index)

能解決快速文字查詢的需求,比如,日誌平臺,相對日誌關鍵詞查詢,如果通過正則來查詢的話效率極低,這時就可以通過文字索引的形式來進行查詢

二.索引操作方法

1.檢視現有索引

若要返回集合上所有索引的列表,則需使用驅動程式的 db.collection.getlndexes() 方法或類似方法。

例如,可使用如下方法檢視 records 集合上的所有索引:

db.records.getIndexes()

2.列出資料庫的所有索引

若要列出資料庫中所有集合的所有索引,則需在 MongoDB 的 Shell 客戶端中進行以下操作:

db.getCollectionNames().forEach(function(collection){
    indexes = db[collection].getIndexes();
    print("Indexes for " + collection + ":" );
    printjson(indexes);
});

3.刪除索引

MongoDB 提供的兩種從集合中刪除索引的方法如下:

# 刪除單個索引
db.collection.dropIndex("")
# 刪除集合的全部索引
db.collection.dropIndexes()

若要刪除特定索引,則可使用該 db.collection.droplndex() 方法。

例如,以下操作將刪除集合中 score 欄位的升序索引:

db.records.dropIndex ({ "score" : 1 })  //升序降序不能錯,如果為-1,則提示無索引

還可以使用 db.collection.droplndexes() 刪除除 _id 索引之外的所有索引。

例如,以下命令將從 records 集合中刪除所有索引:

db.records.dropIndexes()

4.重建索引

db.myCollection.reIndex()  

db.runCommand( { reIndex : 'myCollection' } ) 

通常這是不必要的,但是在集合的大小變動很大及集合在磁碟空間上佔用很多空間時重建索引才有用。對於大資料量的集合來說,重建索引可能會很慢。

MongoDB中索引是大小寫敏感的。

5.建立索引的引數

引數 型別 描述
background Boolean 建索引過程會阻塞其它資料庫操作,background可指定以後臺方式建立索引,即增加 "background" 可選引數。 "background" 預設值為false
unique Boolean 建立的索引是否唯一。指定為true建立唯一索引。預設值為false.
name string 索引的名稱。如果未指定,MongoDB的通過連線索引的欄位名和排序順序生成一個索引名稱。
dropDups Boolean 3.0+版本已廢棄。在建立唯一索引時是否刪除重複記錄,指定 true 建立唯一索引。預設值為 false.
sparse Boolean 對文件中不存在的欄位資料不啟用索引;這個引數需要特別注意,如果設定為true的話,在索引欄位中不會查詢出不包含對應欄位的文件.。預設值為 false.
expireAfterSeconds integer 指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間。
v index version 索引的版本號。預設的索引版本取決於mongod建立索引時執行的版本。
weights document 索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其他索引欄位的得分權重。
default_language string 對於文字索引,該引數決定了停用詞及詞幹和詞器的規則的列表。 預設為英語
language_override string 對於文字索引,該引數指定了包含在文件中的欄位名,語言覆蓋預設的language,預設值為 language.

三.索引規則

1.查詢優化器

Mongo自帶了一個查詢優化器會為我們選擇最合適的查詢方案。

如果一個索引能夠精確匹配一個查詢,那麼查詢優化器就會使用這個索引。

如果不能精確匹配呢?可能會有幾個索引都適合你的查詢,那MongoDB是怎樣選擇的呢?

  • MongoDB的查詢計劃會將多個索引並行的去執行,最先返回第101個結果的就是勝者,其他查詢計劃都會被終止,執行優勝的查詢計劃;
  • 這個查詢計劃會被快取,接下來相同的查詢條件都會使用它;

2.何時查詢計劃快取才會變呢?

  1. 在計劃評估之後表發生了比較大的資料波動,查詢優化器就會重新挑選可行的查詢計劃
  2. 建立索引時
  3. 每執行1000次查詢之後,查詢優化器就會重新評估查詢計劃

3.聯合索引的優化

當你查詢條件的順序和你索引的順序不一致的話,mongo會自動的調整查詢順序,保證你可以使用上索引。

例如:你的查詢條件是(a,c,b)但是你的索引是(a,b,c)mongo會自動將你的查詢條件調整為abc,尋找最優解。

4.聚合管道的優化

  1. 如果管道中不需要使用一個完整的文件的全部欄位的話,管道不會將多餘欄位進行傳遞
  2. $sort 和 $limit 合併,在記憶體中只會維護limit個數量的文件,不需要將所有的文件維護在記憶體中,大大降低記憶體中sort的壓力

然而管道中的索引使用情況是極其不佳的,在管道中,只有在管道最開始時的match sort可以使用到索引,一旦發生過project投射,group分組,lookup表關聯,unwind打散等操作後,就完全無法使用索引。

5.最期望看到的查詢組合

  • Fetch+IDHACK
  • Fetch+ixscan
  • Limit+(Fetch+ixscan)
  • PROJECTION+ixscan

6. 最不期望看到的查詢組合

  • COLLSCAN(全表掃)
  • SORT(使用sort但是無index)
  • COUNTSCAN****(不使用索引進行count)

7. 最左字首原則

假定索引(a,b,c) 它可能滿足的查詢如下:

1. a

2. a,b

3. a,b,c

4. a,c [該組合只能用a部分]

5. a, c, b [cb在查詢時會被優化換位置]

顯然,最左字首的核心是查詢條件欄位必須含有索引第一個欄位

最左值儘可能用最精確過濾性最好的值,不要用那種可能會用於範圍模糊查詢,用於排序的欄位

8. 效率極低的操作符

  1. \(where和\)exists:這兩個操作符,完全不能使用索引。
  2. \(ne和\)not:通常來說取反和不等於,可以使用索引,但是效率極低,不是很有效,往往也會退化成掃描全表。
  3. $nin:不包含,這個操作符也總是會全表掃描
  4. 對於管道中的索引,也很容易出現意外,只有在管道最開始時的match sort可以使用到索引,一旦發生過project投射,group分組,lookup表關聯,unwind打散等操作後,就完全無法使用索引。

四.explain

執行explain

db.union_recipe.find({"name" : /.*雞.*/i,"foodTags.text":"魯菜"}).explain("executionStats")

查詢出來的計劃

{
    "queryPlanner": {
        "plannerVersion": NumberInt("1"),
        "namespace": "iof_prod_recipe.union_recipe",
        "indexFilterSet": false,
        "parsedQuery": {
            "$and": [
                {
                    "foodTags.text": {
                        "$eq": "魯菜"
                    }
                },
                {
                    "name": {
                        "$regex": ".*雞.*",
                        "$options": "i"
                    }
                }
            ]
        },
        "winningPlan": {
            # 根據內層階段樹查到的索引去抓取完整的文件
            "stage": "FETCH",
            "filter": {
                "name": {
                    "$regex": ".*雞.*",
                    "$options": "i"
                }
            },
            # 每個階段將自己的查詢結果傳遞給父階段樹,所以從裡往外讀Explain
            "inputStage": {
                # IXSCAN該階段使用了索引進行掃描
                "stage": "IXSCAN",
                # 使用了 foodTags.text: -1 這條索引
                "keyPattern": {
                    "foodTags.text": -1
                },
                "indexName": "foodTags.text_-1",
                "isMultiKey": true,
                "multiKeyPaths": {
                    "foodTags.text": [
                        "foodTags"
                    ]
                },
                "isUnique": false,
                "isSparse": false,
                "isPartial": false,
                "indexVersion": NumberInt("2"),
                "direction": "forward",
                "indexBounds": {
                    "foodTags.text": [
                        "[\"魯菜\", \"魯菜\"]"
                    ]
                }
            }
        },
        "rejectedPlans": [
            {
                "stage": "FETCH",
                "filter": {
                    "foodTags.text": {
                        "$eq": "魯菜"
                    }
                },
                "inputStage": {
                    "stage": "IXSCAN",
                    "filter": {
                        "name": {
                            "$regex": ".*雞.*",
                            "$options": "i"
                        }
                    },
                    "keyPattern": {
                        "name": 1
                    },
                    "indexName": "name_1",
                    "isMultiKey": false,
                    "multiKeyPaths": {
                        "name": [ ]
                    },
                    "isUnique": false,
                    "isSparse": false,
                    "isPartial": false,
                    "indexVersion": NumberInt("2"),
                    "direction": "forward",
                    "indexBounds": {
                        "name": [
                            "[\"\", {})",
                            "[/.*雞.*/i, /.*雞.*/i]"
                        ]
                    }
                }
            }
        ]
    },
    "executionStats": {
        "executionSuccess": true,
        "nReturned": NumberInt("49"),
        "executionTimeMillis": NumberInt("2"),
        "totalKeysExamined": NumberInt("300"),
        "totalDocsExamined": NumberInt("300"),
        "executionStages": {
            "stage": "FETCH",
            "filter": {
                "name": {
                    "$regex": ".*雞.*",
                    "$options": "i"
                }
            },
            "nReturned": NumberInt("49"),
            "executionTimeMillisEstimate": NumberInt("0"),
            "works": NumberInt("302"),
            "advanced": NumberInt("49"),
            "needTime": NumberInt("251"),
            "needYield": NumberInt("0"),
            "saveState": NumberInt("5"),
            "restoreState": NumberInt("5"),
            "isEOF": NumberInt("1"),
            "invalidates": NumberInt("0"),
            "docsExamined": NumberInt("300"),
            "alreadyHasObj": NumberInt("0"),
            "inputStage": {
                "stage": "IXSCAN",
                "nReturned": NumberInt("300"),
                "executionTimeMillisEstimate": NumberInt("0"),
                "works": NumberInt("301"),
                "advanced": NumberInt("300"),
                "needTime": NumberInt("0"),
                "needYield": NumberInt("0"),
                "saveState": NumberInt("5"),
                "restoreState": NumberInt("5"),
                "isEOF": NumberInt("1"),
                "invalidates": NumberInt("0"),
                "keyPattern": {
                    "foodTags.text": -1
                },
                "indexName": "foodTags.text_-1",
                "isMultiKey": true,
                "multiKeyPaths": {
                    "foodTags.text": [
                        "foodTags"
                    ]
                },
                "isUnique": false,
                "isSparse": false,
                "isPartial": false,
                "indexVersion": NumberInt("2"),
                "direction": "forward",
                "indexBounds": {
                    "foodTags.text": [
                        "[\"魯菜\", \"魯菜\"]"
                    ]
                },
                "keysExamined": NumberInt("300"),
                "seeks": NumberInt("1"),
                "dupsTested": NumberInt("300"),
                "dupsDropped": NumberInt("0"),
                "seenInvalidated": NumberInt("0")
            }
        }
    },
    "ok": 1,
    "operationTime": Timestamp(1598602456, 1),
    "$clusterTime": {
        "clusterTime": Timestamp(1598602456, 1),
        "signature": {
            "hash": BinData(0, "/t+ZhDHuT6EtZMFyqmesvq9Rlfk="),
            "keyId": NumberLong("6838110804550615041")
        }
    }
}

1.介紹

queryPlanner:查詢計劃的選擇器,首先進行查詢分析,最終選擇一個winningPlan,是explain返回的預設層面。

executionStats:為執行統計層面,返回winningPlan的統計結果

allPlansExecution:為返回所有執行計劃的統計,包括rejectedPlan

所以:我們在查詢優化的時候,只需要關注queryPlanner, executionStats即可,因為queryPlanner為我們選擇出了winningPlan, 而executionStats為我們統計了winningPlan的所有關鍵資料。

2.queryPlanner返回結果的意義

explain.queryPlanner: queryPlanner的返回

explain.queryPlanner.namespace:該值返回的是該query所查詢的表

explain.queryPlanner.indexFilterSet:針對該query是否有indexfilter

explain.queryPlanner.winningPlan:查詢優化器針對該query所返回的最優執行計劃的詳細內容。

explain.queryPlanner.winningPlan.stage:最優執行計劃的stage,這裡返回是FETCH,可以理解為通過返回的index位置去檢索具體的文件(stage有數個模式,將在後文中進行詳解)。

Explain.queryPlanner.winningPlan.inputStage:用來描述子stage,並且為其父stage提供文件和索引關鍵字。

explain.queryPlanner.winningPlan.stage的child stage,此處是IXSCAN,表示進行的是index scanning。

explain.queryPlanner.winningPlan.keyPattern:所掃描的index內容,此處是did:1,status:1,modify_time: -1與scid : 1

explain.queryPlanner.winningPlan.indexName:winning plan所選用的index。

explain.queryPlanner.winningPlan.isMultiKey是否是Multikey,此處返回是false,如果索引建立在array上,此處將是true。

explain.queryPlanner.winningPlan.direction:此query的查詢順序,此處是forward,如果用了.sort({modify_time:-1})將顯示backward。

explain.queryPlanner.winningPlan.indexBounds:winningplan所掃描的索引範圍,如果沒有制定範圍就是[MaxKey, MinKey],這主要是直接定位到mongodb的chunck中去查詢資料,加快資料讀取。

explain.queryPlanner.rejectedPlans:其他執行計劃(非最優而被查詢優化器reject的)的詳細返回,其中具體資訊與winningPlan的返回中意義相同,故不在此贅述。

3.executionStats返回結構的意義

executionStats.executionSuccess:是否執行成功

executionStats.nReturned:滿足查詢條件的文件個數,即查詢的返回條數

executionStats.executionTimeMillis:整體執行時間

executionStats.totalKeysExamined:索引整體掃描的文件個數,和早起版本的nscanned 是一樣的

executionStats.totalDocsExamined:document掃描個數, 和早期版本中的nscannedObjects 是一樣的

executionStats.executionStages:整個winningPlan執行樹的詳細資訊,一個executionStages包含一個或者多個inputStages

executionStats.executionStages.stage:這裡是FETCH去掃描對於documents,後面會專門用來解釋大部分查詢使用到的各種stage的意思

executionStats.executionStages.nReturned:由於是FETCH,所以這裡該值與executionStats.nReturned一致

executionStats.executionStages.docsExamined:與executionStats.totalDocsExamined一致executionStats.inputStage中的與上述理解方式相同

explain.executionStats.executionStages.works:被查詢執行階段所操作的“工作單元(work units)”數。

explain.executionStats.executionStages.advanced:優先返回給父stage的中間結果集中文件個數

explain.executionStats.executionStages.isEOF:查詢執行是否已經到了資料流的末尾

這些值的初始值都是0。Works的 值當isEOF為1時要比nReturned大1, isEOF為0是相同。

explain 結果將查詢計劃以階段樹的形式呈現。
每個階段將其結果(文件或索引鍵)傳遞給父節點。
中間節點操縱由子節點產生的文件或索引鍵。
根節點是MongoDB從中派生結果集的最後階段。

4.stage的型別的意義

COLLSCAN :全表掃描

IXSCAN:索引掃描

FETCH::根據索引去檢索指定document

SHARD_MERGE:各個分片返回資料進行merge

SORT:表明在記憶體中進行了排序(與前期版本的scanAndOrder:true一致)

SORT_MERGE:表明在記憶體中進行了排序後再合併

LIMIT:使用limit限制返回數

SKIP:使用skip進行跳過

IDHACK:針對_id進行查詢

SHARDING_FILTER:通過mongos對分片資料進行查詢

COUNT:利用db.coll.count()之類進行count運算

COUNTSCAN:count不使用用Index進行count時的stage返回

COUNT_SCAN:count使用了Index進行count時的stage返回

SUBPLA:未使用到索引的$or查詢的stage返回

TEXT:使用全文索引進行查詢時候的stage返回

五.常用操作

1.分析MongoDB資料庫正在執行的請求

db.currentOp()

{
  "desc" : "conn632530",
  "threadId" : "140298196924160",
  "connectionId" : 632530,
  "client" : "11.192.159.236:57052",
  "active" : true,
  "opid" : 1008837885,
  "secs_running" : 0,
  "microsecs_running" : NumberLong(70),
  "op" : "update",
  "ns" : "mygame.players",
  "query" : {
    "uid" : NumberLong(31577677)
    },
  "numYields" : 0,
    "locks" : {
    "Global" : "w",
    "Database" : "w",
    "Collection" : "w"
    },
  ....
},
欄位 返回值說明
client 該請求是由哪個客戶端發起的。
opid 操作的唯一識別符號。說明 如果有需要,可以通過db.killOp(opid)直接終止該操作。
secs_running 表示該操作已經執行的時間,單位為秒。如果該欄位返回的值特別大,需要檢視請求是否合理。
microsecs_running 表示該操作已經執行的時間,單位為微秒。如果該欄位返回的值特別大,需要檢視請求是否合理。
ns 該操作目標集合。
op 表示操作的型別。通常是查詢、插入、更新、刪除中的一種。
locks 跟鎖相關的資訊,詳情請參見併發介紹,本文不做詳細介紹。

如果發現有異常的請求,您可以找到該請求對應的opid,執行db.killOp(opid)終止該請求。

2.檢視該資料下的慢請求日誌

db.system.profile.find().pretty();

分析慢請求日誌,查詢引起MongoDB CPU使用率升高的原因。檢視到該請求進行了全表掃描

{
        "op" : "query",
        "ns" : "123.testCollection",
        "command" : {
                "find" : "testCollection",
                "filter" : {
                        "name" : "zhangsan"
                },
                "$db" : "123"
        },
        "keysExamined" : 0,
        "docsExamined" : 11000000,
        "cursorExhausted" : true,
        "numYield" : 85977,
        "nreturned" : 0,
        "locks" : {
                "Global" : {
                        "acquireCount" : {
                                "r" : NumberLong(85978)
                        }
                },
                "Database" : {
                        "acquireCount" : {
                                "r" : NumberLong(85978)
                        }
                },
                "Collection" : {
                        "acquireCount" : {
                                "r" : NumberLong(85978)
                        }
                }
        },
        "responseLength" : 232,
        "protocol" : "op_command",
        "millis" : 19428,
        "planSummary" : "COLLSCAN",
        "execStats" : {
                "stage" : "COLLSCAN",
                "filter" : {
                        "name" : {
                                "$eq" : "zhangsan"
                        }
                },
                "nReturned" : 0,
                "executionTimeMillisEstimate" : 18233,
                "works" : 11000002,
                "advanced" : 0,
                "needTime" : 11000001,
                "needYield" : 0,
                "saveState" : 85977,
                "restoreState" : 85977,
                "isEOF" : 1,
                "invalidates" : 0,
                "direction" : "forward",
....in"
                }
        ],
        "user" : "root@admin"
}

通常在慢請求日誌中,您需要重點關注以下幾點。

  • 全表掃描(關鍵字: COLLSCAN、 docsExamined )
    全集合(表)掃描COLLSCAN 。
    當一個操作請求(如查詢、更新、刪除等)需要全表掃描時,將非常佔用CPU資源。在檢視慢請求日誌時發現COLLSCAN關鍵字,很可能是這些查詢佔用了CPU資源。

    說明:

    如果這種請求比較頻繁,建議對查詢的欄位建立索引的方式來優化。
    通過檢視docsExamined的值,可以檢視到一個查詢掃描了多少文件。該值越大,請求所佔用的CPU開銷越大。

  • 不合理的索引(關鍵字: IXSCAN、keysExamined )

    說明:

    索引不是越多越好,索引過多會影響寫入、更新的效能。

    如果您的應用偏向於寫操作,索引可能會影響效能。

    通過檢視keysExamined欄位,可以檢視到 一個使用了索引的查詢,掃描了多少條索引。該值越大,CPU開銷越大。

    如果索引建立的不太合理,或者是匹配的結果很多。這樣即使使用索引,請求開銷也不會優化很多,執行的速度也會很慢。

  • 大量資料排序(關鍵字: SORT、hasSortStage )

    當查詢請求裡包含排序的時候, system.profile 集合裡的hasSortStage欄位會為 true 。

    如果排序無法通 過索引滿足,MongoDB會在查詢結果中進行排序。

    而排序這個動作將非常消耗CPU資源,這種情況需要對經常排序的欄位建立索引的方式進行優化。

    說明 當您在system.profile集合裡發現SORT關鍵字時,可以考慮通過索引來優化排序。

  • 其他還有諸如建立索引、aggregation(遍歷、查詢、更新、排序等動作的組合) 等操作也可能非常耗CPU資源,但本質上也是上述幾種場景。

站在巨人肩膀上摘蘋果

http://c.biancheng.net/view/6558.html

https://docs.mongodb.org/v3.0/reference/explain-results/

https://zhuanlan.zhihu.com/p/77971681

https://www.jianshu.com/p/2b09821a365d

https://www.imooc.com/article/285899

https://blog.csdn.net/weixin_33446857/article/details/83085018

https://www.runoob.com/mongodb/mongodb-advanced-indexing.html

https://www.runoob.com/mongodb/mongodb-indexing.html