「生產事故」MongoDB複合索引引發的災難

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前情提要","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"11月末","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"我司商品服務","attrs":{}}],"attrs":{}},{"type":"text","text":"的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MongoDB主庫","attrs":{}}],"attrs":{}},{"type":"text","text":"曾出現過嚴重抖動、頻繁鎖庫等情況。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"由於諸多業務存在插入","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MongoDB","attrs":{}}],"attrs":{}},{"type":"text","text":"、然後立即查詢等邏輯,因此項目並未開啓讀寫分離。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"最終定位問題是由於:服務器自身磁盤 + 大量","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"慢查詢","attrs":{}}],"attrs":{}},{"type":"text","text":"導致","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"基於上述情況,運維同學後續着重增強了對","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MongoDB慢查詢","attrs":{}}],"attrs":{}},{"type":"text","text":"的監控和告警","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"幸運的一點","attrs":{}},{"type":"text","text":":在出事故之前剛好完成了緩存過期時間的升級且過期時間爲一個月,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"C端查詢","attrs":{}}],"attrs":{}},{"type":"text","text":"都落在緩存上,因此沒有造成","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"P0級","attrs":{}}],"attrs":{}},{"type":"text","text":"事故,僅僅阻塞了部分","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"B端邏輯","attrs":{}}],"attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"事故回放","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我司的各種監控做的比較到位,當天突然收到了數據庫服務器負載較高的告警通知,於是我和同事們就趕緊登錄了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Zabbix監控","attrs":{}}],"attrs":{}},{"type":"text","text":",如下圖所示,截圖的時候是正常狀態,當時事故期間忘記留圖了,可以想象當時的數據曲線反正是該高的很低,該低的很高就是了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Zabbix 分佈式監控系統官網:https://www.zabbix.com/","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e6/e6f2212c69deae3fdfd8353d05689736.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"開始分析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們研發是沒有操控服務器權限的,因此委託運維同學幫助我們抓取了部分查詢記錄,如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"---------------------------------------------------------------------------------------------------------------------------+\nOp | Duration | Query ---------------------------------------------------------------------------------------------------------------------------+\nquery | 5 s | {\"filter\": {\"orgCode\": 350119, \"fixedStatus\": {\"$in\": [1, 2]}}, \"sort\": {\"_id\": -1}, \"find\": \"sku_main\"} \nquery | 5 s | {\"filter\": {\"orgCode\": 350119, \"fixedStatus\": {\"$in\": [1, 2]}}, \"sort\": {\"_id\": -1}, \"find\": \"sku_main\"} query | 4 s | {\"filter\": {\"orgCode\": 346814, \"fixedStatus\": {\"$in\": [1, 2]}}, \"sort\": {\"_id\": -1}, \"find\": \"sku_main\"} query | 4 s | {\"filter\": {\"orgCode\": 346814, \"fixedStatus\": {\"$in\": [1, 2]}}, \"sort\": {\"_id\": -1}, \"find\": \"sku_main\"} query | 4 s | {\"filter\": {\"orgCode\": 346814, \"fixedStatus\": {\"$in\": [1, 2]}}, \"sort\": {\"_id\": -1}, \"find\": \"sku_main\"}\n...","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"查詢很慢的話所有研發應該第一時間想到的就是","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"索引","attrs":{}}],"attrs":{}},{"type":"text","text":"的使用問題,所以立即檢查了一遍索引,如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"### 當時的索引\n\ndb.sku_main.ensureIndex({\"orgCode\": 1, \"_id\": -1},{background:true});\ndb.sku_main.ensureIndex({\"orgCode\": 1, \"upcCode\": 1},{background:true});\n....","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我屏蔽了干擾項,反正能很明顯的看出來,這個查詢是完全可以命中索引的,所以就需要直面第一個問題:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"上述查詢記錄中排首位的慢查詢到底是不是出問題的根源?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我的判斷是:它應該不是數據庫整體緩慢的根源,因爲第一它的查詢條件足夠簡單暴力,完全命中索引,在索引之上有一點其他的查詢條件而已,第二在查詢記錄中也存在相同結構不同條件的查詢,耗時非常短。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在運維同學繼續排查查詢日誌時,發現了另一個比較驚爆的查詢,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"### 當時場景日誌\n\nquery: { $query: { shopCategories.0: { $exists: false }, orgCode: 337451, fixedStatus: { $in: [ 1, 2 ] }, _id: { $lt: 2038092587 } }, $orderby: { _id: -1 } } planSummary: IXSCAN { _id: 1 } ntoreturn:1000 ntoskip:0 keysExamined:37567133 docsExamined:37567133 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:293501 nreturned:659 reslen:2469894 locks:{ Global: { acquireCount: { r: 587004 } }, Database: { acquireCount: { r: 293502 } }, Collection: { acquireCount: { r: 293502 } } } \n\n# 耗時\n179530ms","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"耗時180秒且基於查詢的","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"執行計劃","attrs":{}}],"attrs":{}},{"type":"text","text":"可以看出,它走的是","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"id","attrs":{}}],"attrs":{}},{"type":"text","text":"索引,進行了全表掃描,掃描的數據總量爲:37567133,不慢纔怪。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"迅速解決","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定位到問題後,沒辦法立即修改,第一要務是:","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"止損","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結合當時的時間也比較晚了,因此我們發了公告,禁止了上述查詢的功能並短暫暫停了部分業務,,過了一會之後進行了","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"主從切換","attrs":{}}],"attrs":{}},{"type":"text","text":",再去看","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Zabbix監控","attrs":{}}],"attrs":{}},{"type":"text","text":"就一切安好了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"分析根源","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們回顧一下查詢的語句和我們預期的索引,如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"### 原始Query\ndb.getCollection(\"sku_main\").find({ \n \"orgCode\" : NumberLong(337451), \n \"fixedStatus\" : { \n \"$in\" : [\n 1.0, \n 2.0\n ]\n }, \n \"shopCategories\" : { \n \"$exists\" : false\n }, \n \"_id\" : { \n \"$lt\" : NumberLong(2038092587)\n }\n }\n).sort(\n { \n \"_id\" : -1.0\n }\n).skip(1000).limit(1000);\n\n### 期望的索引\ndb.sku_main.ensureIndex({\"orgCode\": 1, \"_id\": -1},{background:true});","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"乍一看,好像一切都很Nice啊,字段","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"orgCode","attrs":{}}],"attrs":{}},{"type":"text","text":"等值查詢,字段","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"_id","attrs":{}}],"attrs":{}},{"type":"text","text":"按照創建索引的方向進行倒序排序,爲啥會這麼慢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,關鍵的一點就在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"$lt","attrs":{}}],"attrs":{}},{"type":"text","text":" 上","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"知識點一:索引、方向及排序","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在MongoDB中,排序操作可以通過從索引中按照索引的順序獲取文檔的方式,來保證結果的有序性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果MongoDB的查詢計劃器沒法從索引中得到排序順序,那麼它就需要在內存中對結果排序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"注意","attrs":{}},{"type":"text","text":":不用索引的排序操作,會在內存超過32MB時終止,也就是說MongoDB只能支持32MB以內的非索引排序","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"知識點二:單列索引不在乎方向","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無論是MongoDB還是MySQL都是用的樹結構作爲索引,如果","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"排序方向","attrs":{}}],"attrs":{}},{"type":"text","text":"和","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"索引方向","attrs":{}}],"attrs":{}},{"type":"text","text":"相反,只需要從另一頭開始遍歷即可,如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"# 索引\ndb.records.createIndex({a:1}); \n\n# 查詢\ndb.records.find().sort({a:-1});\n\n# 索引爲升序,但是我查詢要按降序,我只需要從右端開始遍歷即可滿足需求,反之亦然\nMIN 0 1 2 3 4 5 6 7 MAX","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"MongoDB的複合索引結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"官方介紹:MongoDB supports ","attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"compound indexes","attrs":{}},{"type":"text","text":", where a single index structure holds references to multiple fields within a collection’s documents. ","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"複合索引結構示意圖如下所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fa/fae4f0f93651fb89389924012a0b230c.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"該索引剛好和我們討論的是一樣的,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"userid順序","attrs":{}}],"attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"score倒序","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們需要直面第二個問題:","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"複合索引在使用時需不需要在乎方向?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設兩個查詢條件:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"# 查詢 一\ndb.getCollection(\"records\").find({ \n \"userid\" : \"ca2\"\n}).sort({\"score\" : -1.0});\n\n\n# 查詢 二\ndb.getCollection(\"records\").find({ \n \"userid\" : \"ca2\"\n}).sort({\"score\" : 1.0});","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述的查詢沒有任何問題,因爲受到","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"score","attrs":{}}],"attrs":{}},{"type":"text","text":"字段排序的影響,只是數據從左側還是從右側遍歷的問題,那麼下面的一個查詢呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"# 錯誤示範\ndb.getCollection(\"records\").find({ \n \"userid\" : \"ca2\",\n \"score\" : { \n \"$lt\" : NumberLong(2038092587)\n }\n}).sort({\"score\" : -1.0});","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"錯誤原因如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"由於score字段按照倒序排序,因此爲了使用該索引,所以需要從左側開始遍歷","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"從倒序順序中找小於某個值的數據,勢必會掃描很多無用數據,然後丟棄,當前場景下找大於某個值纔是最佳方案","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"所以MongoDB爲了更多場景考慮,在該種情況下,放棄了複合索引,選用其他的索引,如 score 的單列索引","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"針對性修改","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"仔細閱讀了根源之後,再回顧線上的查詢語句,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"### 原始Query\ndb.getCollection(\"sku_main\").find({ \n \"orgCode\" : NumberLong(337451), \n \"fixedStatus\" : { \n \"$in\" : [\n 1.0, \n 2.0\n ]\n }, \n \"shopCategories\" : { \n \"$exists\" : false\n }, \n \"_id\" : { \n \"$lt\" : NumberLong(2038092587)\n }\n }\n).sort(\n { \n \"_id\" : -1.0\n }\n).skip(1000).limit(1000);\n\n### 期望的索引\ndb.sku_main.ensureIndex({\"orgCode\": 1, \"_id\": -1},{background:true});","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"犯的錯誤一模一樣,所以","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MongoDB","attrs":{}}],"attrs":{}},{"type":"text","text":"放棄了複合索引的使用,該爲單列索引,因此進行鍼對性修改,把 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"$lt","attrs":{}}],"attrs":{}},{"type":"text","text":" 條件改爲 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"$gt","attrs":{}}],"attrs":{}},{"type":"text","text":" 觀察優化結果:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"bash"},"content":[{"type":"text","text":"# 原始查詢\n[TEMP INDEX] => lt: {\"limit\":1000,\"queryObject\":{\"_id\":{\"$lt\":2039180008},\"categoryId\":23372,\"orgCode\":351414,\"fixedStatus\":{\"$in\":[1,2]}},\"restrictedTypes\":[],\"skip\":0,\"sortObject\":{\"_id\":-1}}\n\n# 原始耗時\n[TEMP LT] => 超時 (超時時間10s)\n\n# 優化後查詢\n[TEMP INDEX] => gt: {\"limit\":1000,\"queryObject\":{\"_id\":{\"$gt\":2039180008},\"categoryId\":23372,\"orgCode\":351414,\"fixedStatus\":{\"$in\":[1,2]}},\"restrictedTypes\":[],\"skip\":0,\"sortObject\":{\"_id\":-1}}\n\n# 優化後耗時\n[TEMP GT] => 耗時: 383ms , List Size: 999","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分析了小2000字,其實改動就是兩個字符而已,當然真正的改動需要考慮業務的需要,但是問題既然已經定位,修改什麼的就不難了,回顧上述內容總結如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"學習數據庫知識的時候可以用類比的方式,但是需要額外注意其不同的地方(MySQL、MongoDB索引、索引的方向)","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MongoDB數據庫單列索引可以不在乎方向,如對無索引字段排序需要控制數據量級(32M)","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"MongoDB數據庫複合索引在使用中一定要注意其方向","attrs":{}}],"attrs":{}},{"type":"text","text":",要完全理解其邏輯,避免索引失效","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"最後","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你覺得這篇內容對你挺有幫助的話:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":" 當然要點贊支持一下啦~","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":" 搜索並關注公衆號「","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"是Kerwin啊","attrs":{}},{"type":"text","text":"」,一起嘮嘮嗑~","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":" 再來看看最近幾篇的「","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"查漏補缺","attrs":{}},{"type":"text","text":"」系列吧,該系列會持續輸出~","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - ","attrs":{}},{"type":"link","attrs":{"href":"https://juejin.cn/post/6870264679063617550","title":""},"content":[{"type":"text","text":"「查缺補漏」鞏固你的Nginx知識體系","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - ","attrs":{}},{"type":"link","attrs":{"href":"https://juejin.cn/post/6862865811137101837","title":""},"content":[{"type":"text","text":"「查缺補漏」鞏固你的RocketMQ知識體系","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - ","attrs":{}},{"type":"link","attrs":{"href":"https://juejin.cn/post/6857667542652190728","title":""},"content":[{"type":"text","text":"「查缺補漏」鞏固你的Redis知識體系(笑)","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" - ","attrs":{}},{"type":"link","attrs":{"href":"https://juejin.cn/post/6860262796618268680","title":""},"content":[{"type":"text","text":"悄咪咪提高團隊幸福感 & Surprise!","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章