校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 深入理解MongoDB的復合索引

深入理解MongoDB的復合索引

熱門標簽:怎么投訴地圖標注 廣州長安公司怎樣申請400電話 蘋果汽車租賃店地圖標注 杭州人工電銷機器人價格 濟南電銷機器人加盟公司 電銷機器人是什么軟件 老虎洗衣店地圖標注 云南外呼系統 呼和浩特電銷外呼系統加盟

為什么需要索引?

當你抱怨MongoDB集合查詢效率低的時候,可能你就需要考慮使用索引了,為了方便后續介紹,先科普下MongoDB里的索引機制(同樣適用于其他的數據庫比如mysql)。

mongo-9552:PRIMARYgt; db.person.find()
{ "_id" : ObjectId("571b5da31b0d530a03b3ce82"), "name" : "jack", "age" : 19 }
{ "_id" : ObjectId("571b5dae1b0d530a03b3ce83"), "name" : "rose", "age" : 20 }
{ "_id" : ObjectId("571b5db81b0d530a03b3ce84"), "name" : "jack", "age" : 18 }
{ "_id" : ObjectId("571b5dc21b0d530a03b3ce85"), "name" : "tony", "age" : 21 }
{ "_id" : ObjectId("571b5dc21b0d530a03b3ce86"), "name" : "adam", "age" : 18 }

當你往某各個集合插入多個文檔后,每個文檔在經過底層的存儲引擎持久化后,會有一個位置信息,通過這個位置信息,就能從存儲引擎里讀出該文檔。比如mmapv1引擎里,位置信息是『文件id + 文件內offset 』, 在wiredtiger存儲引擎(一個KV存儲引擎)里,位置信息是wiredtiger在存儲文檔時生成的一個key,通過這個key能訪問到對應的文檔;為方便介紹,統一用pos(position的縮寫)來代表位置信息。

什么是復合索引?

復合索引,即Compound Index,指的是將多個鍵組合到一起創建索引,這樣可以加速匹配多個鍵的查詢。不妨通過一個簡單的示例理解復合索引。

students集合如下:

db.students.find().pretty()
{
 "_id" : ObjectId("5aa7390ca5be7272a99b042a"),
 "name" : "zhang",
 "age" : "15"
}
{
 "_id" : ObjectId("5aa7393ba5be7272a99b042b"),
 "name" : "wang",
 "age" : "15"
}
{
 "_id" : ObjectId("5aa7393ba5be7272a99b042c"),
 "name" : "zhang",
 "age" : "14"
}

在name和age兩個鍵分別創建了索引(_id自帶索引):

db.students.getIndexes()
[
 {
 "v" : 1,
 "key" : {
 "name" : 1
 },
 "name" : "name_1",
 "ns" : "test.students"
 },
 {
 "v" : 1,
 "key" : {
 "age" : 1
 },
 "name" : "age_1",
 "ns" : "test.students"
 }
]

當進行多鍵查詢時,可以通過explian()分析執行情況(結果僅保留winningPlan):

db.students.find({name:"zhang",age:"14"}).explain()
"winningPlan":
{
 "stage": "FETCH",
 "filter":
 {
  "name":
  {
   "$eq": "zhang"
  }
 },
 "inputStage":
 {
  "stage": "IXSCAN",
  "keyPattern":
  {
   "age": 1
  },
  "indexName": "age_1",
  "isMultiKey": false,
  "isUnique": false,
  "isSparse": false,
  "isPartial": false,
  "indexVersion": 1,
  "direction": "forward",
  "indexBounds":
  {
   "age": [
    "[\"14\", \"14\"]"
   ]
  }
 }
}

由winningPlan可知,這個查詢依次分為IXSCAN和FETCH兩個階段。IXSCAN即索引掃描,使用的是age索引;FETCH即根據索引去查詢文檔,查詢的時候需要使用name進行過濾。

為name和age創建復合索引:

db.students.createIndex({name:1,age:1})
db.students.getIndexes()
[
 {
 "v" : 1,
 "key" : {
 "name" : 1,
 "age" : 1
 },
 "name" : "name_1_age_1",
 "ns" : "test.students"
 }
]

