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

主頁(yè) > 知識(shí)庫(kù) > 關(guān)于MongoDB謹(jǐn)防索引seek的效率問(wèn)題詳析

關(guān)于MongoDB謹(jǐn)防索引seek的效率問(wèn)題詳析

熱門(mén)標(biāo)簽:外呼線路資源屬于電信業(yè)務(wù)嗎 內(nèi)蒙古營(yíng)銷(xiāo)智能外呼系統(tǒng)哪個(gè)好 長(zhǎng)沙電銷(xiāo)外呼防封卡是什么 河南電話外呼系統(tǒng)招商 呼和浩特外呼系統(tǒng)原理是什么 crm外呼系統(tǒng)聯(lián)系方式 小裙科技電銷(xiāo)機(jī)器人怎樣 青白江400企業(yè)電話申請(qǐng) 智能外呼系統(tǒng)官網(wǎng)

背景

最近線上的一個(gè)工單分析服務(wù)一直不大穩(wěn)定,監(jiān)控平臺(tái)時(shí)不時(shí)發(fā)出數(shù)據(jù)庫(kù)操作超時(shí)的告警。

運(yùn)維兄弟溝通后,發(fā)現(xiàn)在每天凌晨1點(diǎn)都會(huì)出現(xiàn)若干次的業(yè)務(wù)操作失敗,而數(shù)據(jù)庫(kù)監(jiān)控上并沒(méi)有發(fā)現(xiàn)明顯的異常。

在該分析服務(wù)的日志中發(fā)現(xiàn)了某個(gè)數(shù)據(jù)庫(kù)操作產(chǎn)生了 SocketTimeoutException。

開(kāi)發(fā)同學(xué)一開(kāi)始希望通過(guò)調(diào)整 MongoDB Java Driver 的超時(shí)參數(shù)來(lái)規(guī)避這個(gè)問(wèn)題。
但經(jīng)過(guò)詳細(xì)分析之后,這樣是無(wú)法根治問(wèn)題的,而且超時(shí)配置應(yīng)該如何調(diào)整也難以評(píng)估。

下面是關(guān)于對(duì)這個(gè)問(wèn)題的分析、調(diào)優(yōu)的過(guò)程。

初步分析

從出錯(cuò)的信息上看,是數(shù)據(jù)庫(kù)的操作響應(yīng)超時(shí)了,此時(shí)客戶端配置的 SocketReadTimeout 為 60s。
那么,是什么操作會(huì)導(dǎo)致數(shù)據(jù)庫(kù) 60s 還沒(méi)能返回呢?

業(yè)務(wù)操作

左邊的數(shù)據(jù)庫(kù)是一個(gè)工單數(shù)據(jù)表(t_work_order),其中記錄了每張工單的信息,包括工單編號(hào)(oid)、最后修改時(shí)間(lastModifiedTime)

分析服務(wù)是Java實(shí)現(xiàn)的一個(gè)應(yīng)用程序,在每天凌晨1:00 會(huì)拉取出前一天修改的工單信息(要求按工單號(hào)排序)進(jìn)行處理。

由于工單表非常大(千萬(wàn)級(jí)),所以在處理時(shí)會(huì)采用分頁(yè)的做法(每次取1000條),使用按工單號(hào)翻頁(yè)的方式:

第一次拉取

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}, 
  "oid": {$exists: true}})
  .sort({"oid":1}).limit(1000)

第二次拉取,以第一次拉取的最后一條記錄的工單號(hào)作為起點(diǎn)

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}, 
  "oid": {$exists: true, $gt: "VXZ190"}})
  .sort({"oid":1}).limit(1000)
..

根據(jù)這樣的查詢,開(kāi)發(fā)人員給數(shù)據(jù)表使用的索引如下:

db.t_work_order.ensureIndexes({
  "oid" : 1,
  "lastModifiedTime" : -1
})

