日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot mongo查询固定字段_你真的会用索引么?[Mongo]

發布時間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot mongo查询固定字段_你真的会用索引么?[Mongo] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一次奇怪的查詢經歷

如何奇怪了?

  • 對同一張表,用同樣的SQL,查詢200萬條數據耗時100ms,查詢二十條數據卻耗時30s。
  • 數據量少了10萬倍,完全不是一個數量級的數據,耗時卻多了300倍。
  • 明明加了索引為什么還是那么慢?

下圖是在本地簡化模擬出來的查詢結果,雖然沒有那么夸張但是同樣可以復現問題。

95.6萬條數據,用時0.08秒

106條數據,用時10秒

如上二圖,通過相同查詢條件以及相同的排序條件,進行查詢,查詢效率缺卻天差地別,下面讓我們來一起探索一下究竟是為什么?

索引概述

我們常常會看到一些亂七八糟的索引,所以我們用索引的真正目的是什么呢?

終極目的:借助索引快速搜索,有效減少了掃描的行數

精髓:不止要有索引,索引的過濾性還要好,區分度要足夠高,這才是好的設計

索引的類型和屬性

唯一索引

唯一索引是索引具有的一種屬性,讓索引具備唯一性,確保這張表中,該條索引數據不會重復出現。在每一次insert和update操作時,都會進行索引的唯一性校驗,保證該索引的字段組合在表中唯一。

db.containers.createIndex({name: 1},{unique:true, background: true}) db.packages.createIndex({ appId: 1, version: 1 },{unique:true, background: true}) 知識點一:創建索引時,1表示按升序存儲,-1表示按降序存儲。知識點二:Mongo提供兩種建索引的方式foreground和background。前臺操作,它會阻塞用戶對數據的讀寫操作直到index構建完畢;后臺模式,不阻塞數據讀寫操作,獨立的后臺線程異步構建索引,此時仍然允許對數據的讀寫操作。創建索引時一定要寫{background: true}創建索引時一定要寫{background: true}創建索引時一定要寫{background: true}

復合索引

概念:指的是將多個鍵組合到一起創建索引,終極目的是加速匹配多個鍵的查詢。

看例子來理解復合索引是最直接的方式:

圖中模擬了簡單的航班信息表的數據。

對表中指定航班進行查詢,查詢后按價格排序。

db.getCollection('flight').find({flight: “CA12345”}).sort({price: 1})

在沒有索引的情況下,那么他其實是會一條一條的掃描全部8條數據,找到CA12345航班,然后再在內存中按價錢進行排序。

如果這時我給航班添加一條索引db.flights.createIndex({ flight: 1 },{background: true}),那么索引會類似于下圖一樣,將數據按照索引規則進行排序,此時就只需要掃描4條CA12345航班的數據,然后再在內存中進行排序。如果數據量大了以后,在內存中進行排序的代價是非常大的。

所以我們可以建立復合索引 db.flights.createIndex({ flight: 1, price: 1 },{background: true})

讓數據按照索引先將所有數據以航班號有序排列,再在航班號相同的數據集中按價格升序排列,這樣在進行查詢的時候,就可以準確的使用索引掃描4條數據,并且他們本身就是有序的,無需再進行額外的排序工作。以上實現了通過復合索引,讓查詢變得最優,這就是復合索引的作用。

內嵌索引

可以在嵌套的文檔上建立索引,方式與建立正常索引完全一致。

個人信息表結構如下,包含了省市區三級的地址信息,如果想要給城市(city)添加索引,其實就和正常添索引一樣

db.personInfos.createIndex({“address.city”:1})