有了復合索引之后,同一個查詢的執行方式就不同了:

db.students.find({name:"zhang",age:"14"}).explain()
"winningPlan":
{
 "stage": "FETCH",
 "inputStage":
 {
  "stage": "IXSCAN",
  "keyPattern":
  {
   "name": 1,
   "age": 1
  },
  "indexName": "name_1_age_1",
  "isMultiKey": false,
  "isUnique": false,
  "isSparse": false,
  "isPartial": false,
  "indexVersion": 1,
  "direction": "forward",
  "indexBounds":
  {
   "name": [
    "[\"zhang\", \"zhang\"]"
   ],
   "age": [
    "[\"14\", \"14\"]"
   ]
  }
 }
}

由winningPlan可知,這個查詢的順序沒有變化,依次分為IXSCAN和FETCH兩個階段。但是,IXSCAN使用的是name與age的復合索引;FETCH即根據索引去查詢文檔,不需要過濾。

這個示例的數據量太小,并不能看出什么問題。但是實際上,當數據量很大,IXSCAN返回的索引比較多時,FETCH時進行過濾將非常耗時。接下來將介紹一個真實的案例。

定位MongoDB性能問題

隨著接收的錯誤數據不斷增加,我們Fundebug已經累計處理3.5億錯誤事件,這給我們的服務不斷帶來性能方面的挑戰,尤其對于MongoDB集群來說。

對于生產數據庫,配置profile,可以記錄MongoDB的性能數據。執行以下命令,則所有超過1s的數據庫讀寫操作都會被記錄下來。

db.setProfilingLevel(1,1000)

查詢profile所記錄的數據,會發現events集合的某個查詢非常慢:

db.system.profile.find().pretty()
{
 "op" : "command",
 "ns" : "fundebug.events",
 "command" : {
 "count" : "events",
 "query" : {
 "createAt" : {
 "$lt" : ISODate("2018-02-05T20:30:00.073Z")
 },
 "projectId" : ObjectId("58211791ea2640000c7a3fe6")
 }
 },
 "keyUpdates" : 0,
 "writeConflicts" : 0,
 "numYield" : 1414,
 "locks" : {
 "Global" : {
 "acquireCount" : {
 "r" : NumberLong(2830)
 }
 },
 "Database" : {
 "acquireCount" : {
 "r" : NumberLong(1415)
 }
 },
 "Collection" : {
 "acquireCount" : {
 "r" : NumberLong(1415)
 }
 }
 },
 "responseLength" : 62,
 "protocol" : "op_query",
 "millis" : 28521,
 "execStats" : {
 },
 "ts" : ISODate("2018-03-07T20:30:59.440Z"),
 "client" : "192.168.59.226",
 "allUsers" : [ ],
 "user" : ""
}

events集合中有數億個文檔,因此count操作比較慢也不算太意外。根據profile數據,這個查詢耗時28.5s,時間長得有點離譜。另外,numYield高達1414,這應該就是操作如此之慢的直接原因。根據MongoDB文檔,numYield的含義是這樣的:

The number of times the operation yielded to allow other operations to complete. Typically, operations yield when they need access to data that MongoDB has not yet fully read into memory. This allows other operations that have data in memory to complete while MongoDB reads in data for the yielding operation.

這就意味著大量時間消耗在讀取硬盤上,且讀了非常多次。可以推測,應該是索引的問題導致的。

不妨使用explian()來分析一下這個查詢(僅保留executionStats):