盡管該索引與查詢字段基本是匹配的,但在實(shí)際執(zhí)行時(shí)卻表現(xiàn)出很低的效率:
第一次拉取時(shí)間非常的長(zhǎng),經(jīng)常超過(guò)60s導(dǎo)致報(bào)錯(cuò),而后面的拉取時(shí)間則會(huì)快一些

為了精確的模擬該場(chǎng)景,我們?cè)跍y(cè)試環(huán)境中預(yù)置了小部分?jǐn)?shù)據(jù),對(duì)拉取記錄的SQL執(zhí)行Explain:

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}
  "oid": {$exists: true}})
  .sort({"oid":1}).limit(1000)
  .explain("executionStats")

輸出結(jié)果如下

"nReturned" : 1000,
"executionTimeMillis" : 589,
"totalKeysExamined" : 136661,
"totalDocsExamined" : 1000,

...

"indexBounds" : {
    "oid" : [
        "[MinKey, MaxKey]"
    ],
    "lastModifiedTime" : [
        "(new Date(1554806697106), new Date(1554803097106))"
    ]
},
"keysExamined" : 136661,
"seeks" : 135662,

在執(zhí)行過(guò)程中發(fā)現(xiàn),檢索1000條記錄,居然需要掃描 13.6 W條索引項(xiàng)!

其中,幾乎所有的開(kāi)銷(xiāo)都花費(fèi)在了 一個(gè)seeks操作上了。

索引seeks的原因

官方文檔對(duì)于 seeks 的解釋如下:

The number of times that we had to seek the index cursor to a new position in order to complete the index scan.

翻譯過(guò)來(lái)就是:

seeks 是指為了完成索引掃描(stage),執(zhí)行器必須將游標(biāo)定位到新位置的次數(shù)。

我們都知道 MongoDB 的索引是B+樹(shù)的實(shí)現(xiàn)(3.x以上),對(duì)于連續(xù)的葉子節(jié)點(diǎn)掃描來(lái)說(shuō)是非常快的(只需要一次尋址),那么seeks操作太多則表示整個(gè)掃描過(guò)程中出現(xiàn)了大量的尋址(跳過(guò)非目標(biāo)節(jié)點(diǎn))。
而且,這個(gè)seeks指標(biāo)是在3.4版本支持的,因此可以推測(cè)該操作對(duì)性能是存在影響的。

為了探究 seeks 是怎么產(chǎn)生的,我們對(duì)查詢語(yǔ)句嘗試做了一些變更:

去掉 exists 條件

exists 條件的存在是因?yàn)闅v史問(wèn)題(一些舊記錄并不包含工單號(hào)的字段),為了檢查exists查詢是否為關(guān)鍵問(wèn)題,修改如下:

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}
  })
  .sort({"oid":1}).limit(1000)
  .explain("executionStats")

執(zhí)行后的結(jié)果為:

"nReturned" : 1000,
"executionTimeMillis" : 1533,
"totalKeysExamined" : 272322,
"totalDocsExamined" : 272322,
 
...

"inputStage" : {
  "stage" : "FETCH",
  "filter" : {
      "$and" : [
          {
              "lastModifiedTime" : {
                  "$lt" : ISODate("2019-04-09T10:44:57.106Z")
              }
          },
          {
              "lastModifiedTime" : {
                  "$gt" : ISODate("2019-04-09T09:44:57.106Z")
              }
          }
      ]
},

...

"indexBounds" : {
    "oid" : [
        "[MinKey, MaxKey]"
    ],
    "lastModifiedTime" : [
        "[MaxKey, MinKey]"
    ]
},
"keysExamined" : 272322,
"seeks" : 1,

這里發(fā)現(xiàn),去掉 exists 之后,seeks 變成了1次,但整個(gè)查詢掃描了 27.2W 條索引項(xiàng)! 剛好是去掉之前的2倍。

seeks 變?yōu)?次說(shuō)明已經(jīng)使用了葉節(jié)點(diǎn)順序掃描的方式,然而由于掃描范圍非常大,為了找到目標(biāo)記錄,會(huì)執(zhí)行順序掃描并過(guò)濾大量不符合條件的記錄。