const personInfo = new Schema({name: { type: String, required: true },address: {province: { type: String, required: true },city: { type: String, required: true }, district: { type: String, required: true },} }, {timestamps: true});知識點三:
對嵌套文檔本身“address”建立索引,與對嵌套文檔的某個字段(address.city)建立索引是完全不相同的。
對整個文檔建立索引,只有在使用文檔完整匹配時才會使用到這個索引,例如建立了這樣一個索引db.personInfos.createIndex({“address”:1}),那么只有使用db.personInfos.find({“address”:{“province”:”xxx”,”city”:”xxx”,""district":"xxx"}})這種完整匹配時才會使用到這個索引,使用db.personInfos.find({“address.city”:”xxx”})是不會使用到該索引的。

數組索引

MongoDB支持對數組建立索引,這樣就可以高效的搜索數組中的特定元素。

知識點四:
但是!對數組建立索引的代價是非常高的,他實際上是會對數組中的每一項都單獨建立索引,就相當于假設數組中有十項,那么就會在原基礎上,多出十倍的索引大小。如果有一百個一千個呢?
所以在mongo中是禁止對兩個數組添加復合索引的,對兩個數組添加索引那么索引大小將是爆炸增長,所以謹記在心。

過期索引(TTL)

可以針對某個時間字段,指定文檔的過期時間(經過指定時間后過期 或 在某個時間點過期)

哈希索引(Hashed Index)

是指按照某個字段的hash值來建立索引,hash索引只能滿足字段完全匹配的查詢,不能滿足范圍查詢等

地理位置索引(Geospatial Index)

能很好的解決一些場景,比如『查找附近的美食』、『查找附近的加油站』等

文本索引(Text Index)

能解決快速文本查找的需求,比如,日志平臺,相對日志關鍵詞查找,如果通過正則來查找的話效率極低,這時就可以通過文本索引的形式來進行查找

索引的優點

1.減少數據掃描:避免全表掃描代價

2.減少內存計算:避免分組排序計算

3.提供數據約束:唯一和時間約束性

索引的缺點

1.增加容量消耗:創建時需額外存儲索引數據

2.增加修改代價:增刪改都需要維護索引數據

3.索引依賴內存:會占用極其寶貴的內存資源

索引固然不全是優點,如果不能了解到索引可能帶來的危害濫用索引,后果也是非常嚴重的。

索引雖然也是持久化在磁盤中的,但為了確保索引的速度,實際上需要將索引加載到內存中使用,使用過后還會進行緩存,內存資源相比磁盤空間那是非常的珍貴了。當內存不足以承載索引的時候,就會出現內存——磁盤交換的情況,這時會大大降低索引的性能。

有人說研究索引好累啊?我給我的每個字段都加一個索引不就完事了么?其實每個人都知道這樣不好,但實戰中好多人都是這樣干的。無腦的給每個字段都加上索引就意味著每一次數據庫操作,不僅需要更新文檔,還需要有大量索引需要更新。mongo每次查詢只會使用一個索引。想不到吧?不是你想的我先查航班,在用價格排序,會先走航班的索引,再走價格的索引,你做夢去吧,不可能的,他只會選定一條索引,并不會因為你給每個字端都加了索引就解決問題了。

知識點五:為了追求索引的速度,索引是加載在內存中使用的,不能合理使用索引后果嚴重。mongo每次查詢只會使用一次索引!!!只有$or或查詢特殊,他會給每一個或分支使用索引然后再合并

何時不應該使用索引

也有一些查詢不使用索引會更快。結果集在原集合中所占的比例越大,查詢效率越慢。因為使用索引需要進行兩次查找:一次查找索引條目,一次根據索引指針去查找相應的文檔。而全表掃描只需要進行一次查詢。在最壞的情況,使用索引進行查找次數會是全表掃描的兩倍。效率會明顯比全表掃描低。

而相反在提取較小的子數據集時,索引就非常有效,這就是我們為什么會使用分頁。

查詢優化器

Mongo自帶了一個查詢優化器會為我們選擇最合適的查詢方案。

如果一個索引能夠精確匹配一個查詢,那么查詢優化器就會使用這個索引。

如果不能精確匹配呢?可能會有幾個索引都適合你的查詢,那MongoDB是怎樣選擇的呢?

  • MongoDB的查詢計劃會將多個索引并行的去執行,最先返回第101個結果的就是勝者,其他查詢計劃都會被終止,執行優勝的查詢計劃;
  • 這個查詢計劃會被緩存,接下來相同的查詢條件都會使用它;

何時查詢計劃緩存才會變呢?

  • 在計劃評估之后表發生了比較大的數據波動,查詢優化器就會重新挑選可行的查詢計劃
  • 建立索引時
  • 每執行1000次查詢之后,查詢優化器就會重新評估查詢計劃
  • 聯合索引的優化

    當你查詢條件的順序和你索引的順序不一致的話,mongo會自動的調整查詢順序,保證你可以使用上索引。

    例如:你的查詢條件是(a,c,b)但是你的索引是(a,b,c)mongo會自動將你的查詢條件調整為abc,尋找最優解。

    聚合管道的優化

  • 如果管道中不需要使用一個完整的文檔的全部字段的話,管道不會將多余字段進行傳遞
  • $sort 和 $limit 合并,在內存中只會維護limit個數量的文檔,不需要將所有的文檔維護在內存中,大大降低內存中sort的壓力
  • 然而管道中的索引使用情況是極其不佳的,在管道中,只有在管道最開始時的match sort可以使用到索引,一旦發生過project投射,group分組,lookup表關聯,unwind打散等操作后,就完全無法使用索引。

    希望通過本文能讓你對Mongo的索引有更深的理解

    Explain查詢計劃

    提到查的慢,二話不說直接看查詢計劃好么?具體每一個字段的含義我就不做贅述了很容易查到,我截取winningPlan的部分和大家一起看一下。WinningPlan就是在查詢計劃中勝出的方案,那肯定就有被淘汰的方案,是在rejectPlan里。

    // 查詢計劃中的winningPlan部分 "winningPlan": {"stage": "FETCH","filter": {"createdAt": {"$gte": ISODate("2019-07-22T12:00:44.000Z")}},"inputStage": {"stage": "IXSCAN","keyPattern": {"load": 1},"indexName": "load_1","isMultiKey": false,"multiKeyPaths": {"load": []},"isUnique": false,"isSparse": false,"isPartial": false,"indexVersion": 2,"direction": "backward","indexBounds": {"load": ["[MaxKey, MinKey]"]}} },

    看不懂?沒關系,先學習了下面兩個知識點,我帶你讀一遍。

    知識點六:explain 結果將查詢計劃以階段樹的形式呈現。每個階段將其結果(文檔或索引鍵)傳遞給父節點。中間節點操縱由子節點產生的文檔或索引鍵。根節點是MongoDB從中派生結果集的最后階段。

    對于新人一定要特別注意:在看查詢結果的階段樹的時候一定一定是從最里層一層一層往外看的,不是直接順著讀下來的。

    知識點七:在查詢計劃中出現了很多stage,下面列舉的經常出現的stage以及他的含義:COLLSCAN:全表掃描IXSCAN:索引掃描FETCH:根據前面掃描到的位置抓取完整文檔SORT:進行內存排序,最終返回結果SORT_KEY_GENERATOR:獲取每一個文檔排序所用的鍵值LIMIT:使用limit限制返回數SKIP:使用skip進行跳過IDHACK:針對_id進行查詢COUNTSCAN:count不使用用Index進行count時的stage返回COUNT_SCAN:count使用了Index進行count時的stage返回TEXT:使用全文索引進行查詢時候的stage返回

    Explain解讀:

    將解讀寫在了注釋中,按順序閱讀

    // 查詢計劃中的winningPlan部分 "winningPlan": {"stage": "FETCH", // 5. 根據內層階段樹查到的索引去抓取完整的文檔"filter": { // 6. 再根據createdAt參數進行篩選"createdAt": {"$gte": ISODate("2019-07-22T12:00:44.000Z")}},"inputStage": { // 1. 每個階段將自己的查詢結果傳遞給父階段樹,所以從里往外讀Explain"stage": "IXSCAN", // 2. IXSCAN該階段使用了索引進行掃描"keyPattern": {"load": 1 // 3. 使用了 load:1 這條索引},"indexName": "load_1","isMultiKey": false,"multiKeyPaths": {"load": []},"isUnique": false,"isSparse": false,"isPartial": false,"indexVersion": 2,"direction": "backward", "indexBounds": {"load": ["[MaxKey, MinKey]" // 4. 邊界]}} },

    最后在本文末尾,留下了前面查詢航班按價錢排序的例子,在各種索引下的查詢計劃

    最期望看到的查詢組合

    • Fetch+IDHACK
    • Fetch+ixscan
    • Limit+(Fetch+ixscan)
    • PROJECTION+ixscan

    最不期望看到的查詢組合

    • COLLSCAN(全表掃)
    • SORT(使用sort但是無index)
    • COUNTSCAN (不使用索引進行count)

    最左前綴原則

    假定索引(a,b,c) 它可能滿足的查詢如下:

    1. a

    2. a,b

    3. a,b,c

    4. a,c [該組合只能用a部分]

    5. a, c, b [cb在查詢時會被優化換位置]

    顯然,最左前綴的核心是查詢條件字段必須含有索引第一個字段

    最左值盡可能用最精確過濾性最好的值,不要用那種可能會用于范圍模糊查詢,用于排序的字段

    效率極低的操作符

  • $where和$exists:這兩個操作符,完全不能使用索引。
  • $ne和$not:通常來說取反和不等于,可以使用索引,但是效率極低,不是很有效,往往也會退化成掃描全表。
  • $nin:不包含,這個操作符也總是會全表掃描
  • 對于管道中的索引,也很容易出現意外,只有在管道最開始時的match sort可以使用到索引,一旦發生過project投射,group分組,lookup表關聯,unwind打散等操作后,就完全無法使用索引。
  • 索引設計和優化原則

    最后祭出李丹老師的索引設計和優化原則

    1.主鍵的設置

    業務無關、顯示指定、遞增屬性

    2.數據區分度

    原則上區分度高的字段優先做索引字段,如果是組合索引優先放前面

    3.字段更新頻率

    頻繁更新的字段是否做索引字段需要綜合考慮對業務的影響及查詢的代價

    4.前綴索引問題

    需要注意的是因前綴索引只包含部分值因此無法通過前綴索引優化排序

    5.適當冗余設計

    對于存儲較長字符串字段可額外增加字段存儲原字段計算(如hash)后的值

    創建索引時只需要對額外字段創建索引即可

    6.避免無效索引

    通常類似表已經含有主鍵ID就無需再創建額外唯一性的ID索引

    7.查詢覆蓋率

    設計一個索引我們需要考慮盡量覆蓋更多的查詢場景

    8.控制字段數

    如果你設計的索引例如含有7、8個字段通常需要考慮設計是否合理

    優化原則

    1.減少網絡帶寬

    按需返回所需字段、盡量避免返回大字段

    2.減少內存計算

    減少無必要中間結果存儲、減少內存計算

    3.減少磁盤IO

    添加合適的索引、關注SQL改寫

    前文查詢航班按價錢排序的例子,在各種索引下的查詢計劃

    表中的四條數據

    查詢語句以及查看explain的語句

    無索引

    給timeStamp加索引

    刪除timeStamp索引給price加索引

    同時給timeStamp和price加單索引

    創建timeStamp和price的聯合索引

    創建price和timeStamp的聯合索引

    總結

    以上是生活随笔為你收集整理的springboot mongo查询固定字段_你真的会用索引么?[Mongo]的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产精品一区二区在线 | 日韩高清不卡一区 | 色综合天天综合网天天狠天天 | 不卡的av网站 | 国产ts三人妖大战直男 | 五月婷婷基地 | 亚洲男同视频 | 中国性xxx| 久久久久人妻精品色欧美 | 亚洲中文字幕无码专区 | 欧美黄频 | 欧美另类人妖 | 97公开视频 | 欧美一区二区三区大屁股撅起来 | jzzijzzij亚洲成熟少妇 | 日韩精品视频中文字幕 | 日本精品一区二区三区视频 | 欧美人喂奶吃大乳 | 国产偷人爽久久久久久老妇app | 日本www色 | 日本欧美久久久 | 无码播放一区二区三区 | 午夜插插插 | 色妞av | 蜜桃99视频一区二区三区 | 亚洲69av| 国产人妻777人伦精品hd | 2017日日夜夜 | 欧美在线视频你懂的 | 日日草草 | 久热这里只有 | 国产午夜成人久久无码一区二区 | 久久资源365| 成人片黄网站久久久免费 | 精品人妻一区二区三区蜜桃 | 亚洲乱妇老熟女爽到高潮的片 | 青娱乐福利视频 | 麻豆www | 国产21区 | 国产精品高潮呻吟av | 久久国产秒 | se94se欧美| 天美麻花果冻视频大全英文版 | 国产精品色婷婷99久久精品 | 天天色综合图片 | 国产精品人成 | 午夜在线观看视频18 | 成人在线网站 | 成熟女人毛片www免费版在线 | 精品国产乱码久久久久久牛牛 | 国产午夜三级 | 国产一区二区在线免费 | 91福利网站 | 欧洲一区二区三区四区 | 自拍偷拍亚洲综合 | 少妇床戏av | 久久狠 | 国产做爰高潮呻吟视频 | 91蜜桃在线观看 | 欧美一级黄色录像 | 制服丝袜第一页在线观看 | 99在线视频播放 | 欧美色图888| 青青青青青操 | 成人久久久| 撸撸在线视频 | 欧美激情亚洲色图 | 国产h在线| 亚洲香蕉在线观看 | 激情五月开心婷婷 | 精品久久久99 | 国产精品免费看久久久无码 | 精品国产aⅴ麻豆 | 色羞羞 | 欧美日韩国产麻豆 | 精品少妇人妻av免费久久洗澡 | 亚欧成人 | 18视频在线观看网站 | 国产一区二区啪啪啪 | 91在线看视频 | 偷偷操av| 毛片在线播放视频 | 欧美精品一区二区三区四区五区 | 日韩精品一区中文字幕 | 六月婷婷激情网 | 香蕉成人在线视频 | 日本天天色 | 探花国产在线 | 欧美精品久久久久久久多人混战 | 午夜视频福利 | 欧美日韩国产一区二区三区在线观看 | 欧美三级视频 | 国产黄色高清 | 国内自拍在线 | 日韩欧美国产电影 | 欧美极品一区二区三区 | 1024毛片| 成人免费播放 | 婷婷午夜影院 |