婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁(yè) > 知識(shí)庫(kù) > 深入理解MongoDB的復(fù)合索引

深入理解MongoDB的復(fù)合索引

熱門標(biāo)簽:怎么投訴地圖標(biāo)注 廣州長(zhǎng)安公司怎樣申請(qǐng)400電話 蘋果汽車租賃店地圖標(biāo)注 杭州人工電銷機(jī)器人價(jià)格 濟(jì)南電銷機(jī)器人加盟公司 電銷機(jī)器人是什么軟件 老虎洗衣店地圖標(biāo)注 云南外呼系統(tǒng) 呼和浩特電銷外呼系統(tǒng)加盟

為什么需要索引?

當(dāng)你抱怨MongoDB集合查詢效率低的時(shí)候,可能你就需要考慮使用索引了,為了方便后續(xù)介紹,先科普下MongoDB里的索引機(jī)制(同樣適用于其他的數(shù)據(jù)庫(kù)比如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 }

當(dāng)你往某各個(gè)集合插入多個(gè)文檔后,每個(gè)文檔在經(jīng)過(guò)底層的存儲(chǔ)引擎持久化后,會(huì)有一個(gè)位置信息,通過(guò)這個(gè)位置信息,就能從存儲(chǔ)引擎里讀出該文檔。比如mmapv1引擎里,位置信息是『文件id + 文件內(nèi)offset 』, 在wiredtiger存儲(chǔ)引擎(一個(gè)KV存儲(chǔ)引擎)里,位置信息是wiredtiger在存儲(chǔ)文檔時(shí)生成的一個(gè)key,通過(guò)這個(gè)key能訪問(wèn)到對(duì)應(yīng)的文檔;為方便介紹,統(tǒng)一用pos(position的縮寫)來(lái)代表位置信息。

什么是復(fù)合索引?

復(fù)合索引,即Compound Index,指的是將多個(gè)鍵組合到一起創(chuàng)建索引,這樣可以加速匹配多個(gè)鍵的查詢。不妨通過(guò)一個(gè)簡(jiǎn)單的示例理解復(fù)合索引。

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兩個(gè)鍵分別創(chuàng)建了索引(_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"
 }
]

當(dāng)進(jìn)行多鍵查詢時(shí),可以通過(guò)explian()分析執(zhí)行情況(結(jié)果僅保留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可知,這個(gè)查詢依次分為IXSCAN和FETCH兩個(gè)階段。IXSCAN即索引掃描,使用的是age索引;FETCH即根據(jù)索引去查詢文檔,查詢的時(shí)候需要使用name進(jìn)行過(guò)濾。

為name和age創(chuàng)建復(fù)合索引:

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"
 }
]

有了復(fù)合索引之后,同一個(gè)查詢的執(zhí)行方式就不同了:

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可知,這個(gè)查詢的順序沒(méi)有變化,依次分為IXSCAN和FETCH兩個(gè)階段。但是,IXSCAN使用的是name與age的復(fù)合索引;FETCH即根據(jù)索引去查詢文檔,不需要過(guò)濾。

這個(gè)示例的數(shù)據(jù)量太小,并不能看出什么問(wèn)題。但是實(shí)際上,當(dāng)數(shù)據(jù)量很大,IXSCAN返回的索引比較多時(shí),F(xiàn)ETCH時(shí)進(jìn)行過(guò)濾將非常耗時(shí)。接下來(lái)將介紹一個(gè)真實(shí)的案例。

定位MongoDB性能問(wèn)題

隨著接收的錯(cuò)誤數(shù)據(jù)不斷增加,我們Fundebug已經(jīng)累計(jì)處理3.5億錯(cuò)誤事件,這給我們的服務(wù)不斷帶來(lái)性能方面的挑戰(zhàn),尤其對(duì)于MongoDB集群來(lái)說(shuō)。

對(duì)于生產(chǎn)數(shù)據(jù)庫(kù),配置profile,可以記錄MongoDB的性能數(shù)據(jù)。執(zhí)行以下命令,則所有超過(guò)1s的數(shù)據(jù)庫(kù)讀寫操作都會(huì)被記錄下來(lái)。

db.setProfilingLevel(1,1000)

查詢profile所記錄的數(shù)據(jù),會(huì)發(fā)現(xiàn)events集合的某個(gè)查詢非常慢:

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集合中有數(shù)億個(gè)文檔,因此count操作比較慢也不算太意外。根據(jù)profile數(shù)據(jù),這個(gè)查詢耗時(shí)28.5s,時(shí)間長(zhǎng)得有點(diǎn)離譜。另外,numYield高達(dá)1414,這應(yīng)該就是操作如此之慢的直接原因。根據(jù)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.

