婷婷综合国产,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
    精品国产乱码久久| 久久久一区二区三区| 欧美一区国产二区| 色八戒一区二区三区| 在线免费观看日韩欧美| 国产精品日韩成人| 久久久久久99久久久精品网站| 国产偷国产偷亚洲高清人白洁| 亚洲三级视频在线观看| 亚洲综合一二区| 国产成人在线视频免费播放| 色老汉av一区二区三区| 777xxx欧美| 亚洲精品高清视频在线观看| 国产成人在线网站| 国产亚洲欧美一级| 视频在线观看一区| thepron国产精品| 欧美不卡一区二区三区四区| 五月婷婷激情综合| 91麻豆成人久久精品二区三区| 91麻豆精品国产91久久久使用方法| 亚洲精品一区二区三区蜜桃下载| 日韩欧美国产电影| 亚洲一二三级电影| 91在线观看下载| 日韩一区欧美一区| 国产一区二区三区四区在线观看| 在线成人av网站| 亚洲h精品动漫在线观看| 91福利视频久久久久| 亚洲综合清纯丝袜自拍| 欧美色成人综合| 一区二区三区在线观看网站| 老司机精品视频在线| 国产精品久久久久7777按摩| 久久超碰97人人做人人爱| 欧美日韩一区三区| 裸体在线国模精品偷拍| 亚洲精品一区二区三区99| 成人中文字幕合集| 日韩欧美一区在线| 亚洲欧美日韩精品久久久久| 一本色道久久加勒比精品 | 亚洲妇女屁股眼交7| 欧美在线观看18| 亚洲最大的成人av| 欧美久久高跟鞋激| 轻轻草成人在线| 欧美日本韩国一区二区三区视频| 丁香婷婷综合五月| 亚洲精品视频免费看| 91麻豆精品国产91久久久久久久久| 国产精品网站一区| 国产a级毛片一区| 亚洲综合久久久| 欧美videos中文字幕| jlzzjlzz亚洲女人18| 一本一本大道香蕉久在线精品| 精品成人佐山爱一区二区| 91香蕉视频mp4| 亚洲一二三四区不卡| 国产一区二区三区观看| 久久99久久99精品免视看婷婷| 日韩av一区二区在线影视| 日韩亚洲欧美一区| 99精品偷自拍| av一区二区三区| 激情小说欧美图片| 精品91自产拍在线观看一区| 国产精品传媒入口麻豆| 日韩限制级电影在线观看| 91精品国产综合久久精品图片| 国产乱妇无码大片在线观看| 亚洲精品免费电影| 亚洲精品乱码久久久久久| 久久综合给合久久狠狠狠97色69| 26uuu精品一区二区三区四区在线 26uuu精品一区二区在线观看 | 成人精品视频一区| a级精品国产片在线观看| 久久超碰97中文字幕| 五月综合激情日本mⅴ| 精品国产sm最大网站免费看| 一本色道久久加勒比精品| 国产尤物一区二区在线| 亚洲成人免费在线| 337p日本欧洲亚洲大胆精品| 91精品在线免费观看| 欧美探花视频资源| 在线观看91精品国产入口| 色综合av在线| 色综合天天综合在线视频| 国产精品99久久久| 国产精品一区在线观看你懂的| 久久99国产精品麻豆| 激情综合色播五月| 国精产品一区一区三区mba桃花| 久久电影国产免费久久电影| 精品一二三四在线| 国产精品电影院| 亚洲成人先锋电影| 天堂va蜜桃一区二区三区| 国产精品护士白丝一区av| 欧美精品免费视频| eeuss影院一区二区三区 | 日韩电影免费在线| 日本亚洲三级在线| 欧美一区二区三区在线电影| 日韩一区二区在线观看| 日韩欧美中文一区| 久久一日本道色综合| 日韩一级大片在线观看| 91精品国产一区二区三区| 一本色道久久综合狠狠躁的推荐 | 国产精品三级av在线播放| 国产日韩欧美麻豆| 亚洲欧洲精品一区二区三区不卡| 亚洲黄色小视频| 天堂va蜜桃一区二区三区漫画版 | 欧美一区二区三区思思人| 日韩欧美国产不卡| 国产免费成人在线视频| 亚洲伦在线观看| 日日噜噜夜夜狠狠视频欧美人| 三级欧美在线一区| 国产一区二区三区四| proumb性欧美在线观看| 欧美日韩精品免费| 精品国产乱码久久久久久久| 中文字幕二三区不卡| 亚洲国产综合色| 久久国产精品区| 色呦呦网站一区| 日韩欧美一级二级| 亚洲制服欧美中文字幕中文字幕| 一区二区三区免费| 国产福利精品一区| 欧美日韩一本到| 久久九九国产精品| 视频在线观看一区| aaa亚洲精品一二三区| 欧美一卡2卡3卡4卡| 欧美不卡一区二区三区| 久久精品国产99国产精品| 免费三级欧美电影| 午夜精品在线视频一区| 国产成人99久久亚洲综合精品| 岛国精品在线观看| 国产精品久久网站| 狠狠色狠狠色合久久伊人| 久久蜜臀中文字幕| 秋霞午夜鲁丝一区二区老狼| 欧美亚洲一区二区在线观看| 婷婷国产在线综合| 色网综合在线观看| 中文字幕不卡在线播放| 三级久久三级久久久| 欧美性受极品xxxx喷水| 亚洲国产经典视频| 日韩精品免费专区| 精品99999| 国产美女一区二区三区| 99精品久久只有精品| 国产精品九色蝌蚪自拍| 成人综合在线网站| 亚洲欧美日韩中文播放| 91在线视频观看| 一区二区三区高清不卡| 91丨porny丨户外露出| 丝瓜av网站精品一区二区| 欧美三级中文字| 亚洲狼人国产精品| 日韩写真欧美这视频| 麻豆精品视频在线观看视频| 国产亚洲欧美日韩日本| 懂色av一区二区三区蜜臀| 久久久久国产精品免费免费搜索| 风流少妇一区二区| 日韩美女视频19| 成人av午夜电影| 久久er99精品| 中文欧美字幕免费| 日韩成人精品在线观看| 99re这里只有精品视频首页| 亚洲欧美色图小说| 国产午夜精品一区二区| 欧美色视频一区| 色婷婷综合视频在线观看| 日韩成人精品在线观看| 亚洲精品一区二区精华| 3atv一区二区三区| 日本精品一区二区三区四区的功能| 亚洲一区二区欧美日韩| 亚洲欧美国产三级| 国产精品久久毛片av大全日韩| 欧洲日韩一区二区三区| 精品一区中文字幕| 久久99国内精品| 国产精品小仙女| 国产精品小仙女|