在 FETCH 階段出現(xiàn)了 filter可說(shuō)明這一點(diǎn)。與此同時(shí),我們檢查了數(shù)據(jù)表的特征:同一個(gè)工單號(hào)是存在兩條記錄的!于是可以說(shuō)明:

在存在exists查詢條件時(shí),執(zhí)行器會(huì)選擇按工單號(hào)進(jìn)行seeks跳躍式檢索,如下圖:


在不存在exists條件的情況下,執(zhí)行器選擇了葉節(jié)點(diǎn)順序掃描的方式,如下圖:


gt 條件和反序

除了第一次查詢之外,我們對(duì)后續(xù)的分頁(yè)查詢也進(jìn)行了分析,如下:

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}, 
  "oid": {$exists: true, $gt: "VXZ190"}})
  .sort({"oid":1}).limit(1000)
  .explain("executionStats")

上面的語(yǔ)句中,主要是增加了$gt: "VXZ190"這一個(gè)條件,執(zhí)行過(guò)程如下:

"nReturned" : 1000,
"executionTimeMillis" : 6,
"totalKeysExamined" : 1004,
"totalDocsExamined" : 1000,

...

"indexBounds" : {
  "oid" : [ 
    "(\"VXZ190\", {})"
  ],
  "lastModifiedTime" : [ 
    "(new Date(1554806697106), new Date(1554803097106))"
  ]
},
"keysExamined" : 1004,
"seeks" : 5,

可以發(fā)現(xiàn),seeks的數(shù)量非常少,而且檢索過(guò)程只掃描了1004條記錄,效率是很高的。

那么,是不是意味著在后面的數(shù)據(jù)中,滿足查詢的條件的記錄非常密集呢?

為了驗(yàn)證這一點(diǎn),我們將一開(kāi)始第一次分頁(yè)的查詢做一下調(diào)整,改為按工單號(hào)降序的方式(從后往前掃描):

db.t_work_order.find({
  "lastModifiedTime":{
   $gt: new Date("2019-04-09T09:44:57.106Z"),
   $lt: new Date("2019-04-09T10:44:57.106Z")}, 
  "oid": {$exists: true}})
  .sort({"oid":-1}).limit(1000)
  .explain("executionStats")

新的"反序查詢語(yǔ)句"的執(zhí)行過(guò)程如下:

"nReturned" : 1000,
"executionTimeMillis" : 6,
"totalKeysExamined" : 1001,
"totalDocsExamined" : 1000,

...

"direction" : "backward",
"indexBounds" : {
  "oid" : [ 
    "[MaxKey, MinKey]"
  ],
  "lastModifiedTime" : [ 
    "(new Date(1554803097106), new Date(1554806697106))"
  ]
},
"keysExamined" : 1001,
"seeks" : 2,

可以看到,執(zhí)行的效率更高了,幾乎不需要什么 seeks 操作!

經(jīng)過(guò)一番確認(rèn)后,我們獲知了在所有數(shù)據(jù)的分布中,工單號(hào)越大的記錄其更新時(shí)間值也越大,基本上我們想查詢的目標(biāo)數(shù)據(jù)都集中在尾端。

于是就會(huì)出現(xiàn)一開(kāi)始提到的,第一次查詢非常慢甚至超時(shí),而后面的查詢就快了。

上面提到的兩個(gè)查詢執(zhí)行路線如圖所示:

加入$gt 條件,從中間開(kāi)始檢索


反序,從后面開(kāi)始檢索


優(yōu)化思路

通過(guò)分析,我們知道了問(wèn)題的癥結(jié)在于索引的掃描范圍過(guò)大,那么如何優(yōu)化,以避免掃描大量記錄呢?