這就意味著大量時(shí)間消耗在讀取硬盤上,且讀了非常多次。可以推測(cè),應(yīng)該是索引的問(wèn)題導(dǎo)致的。

不妨使用explian()來(lái)分析一下這個(gè)查詢(僅保留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集合并沒(méi)有為projectId與createAt建立復(fù)合索引,因此IXSCAN階段采用的是projectId索引,其nReturned為28338; FETCH階段需要根據(jù)createAt進(jìn)行過(guò)濾,其nReturned為20853,過(guò)濾掉了7485個(gè)文檔;另外,IXSCAN與FETCH階段的executionTimeMillisEstimate分別為30ms和27815ms,因此基本上所有時(shí)間都消耗在了FETCH階段,這應(yīng)該是讀取硬盤導(dǎo)致的。

創(chuàng)建復(fù)合索引

沒(méi)有為projectId和createAt創(chuàng)建復(fù)合索引是個(gè)尷尬的錯(cuò)誤,趕緊補(bǔ)救一下:

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

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

復(fù)合索引創(chuàng)建成果之后,前文的查詢就快了很多(僅保留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的復(fù)合索引,因此非常快,只花了46ms,性能提升了將近600倍!!!對(duì)比使用復(fù)合索引前后的結(jié)果,發(fā)現(xiàn)totalDocsExamined從28338降到了0,表示使用復(fù)合索引之后不再需要去查詢文檔,只需要掃描索引就好了,這樣就不需要去訪問(wèn)磁盤了,自然快了很多。

參考

  • MongoDB 復(fù)合索引
  • MongoDB文檔:Compound Indexes

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

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

標(biāo)簽:廈門 遼陽(yáng) 雞西 玉林 無(wú)錫 興安盟 自貢 泰安

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《深入理解MongoDB的復(fù)合索引》,本文關(guān)鍵詞  深入,理解,MongoDB,的,復(fù)合,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《深入理解MongoDB的復(fù)合索引》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于深入理解MongoDB的復(fù)合索引的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    国产视频911| 欧美zozozo| 欧美日韩黄色一区二区| 久久久无码精品亚洲日韩按摩| 日韩精品每日更新| 欧洲一区在线电影| 亚洲日本成人在线观看| 风间由美一区二区三区在线观看| 欧美亚洲丝袜传媒另类| 欧美性受xxxx黑人xyx| 国产日产亚洲精品系列| 奇米影视在线99精品| 欧美日韩一卡二卡三卡| 七七婷婷婷婷精品国产| 欧美在线高清视频| 一区二区理论电影在线观看| 91麻豆国产香蕉久久精品| 国产精品萝li| bt欧美亚洲午夜电影天堂| 亚洲欧洲综合另类在线| 波多野结衣的一区二区三区| 一区二区久久久久久| 欧美tk—视频vk| a4yy欧美一区二区三区| 日韩精品色哟哟| 久久电影网站中文字幕| 国产精品二三区| 91婷婷韩国欧美一区二区| 亚洲国产精品一区二区久久 | 精品美女在线播放| 丰满少妇久久久久久久| 一区二区三区在线影院| 欧美福利电影网| 成人国产在线观看| 香蕉加勒比综合久久| 久久久久久9999| 91福利精品视频| 国产在线不卡视频| 亚洲香蕉伊在人在线观| 欧美精品一区二区三区视频 | 欧美肥妇毛茸茸| 国内精品免费**视频| 欧美精品一区二区三区在线| 激情五月激情综合网| 亚洲人成亚洲人成在线观看图片| 久久你懂得1024| 成人做爰69片免费看网站| 午夜精品一区二区三区三上悠亚| 久久综合色一综合色88| 欧美视频一区二区三区在线观看| 久久99热99| 最近日韩中文字幕| 欧美精品一区二区三区久久久| 97久久超碰国产精品电影| 日本特黄久久久高潮 | 国产精品女主播在线观看| 欧美午夜片在线看| 成人aa视频在线观看| 九一九一国产精品| 亚洲综合网站在线观看| 国产欧美精品一区二区色综合| 欧美一级理论性理论a| 99精品国产一区二区三区不卡| 老司机精品视频一区二区三区| 午夜电影一区二区三区| 亚洲人成人一区二区在线观看| 国产视频一区在线观看| 久久久精品国产免大香伊| 日韩三级av在线播放| 欧美日本国产一区| 欧美日韩一区国产| 欧美视频中文一区二区三区在线观看| 91片在线免费观看| 在线观看亚洲成人| 欧美精选午夜久久久乱码6080| 欧美日韩一区二区三区免费看| 91麻豆精品国产综合久久久久久| 91精品国产色综合久久久蜜香臀| 日韩视频免费观看高清完整版在线观看 | 日韩三级中文字幕| 欧美大片一区二区三区| 久久综合狠狠综合久久激情| 中文子幕无线码一区tr| 亚洲视频网在线直播| 亚洲一区欧美一区| 美女国产一区二区三区| 国产伦精品一区二区三区免费| fc2成人免费人成在线观看播放| 精品视频一区 二区 三区| 日韩美女在线视频| 国产精品家庭影院| 日本视频在线一区| 国产成人在线视频免费播放| 91麻豆免费在线观看| 日韩视频一区二区在线观看| 国产欧美日韩亚州综合| 亚洲一线二线三线久久久| 九九精品一区二区| 欧美午夜寂寞影院| 亚洲国产高清在线| 免费欧美高清视频| 一本到三区不卡视频| 欧美猛男男办公室激情| 国产欧美一区二区精品久导航 | 久久久精品免费网站| 亚洲精品精品亚洲| 精品一区二区在线看| av午夜精品一区二区三区| 欧美日韩视频在线一区二区| 国产精品久久久久久久久免费相片 | 亚洲精品视频一区| 视频一区二区中文字幕| 成人av手机在线观看| 欧美精品免费视频| 国产情人综合久久777777| 亚洲r级在线视频| 成人午夜av影视| 91精品国产欧美一区二区| 亚洲免费毛片网站| 粉嫩av一区二区三区在线播放 | 久久精品久久99精品久久| 日本黄色一区二区| 中文字幕亚洲在| 精品一区二区三区视频在线观看 | 宅男噜噜噜66一区二区66| 日韩伦理电影网| 激情综合网天天干| 欧美系列一区二区| 成人免费视频在线观看| 国模大尺度一区二区三区| 欧美一二三区在线| 一区二区三区中文字幕精品精品 | 欧美成人免费网站| 日日夜夜精品视频天天综合网| 日韩三级视频在线看| 亚洲精选一二三| 色综合激情五月| 国产精品区一区二区三区| 国产v综合v亚洲欧| 国产精品成人免费精品自在线观看| 国产一区二区h| 国产欧美一区二区精品仙草咪| 国产精品中文字幕日韩精品| 国产日韩欧美精品在线| 国产91精品一区二区麻豆亚洲| 久久精品免视看| 粉嫩久久99精品久久久久久夜| 国产精品久久福利| 色婷婷久久综合| 午夜精品福利一区二区三区蜜桃| 欧美日韩高清一区二区三区| 日本三级韩国三级欧美三级| 精品久久人人做人人爽| 国产福利不卡视频| 一区二区三区影院| 欧美日韩午夜在线视频| 激情亚洲综合在线| 中文字幕制服丝袜一区二区三区 | 一区二区免费看| 51精品秘密在线观看| 久久草av在线| 中文字幕在线不卡一区二区三区| 色综合天天做天天爱| 午夜精品福利在线| 在线成人高清不卡| 狠狠久久亚洲欧美| 国产精品全国免费观看高清| 色婷婷亚洲精品| 青青草国产精品亚洲专区无| 久久久99精品免费观看| 色悠悠久久综合| 麻豆久久久久久久| 中文字幕一区二区三区四区不卡| 欧美日韩国产一区二区三区地区| 国产福利一区二区三区视频在线| 亚洲欧美偷拍卡通变态| 欧美电影免费观看高清完整版在线观看| 国产成人日日夜夜| 日本一区二区三级电影在线观看 | 亚洲国产成人av| 欧美一级夜夜爽| 99久久婷婷国产综合精品电影| 亚洲免费在线看| 在线免费视频一区二区| 一本久久a久久免费精品不卡| 3d成人动漫网站| 国产不卡在线播放| 日韩精品午夜视频| 日韩高清不卡在线| 蜜桃视频第一区免费观看| 国产一区二区精品久久99| 精品一区二区av| 久久se精品一区二区| 国内精品久久久久影院薰衣草| 国产电影精品久久禁18| 成人精品免费网站| 一本到不卡精品视频在线观看| 亚洲国产wwwccc36天堂| 亚洲国产欧美在线| 亚洲精品久久久久久国产精华液|