db.events.explain("executionStats").count({"projectId" : ObjectId("58211791ea2640000c7a3fe6"),createAt:{"$lt" : ISODate("2018-02-05T20:30:00.073Z")}})
"executionStats":
{
 "executionSuccess": true,
 "nReturned": 20853,
 "executionTimeMillis": 28055,
 "totalKeysExamined": 28338,
 "totalDocsExamined": 28338,
 "executionStages":
 {
  "stage": "FETCH",
  "filter":
  {
   "createAt":
   {
    "$lt": ISODate("2018-02-05T20:30:00.073Z")
   }
  },
  "nReturned": 20853,
  "executionTimeMillisEstimate": 27815,
  "works": 28339,
  "advanced": 20853,
  "needTime": 7485,
  "needYield": 0,
  "saveState": 1387,
  "restoreState": 1387,
  "isEOF": 1,
  "invalidates": 0,
  "docsExamined": 28338,
  "alreadyHasObj": 0,
  "inputStage":
  {
   "stage": "IXSCAN",
   "nReturned": 28338,
   "executionTimeMillisEstimate": 30,
   "works": 28339,
   "advanced": 28338,
   "needTime": 0,
   "needYield": 0,
   "saveState": 1387,
   "restoreState": 1387,
   "isEOF": 1,
   "invalidates": 0,
   "keyPattern":
   {
    "projectId": 1
   },
   "indexName": "projectId_1",
   "isMultiKey": false,
   "isUnique": false,
   "isSparse": false,
   "isPartial": false,
   "indexVersion": 1,
   "direction": "forward",
   "indexBounds":
   {
    "projectId": [
     "[ObjectId('58211791ea2640000c7a3fe6'), ObjectId('58211791ea2640000c7a3fe6')]"
    ]
   },
   "keysExamined": 28338,
   "dupsTested": 0,
   "dupsDropped": 0,
   "seenInvalidated": 0
  }
 }
}

可知,events集合并沒有為projectId與createAt建立復合索引,因此IXSCAN階段采用的是projectId索引,其nReturned為28338; FETCH階段需要根據createAt進行過濾,其nReturned為20853,過濾掉了7485個文檔;另外,IXSCAN與FETCH階段的executionTimeMillisEstimate分別為30ms和27815ms,因此基本上所有時間都消耗在了FETCH階段,這應該是讀取硬盤導致的。

創建復合索引

沒有為projectId和createAt創建復合索引是個尷尬的錯誤,趕緊補救一下:

db.events.createIndex({projectId:1,createTime:-1},{background: true})

在生產環境構建索引這種事最好是晚上做,這個命令一共花了大概7個小時吧!background設為true,指的是不要阻塞數據庫的其他操作,保證數據庫的可用性。但是,這個命令會一直占用著終端,這時不能使用CTRL + C,否則會終止索引構建過程。

復合索引創建成果之后,前文的查詢就快了很多(僅保留executionStats):

db.javascriptevents.explain("executionStats").count({"projectId" : ObjectId("58211791ea2640000c7a3fe6"),createAt:{"$lt" : ISODate("2018-02-05T20:30:00.073Z")}})
"executionStats":
{
 "executionSuccess": true,
 "nReturned": 0,
 "executionTimeMillis": 47,
 "totalKeysExamined": 20854,
 "totalDocsExamined": 0,
 "executionStages":
 {
  "stage": "COUNT",
  "nReturned": 0,
  "executionTimeMillisEstimate": 50,
  "works": 20854,
  "advanced": 0,
  "needTime": 20853,
  "needYield": 0,
  "saveState": 162,
  "restoreState": 162,
  "isEOF": 1,
  "invalidates": 0,
  "nCounted": 20853,
  "nSkipped": 0,
  "inputStage":
  {
   "stage": "COUNT_SCAN",
   "nReturned": 20853,
   "executionTimeMillisEstimate": 50,
   "works": 20854,
   "advanced": 20853,
   "needTime": 0,
   "needYield": 0,
   "saveState": 162,
   "restoreState": 162,
   "isEOF": 1,
   "invalidates": 0,
   "keysExamined": 20854,
   "keyPattern":
   {
    "projectId": 1,
    "createAt": -1
   },
   "indexName": "projectId_1_createTime_-1",
   "isMultiKey": false,
   "isUnique": false,
   "isSparse": false,
   "isPartial": false,
   "indexVersion": 1
  }
 }
}