從現(xiàn)有的索引及條件來(lái)看,由于同時(shí)存在gt、exists以及葉子節(jié)點(diǎn)的時(shí)間范圍限定,不可避免的會(huì)產(chǎn)生seeks操作,
而且查詢的性能是不穩(wěn)定的,跟數(shù)據(jù)分布、具體查詢條件都有很大的關(guān)系。

于是一開(kāi)始所提到的僅僅是增加 socketTimeout 的閾值可能只是治標(biāo)不治本,一旦數(shù)據(jù)的索引值分布變化或者數(shù)據(jù)量持續(xù)增大,可能會(huì)發(fā)生更嚴(yán)重的事情。

回到一開(kāi)始的需求場(chǎng)景,定時(shí)器要求讀取每天更新的工單(按工單號(hào)排序),再進(jìn)行分批處理。

那么,按照化零為整的思路,新增一個(gè)lastModifiedDay字段,這個(gè)存儲(chǔ)的就是lastModifiedTime對(duì)應(yīng)的日期值(低位取整),這樣在同一天內(nèi)更新的工單記錄都有同樣的值。

建立組合索引 {lastModifiedDay:1, oid:1},相應(yīng)的查詢條件改為:

{
 "lastModifiedDay": new Date("2019-04-09 00:00:00.000"),
 "oid": {$gt: "VXZ190"}
} 
-- limit 1000

執(zhí)行結(jié)果如下:

"nReturned" : 1000,
"executionTimeMillis" : 6,
"totalKeysExamined" : 1000,
"totalDocsExamined" : 1000,

...

"indexBounds" : {
    "lastModifiedDay" : [
        "(new Date(1554803000000), new Date(1554803000000))"
    ],
    "oid" : [
        "(\"VXZ190\", {})"
    ]
},
"keysExamined" : 1000,
"seeks" : 1,

這樣優(yōu)化之后,每次查詢最多只掃描1000條記錄,查詢速度是非常快的!

小結(jié)

本質(zhì)上,這就是一種空間換時(shí)間的方法,即通過(guò)存儲(chǔ)一個(gè)額外的索引字段來(lái)加速查詢,通過(guò)增加少量的存儲(chǔ)開(kāi)銷(xiāo)提升了整體的效能。

在對(duì)于許多問(wèn)題進(jìn)行優(yōu)化時(shí),經(jīng)常是需要從應(yīng)用場(chǎng)景觸發(fā),適當(dāng)?shù)霓D(zhuǎn)換思路。

比如在本文的問(wèn)題中,是不是一定要增加字段呢?如果業(yè)務(wù)上可以接受不按工單號(hào)排序進(jìn)行讀取,那么僅使用更新時(shí)間字段進(jìn)行分頁(yè)拉取也是可以達(dá)到效果的,具體還是要由業(yè)務(wù)場(chǎng)景來(lái)定。

總結(jié)

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

您可能感興趣的文章:
  • MongoDB 數(shù)據(jù)庫(kù)的命名、設(shè)計(jì)規(guī)范詳解
  • 28個(gè)MongoDB經(jīng)典面試題詳解
  • MongoDB常用數(shù)據(jù)庫(kù)命令大全
  • 修復(fù) Mac brew 安裝 mongodb 報(bào) Error: No available formula with the name ‘mongodb’ 問(wèn)題詳解
  • MongoDB啟動(dòng)報(bào)錯(cuò) 28663 Cannot start server
  • Node.js操作MongoDB數(shù)據(jù)庫(kù)實(shí)例分析
  • MongoDB數(shù)據(jù)庫(kù)安裝配置、基本操作實(shí)例詳解
  • Windows10安裝MongoDB4.0詳細(xì)步驟及啟動(dòng)配置教程
  • nodejs對(duì)mongodb數(shù)據(jù)庫(kù)的增加修刪該查實(shí)例代碼
  • mongodb基本命令實(shí)例小結(jié)
  • Win10 64位安裝MongoDB數(shù)據(jù)庫(kù)的詳細(xì)教程
  • linux下安裝mongodb教程
  • Python操作redis和mongoDB的方法
  • dotnet core鏈接mongodb代碼實(shí)例
  • Zabbix3.4監(jiān)控mongodb數(shù)據(jù)庫(kù)狀態(tài)的方法
  • Windows安裝壓縮版MongoDB的教程
  • 在Laravel中使用MongoDB的方法示例
  • MongoDB中數(shù)據(jù)的替換方法實(shí)現(xiàn)類(lèi)Replace()函數(shù)功能詳解