可知,count操作使用了projectId和createAt的復合索引,因此非常快,只花了46ms,性能提升了將近600倍!!!對比使用復合索引前后的結果,發現totalDocsExamined從28338降到了0,表示使用復合索引之后不再需要去查詢文檔,只需要掃描索引就好了,這樣就不需要去訪問磁盤了,自然快了很多。

參考

  • MongoDB 復合索引
  • MongoDB文檔:Compound Indexes

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • MongoDB索引使用詳解
  • MongoDB中唯一索引(Unique)的那些事
  • MongoDB的基礎查詢和索引操作方法總結
  • MongoDB中創建索引需要注意的事項
  • MongoDB性能篇之創建索引,組合索引,唯一索引,刪除索引和explain執行計劃
  • mongodb處理中文索引與查找字符串詳解
  • MongoDB查詢字段沒有創建索引導致的連接超時異常解案例分享
  • 關于MongoDB索引管理-索引的創建、查看、刪除操作詳解
  • MongoDB自動刪除過期數據的方法(TTL索引)
  • 關于對MongoDB索引的一些簡單理解

標簽:廈門 遼陽 雞西 玉林 無錫 興安盟 自貢 泰安

巨人網絡通訊聲明:本文標題《深入理解MongoDB的復合索引》,本文關鍵詞  深入,理解,MongoDB,的,復合,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《深入理解MongoDB的復合索引》相關的同類信息!
  • 本頁收集關于深入理解MongoDB的復合索引的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    亚洲美女淫视频| 日产国产欧美视频一区精品 | 午夜成人免费电影| 精品盗摄一区二区三区| 91成人在线精品| 国产传媒欧美日韩成人| 日产欧产美韩系列久久99| 成人欧美一区二区三区视频网页| 欧美一区二区网站| 91豆麻精品91久久久久久| 国产黄色91视频| 蜜臀va亚洲va欧美va天堂| 亚洲精品亚洲人成人网在线播放| 精品国产乱码久久久久久久久 | 亚洲成人中文在线| 综合欧美亚洲日本| 欧美精品一区二区蜜臀亚洲| 欧美午夜片在线观看| 91丨porny丨在线| 国产福利精品一区二区| 狠狠色丁香婷婷综合久久片| 亚洲电影一区二区三区| 亚洲视频在线一区| 国产欧美精品一区二区色综合朱莉 | 久久亚洲一区二区三区四区| 欧美日韩精品专区| 日本高清免费不卡视频| aaa欧美色吧激情视频| 岛国av在线一区| 国产精品一区二区男女羞羞无遮挡| 男男成人高潮片免费网站| 午夜国产精品影院在线观看| 一区二区三区**美女毛片| 亚洲欧美激情在线| 亚洲欧美电影院| 亚洲黄色免费电影| 亚洲综合一区二区三区| 一区二区三区日韩在线观看| 亚洲黄色av一区| 亚洲综合久久久| 亚洲一二三四在线| 婷婷六月综合亚洲| 五月开心婷婷久久| 美女脱光内衣内裤视频久久网站| 青青草伊人久久| 男女视频一区二区| 国产在线视频一区二区三区| 国产成人在线视频网站| 夫妻av一区二区| www.日韩在线| 日本韩国欧美一区二区三区| 欧美少妇性性性| 在线综合亚洲欧美在线视频 | 国产精品国产三级国产普通话三级| www久久精品| 国产日韩高清在线| 国产精品久久久久国产精品日日| 自拍av一区二区三区| 亚洲乱码国产乱码精品精98午夜 | 欧美亚洲综合久久| 91精品国产品国语在线不卡| 精品国产一区二区三区久久久蜜月| 精品国产一区a| 中文字幕 久热精品 视频在线| 综合久久国产九一剧情麻豆| 一区二区三区在线视频免费观看 | 男男成人高潮片免费网站| 精品一区二区三区欧美| 不卡av免费在线观看| 欧美亚日韩国产aⅴ精品中极品| 56国语精品自产拍在线观看| 精品国一区二区三区| 国产精品麻豆视频| 日日夜夜一区二区| 春色校园综合激情亚洲| 欧美色图在线观看| 久久久亚洲高清| 亚洲一区国产视频| 韩国三级电影一区二区| 91麻豆6部合集magnet| 7777精品久久久大香线蕉| 欧美国产一区二区在线观看| 亚洲成人av一区二区三区| 国产精品一色哟哟哟| 欧美三区免费完整视频在线观看| 日韩欧美一二三四区| 亚洲精品videosex极品| 国产一区二区主播在线| 欧美午夜理伦三级在线观看| 国产亚洲一区二区三区在线观看| 一个色在线综合| 国产精品一区不卡| 91精品婷婷国产综合久久| 国产精品另类一区| 日本伊人色综合网| 91麻豆免费视频| 久久免费看少妇高潮| 亚洲一二三四在线| 成人aa视频在线观看| 2024国产精品| 亚洲国产成人精品视频| 不卡区在线中文字幕| 精品国产制服丝袜高跟| 视频在线在亚洲| 色偷偷成人一区二区三区91| 久久久美女毛片| 美女诱惑一区二区| 欧美午夜在线观看| 亚洲欧美日本韩国| 丁香另类激情小说| www欧美成人18+| 蜜桃精品视频在线| 在线不卡免费av| 亚洲一二三区视频在线观看| 国产成人综合网站| 精品欧美久久久| 日韩 欧美一区二区三区| 欧美性生活久久| 亚洲视频在线观看一区| 成人性生交大片免费看在线播放| 日韩视频在线观看一区二区| 婷婷综合另类小说色区| 色狠狠桃花综合| 一区二区三区在线观看欧美| 99re这里都是精品| 亚洲欧洲韩国日本视频| 国产成人av网站| 久久一二三国产| 国产在线观看一区二区| 精品捆绑美女sm三区| 麻豆91在线播放免费| 日韩视频在线观看一区二区| 免费在线观看一区二区三区| 欧美一级理论片| 另类的小说在线视频另类成人小视频在线 | 国产精品乱码人人做人人爱| 精品播放一区二区| 免费成人你懂的| 精品国产一区a| 国产精品一区二区x88av| 国产三级一区二区| 国产精品亚洲一区二区三区在线| 久久久精品天堂| 成人免费观看av| 曰韩精品一区二区| 欧美日韩精品系列| 麻豆成人综合网| 久久久午夜精品| 99视频在线精品| 一区二区三区日韩在线观看| 欧美日韩www| 日本成人在线看| 久久久久久99精品| 99久久777色| 亚洲国产视频网站| 日韩美女视频在线| 国产高清不卡一区| 亚洲视频一区二区在线观看| 91国偷自产一区二区使用方法| 亚洲成人先锋电影| 日韩亚洲欧美成人一区| 韩国v欧美v亚洲v日本v| 国产精品麻豆网站| 欧美裸体一区二区三区| 九九**精品视频免费播放| 国产精品无圣光一区二区| 在线观看免费一区| 美女免费视频一区二区| 日本一区二区三区在线不卡| 91麻豆免费看| 蜜桃一区二区三区在线| 国产欧美精品一区二区色综合| 色综合天天综合网天天狠天天| 天天综合天天综合色| www国产成人| 日本乱人伦aⅴ精品| 久久国产精品99久久久久久老狼| 中文字幕av一区 二区| 欧美另类高清zo欧美| 国产成人av电影免费在线观看| 亚洲综合无码一区二区| 久久久电影一区二区三区| 欧美性色欧美a在线播放| 国产精一区二区三区| 亚洲成人久久影院| 国产精品人人做人人爽人人添| 欧美日韩国产小视频| 成人综合婷婷国产精品久久| 午夜婷婷国产麻豆精品| 国产精品视频看| 日韩精品一区二区三区视频| 色av成人天堂桃色av| 国产麻豆精品一区二区| 亚洲不卡一区二区三区| 中文字幕免费不卡| 精品免费一区二区三区| 欧美日本一区二区三区四区 | 欧美精品久久一区二区三区| 成人av网站在线| 黑人精品欧美一区二区蜜桃|