標(biāo)簽:舟山 楚雄 呼倫貝爾 黃石 菏澤 安順 池州 白山

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《關(guān)于MongoDB謹(jǐn)防索引seek的效率問(wèn)題詳析》,本文關(guān)鍵詞  關(guān)于,MongoDB,謹(jǐn)防,索引,seek,;如發(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)文章
  • 下面列出與本文章《關(guān)于MongoDB謹(jǐn)防索引seek的效率問(wèn)題詳析》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于關(guān)于MongoDB謹(jǐn)防索引seek的效率問(wèn)題詳析的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    国产精品看片你懂得| 欧美另类videos死尸| 欧美私人免费视频| 国产精品女同互慰在线看| 美国十次了思思久久精品导航| 一本高清dvd不卡在线观看| 国产拍欧美日韩视频二区| 久久国产免费看| 91精品国产乱码| 亚洲一卡二卡三卡四卡五卡| 成人av网址在线| 国产嫩草影院久久久久| 丰满亚洲少妇av| 国产精品美女久久久久久久网站| 国产在线精品一区二区三区不卡| 欧美成人在线直播| 美腿丝袜亚洲三区| 久久夜色精品国产欧美乱极品| 久久99国内精品| 精品va天堂亚洲国产| 精品制服美女久久| 久久亚洲欧美国产精品乐播| 国产1区2区3区精品美女| 国产精品水嫩水嫩| 91麻豆国产精品久久| 亚洲午夜国产一区99re久久| 69精品人人人人| 久久精品二区亚洲w码| 26uuu久久天堂性欧美| 国产suv一区二区三区88区| 国产精品伦理在线| 色偷偷88欧美精品久久久| 亚洲一区二区三区在线| 91麻豆精品国产自产在线观看一区 | 久久婷婷国产综合国色天香| 国产精品996| 国产日韩欧美不卡在线| 99视频超级精品| 亚洲国产日韩综合久久精品| 91精品国产综合久久香蕉的特点 | 精品久久人人做人人爱| 国产69精品一区二区亚洲孕妇| 亚洲精品免费一二三区| 3d动漫精品啪啪| 国产mv日韩mv欧美| 亚洲第一在线综合网站| 久久日韩粉嫩一区二区三区 | 欧美成人r级一区二区三区| 国产不卡视频一区| 午夜不卡av免费| 日本一区二区三区四区| 欧美唯美清纯偷拍| 国产精品系列在线播放| 亚洲bt欧美bt精品| 亚洲国产经典视频| 欧美一卡2卡三卡4卡5免费| 暴力调教一区二区三区| 另类小说图片综合网| 亚洲欧美日韩在线| 久久久久久一二三区| 欧美三日本三级三级在线播放| 国产经典欧美精品| 午夜国产精品影院在线观看| 国产精品青草综合久久久久99| 欧美一区二区黄色| 欧美中文一区二区三区| 成人免费视频一区| 久久精品国产免费看久久精品| 亚洲六月丁香色婷婷综合久久| 久久色成人在线| 日韩一区二区免费在线观看| 色综合天天视频在线观看| 国产一区二区三区| 轻轻草成人在线| 亚洲成va人在线观看| 亚洲色欲色欲www在线观看| 久久免费国产精品| 欧美大片日本大片免费观看| 色久优优欧美色久优优| 成人午夜免费电影| 国产毛片精品一区| 久久超碰97中文字幕| 香蕉乱码成人久久天堂爱免费| 亚洲免费在线播放| 国产三级精品三级在线专区| 4438x亚洲最大成人网| 日本丶国产丶欧美色综合| 成人精品视频.| 国产成人精品午夜视频免费 | 色综合久久88色综合天天| 成人高清av在线| 国产超碰在线一区| 国产成人免费网站| 激情国产一区二区| 免费av成人在线| 美国一区二区三区在线播放| 蜜臀av性久久久久蜜臀aⅴ四虎| 日日噜噜夜夜狠狠视频欧美人| 亚洲大片精品永久免费| 亚洲福利一二三区| 午夜成人免费电影| 爽爽淫人综合网网站| 亚洲成人自拍偷拍| 日韩高清一区在线| 日日骚欧美日韩| 久久精品国产精品亚洲精品| 激情综合网av| 国产高清在线精品| 成人开心网精品视频| 99久久精品国产精品久久| 99久精品国产| 欧美色网一区二区| 欧美一卡在线观看| 日韩一区二区电影网| 久久综合国产精品| 欧美激情一区二区三区| 亚洲日本一区二区三区| 亚洲国产精品久久艾草纯爱| 日韩精品久久久久久| 国产在线精品视频| 成人国产精品视频| 欧美专区亚洲专区| 日韩一区二区三区四区 | 性久久久久久久久| 亚洲不卡在线观看| 久久精品72免费观看| 国产精品亚洲一区二区三区妖精| 国产91精品一区二区麻豆网站 | 精品日韩欧美一区二区| 久久久99免费| 亚洲欧美日韩中文字幕一区二区三区 | 色综合久久久久网| 欧美一区午夜精品| 久久精品视频免费| 亚洲精品视频在线看| 七七婷婷婷婷精品国产| 国产成人在线免费| 欧美丝袜丝交足nylons| 久久婷婷久久一区二区三区| 自拍偷拍亚洲综合| 秋霞av亚洲一区二区三| 9i在线看片成人免费| 日韩一区二区在线观看视频| 国产精品嫩草影院com| 日本网站在线观看一区二区三区 | 国产精品久久久久久久久免费相片 | 91麻豆免费视频| 制服丝袜亚洲播放| 亚洲欧洲99久久| 美女视频一区二区| 一本大道久久a久久精二百| 精品国产91乱码一区二区三区| 一区二区三区四区高清精品免费观看 | 不卡电影一区二区三区| 日韩午夜激情av| 亚洲乱码国产乱码精品精小说 | 亚洲一区av在线| 国产成人在线视频网址| 3d成人动漫网站| 亚洲精品日产精品乱码不卡| 国产最新精品免费| 在线播放亚洲一区| 亚洲精品乱码久久久久久| 国产乱国产乱300精品| 欧美三级电影网| 1024成人网| 成人黄色片在线观看| 久久久久久影视| 久久99精品国产.久久久久久| 欧美亚洲国产怡红院影院| 亚洲国产精品精华液ab| 狠狠网亚洲精品| 日韩一区二区三区电影在线观看 | 色婷婷一区二区三区四区| 国产日韩高清在线| 久久99国内精品| 日韩午夜中文字幕| 青青草原综合久久大伊人精品优势| 欧美午夜精品久久久| 亚洲激情综合网| 色综合一个色综合亚洲| 亚洲欧洲精品一区二区精品久久久| 国产成人综合精品三级| 久久免费午夜影院| 国产一区二区不卡老阿姨| 欧美精品一区二区三区视频| 精品一区二区三区免费| 欧美不卡视频一区| 久久99久久久久久久久久久| 欧美一区二区视频观看视频| 亚洲国产成人高清精品| 欧美另类变人与禽xxxxx| 偷拍一区二区三区| 91精品久久久久久久99蜜桃| 日本91福利区| 日韩免费高清电影| 国产一区二三区| 亚洲国产精品99久久久久久久久| 国产+成+人+亚洲欧洲自线| 欧美高清在线一区二区|