欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MongoDB索引使用詳解

 更新時(shí)間:2016年01月15日 10:24:15   投稿:hebedich  
索引,使用索引可快速訪問數(shù)據(jù)庫(kù)表中的特定信息。索引是對(duì)數(shù)據(jù)庫(kù)表中一列或多列的值進(jìn)行排序的一種結(jié)構(gòu),例如 employee 表的姓名(name)列。如果要按姓查找特定職員,與必須搜索表中的所有行相比,索引會(huì)幫助您更快地獲得該信息。

索引就像書的目錄,如果查找某內(nèi)容在沒有目錄的幫助下,只能全篇查找翻閱,這導(dǎo)致效率非常的低下;如果在借助目錄情況下,就能很快的定位具體內(nèi)容所在區(qū)域,效率會(huì)直線提高。

索引簡(jiǎn)介

首先打開命令行,輸入mongo。默認(rèn)mongodb會(huì)連接名為test的數(shù)據(jù)庫(kù)。

➜ ~ mongo
MongoDB shell version: 2.4.9
connecting to: test
> show collections
> 

可以使用show collections/tables查看數(shù)據(jù)庫(kù)為空。

然后在mongodb命令行終端執(zhí)行如下代碼

> for(var i=0;i<100000;i++) {
... db.users.insert({username:'user'+i})
... }
> show collections
system.indexes
users
> 

再查看數(shù)據(jù)庫(kù)發(fā)現(xiàn)多了system.indexes 和 users兩個(gè)表,前者即所謂的索引,后者為新建的數(shù)據(jù)庫(kù)表。
這樣user表中即有了10萬條數(shù)據(jù)。

> db.users.find()
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e4"), "username" : "user0" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e5"), "username" : "user1" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e6"), "username" : "user2" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e7"), "username" : "user3" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e8"), "username" : "user4" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e9"), "username" : "user5" }

現(xiàn)在需要查找其中任意一條數(shù)據(jù),比如

> db.users.find({username: 'user1234'})
{ "_id" : ObjectId("5694d5db8fad9e319c5b48b6"), "username" : "user1234" }

發(fā)現(xiàn)這條數(shù)據(jù)成功找到,但需要了解詳細(xì)信息,需要加上explain方法

> db.users.find({username: 'user1234'}).explain()
{
  "cursor" : "BasicCursor",
  "isMultiKey" : false,
  "n" : 1,
  "nscannedObjects" : 100000,
  "nscanned" : 100000,
  "nscannedObjectsAllPlans" : 100000,
  "nscannedAllPlans" : 100000,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 30,
  "indexBounds" : {
    
  },
  "server" : "root:27017"
}

參數(shù)很多,目前我們只關(guān)注其中的"nscanned" : 100000和"millis" : 30這兩項(xiàng)。

nscanned表示mongodb在完成這個(gè)查詢過程中掃描的文檔總數(shù)??梢园l(fā)現(xiàn),集合中的每個(gè)文檔都被掃描了,并且總時(shí)間為30毫秒。

如果數(shù)據(jù)有1000萬個(gè),如果每次查詢文檔都遍歷一遍。呃,時(shí)間也是相當(dāng)可觀。

對(duì)于此類查詢,索引是一個(gè)非常好的解決方案。

> db.users.ensureIndex({"username": 1})

然后再查找user1234

> db.users.ensureIndex({"username": 1})
> db.users.find({username: 'user1234'}).explain()
{
  "cursor" : "BtreeCursor username_1",
  "isMultiKey" : false,
  "n" : 1,
  "nscannedObjects" : 1,
  "nscanned" : 1,
  "nscannedObjectsAllPlans" : 1,
  "nscannedAllPlans" : 1,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 0,
  "indexBounds" : {
    "username" : [
      [
        "user1234",
        "user1234"
      ]
    ]
  },
  "server" : "root:27017"
}

的確有點(diǎn)不可思議,查詢?cè)谒查g完成,因?yàn)橥ㄟ^索引只查找了一條數(shù)據(jù),而不是100000條。

當(dāng)然使用索引是也是有代價(jià)的:對(duì)于添加的每一條索引,每次寫操作(插入、更新、刪除)都將耗費(fèi)更多的時(shí)間。這是因?yàn)?,?dāng)數(shù)據(jù)發(fā)生變化時(shí),不僅要更新文檔,還要更新級(jí)集合上的所有索引。因此,mongodb限制每個(gè)集合最多有64個(gè)索引。通常,在一個(gè)特定的集合上,不應(yīng)該擁有兩個(gè)以上的索引。

小技巧

如果一個(gè)非常通用的查詢,或者這個(gè)查詢?cè)斐闪诵阅芷款i,那么在某字段(比如username)建立索引是非常好的選擇。但只是給管理員用的查詢(不太在意查詢耗費(fèi)時(shí)間),就不該對(duì)這個(gè)字段建立索引。

復(fù)合索引

索引的值是按一定順序排列的,所以使用索引鍵對(duì)文檔進(jìn)行排序非常快。

db.users.find().sort({'age': 1, 'username': 1})

這里先根據(jù)age排序再根據(jù)username排序,所以u(píng)sername在這里發(fā)揮的作用并不大。為了優(yōu)化這個(gè)排序,可能需要在age和username上建立索引。

db.users.ensureIndex({'age':1, 'username': 1})
這就建立了一個(gè)復(fù)合索引(建立在多個(gè)字段上的索引),如果查詢條件包括多個(gè)鍵,這個(gè)索引就非常有用。

建立復(fù)合索引后,每個(gè)索引條目都包括一個(gè)age字段和一個(gè)username字段,并且指向文檔在磁盤上的存儲(chǔ)位置。
此時(shí),age字段是嚴(yán)格升序排列的,如果age相等時(shí)再按照username升序排列。

查詢方式

點(diǎn)查詢(point query)

用于查詢單個(gè)值(盡管包含這個(gè)值的文檔可能有多個(gè))

db.users.find({'age': 21}).sort({'username': -1})

因?yàn)槲覀円呀?jīng)建立好復(fù)合索引,一個(gè)age一個(gè)username,建立索引時(shí)使用的是升序排序(即數(shù)字1),當(dāng)使用點(diǎn)查詢查找{age:21},假設(shè)仍然是10萬條數(shù)據(jù),可能年齡是21的很多人,因此會(huì)找到不只一條數(shù)據(jù)。然后sort({'username': -1})會(huì)對(duì)這些數(shù)據(jù)進(jìn)行逆序排序,本意是這樣。但我們不要忘記建立索引時(shí)'username':1是升序(從小到大),如果想得到逆序只要對(duì)數(shù)據(jù)從最后一個(gè)索引開始,依次遍歷即可得到想要的結(jié)果。

排序方向并不重要,mongodb可以從任意方向?qū)λ饕M(jìn)行遍歷。
綜上,復(fù)合索引在點(diǎn)查詢這種情況非常高效,直接定位年齡,不需要對(duì)結(jié)果進(jìn)行排序,返回結(jié)果。

多值查詢(multi-value-query)

db.users.find({'age': {"$gte": 21, "$lte": 30}})

查找多個(gè)值相匹配的文檔。多值查詢也可以理解為多個(gè)點(diǎn)查詢。
如上,要查找年齡介于21到30之間。monogdb會(huì)使用索引的中的第一個(gè)鍵"age"得到匹配的結(jié)果,而結(jié)果通常是按照索引順序排列的。

db.users.find({'age': {"$gte": 21, "$lte": 30}}).sort({'username': 1})

與上一個(gè)類似,這次需要對(duì)結(jié)果排序。
在沒有sort時(shí),我們查詢的結(jié)果首先是根據(jù)age等于21,age等于22..這樣從小到大排序,當(dāng)age等于21有多個(gè)時(shí),在進(jìn)行usernameA-Z(0-9)這樣排序。所以,sort({'username': 1}),要將所有結(jié)果通過名字升序排列,這次不得不先在內(nèi)存中進(jìn)行排序,然后返回。效率不如上一個(gè)高。

當(dāng)然,在文檔非常少的情況,排序也花費(fèi)不了多少時(shí)間。
如果結(jié)果集很大,比如超過32MB,MongoDB會(huì)拒絕對(duì)如此多的數(shù)據(jù)進(jìn)行排序工作。

還有另外一種解決方案

也可以建立另外一個(gè)索引{'username': 1, 'age': 1}, 如果先對(duì)username建立索引,當(dāng)再sortusername,相當(dāng)沒有進(jìn)行排序。但是需要在整個(gè)文檔查找age等于21的帥哥美女,所以搜尋時(shí)間就長(zhǎng)了。

但哪個(gè)效率更高呢?

如果建立多個(gè)索引,如何選擇使用哪個(gè)呢?
效率高低是分情況的,如果在沒有限制的情況下,不用進(jìn)行排序但需要搜索整個(gè)集合時(shí)間會(huì)遠(yuǎn)超過前者。但是在返回部分?jǐn)?shù)據(jù)(比如limit(1000)),新的贏家就產(chǎn)生了。

>db.users.find({'age': {"$gte": 21, "$lte": 30}}).
sort({username': 1}).
limit(1000).
hint({'age': 1, 'username': 1})
explain()['millis']
2031ms

>db.users.find({'age': {"$gte": 21, "$lte": 30}}).
sort({username': 1}).
limit(1000).
hint({'username': 1, 'age': 1}).
explain()['millis']
181ms

其中可以使用hint指定要使用的索引。
所以這種方式還是很有優(yōu)勢(shì)的。比如一般場(chǎng)景下,我們不會(huì)把所有的數(shù)據(jù)都取出來,只是去查詢最近的,所以這種效率也會(huì)更高。

索引類型

唯一索引

可以確保集合的每個(gè)文檔的指定鍵都有唯一值。

db.users.ensureIndex({'username': 1, unique: true})
比如使用mongoose框架,在定義schema時(shí),即可指定unique: true.
如果插入2個(gè)相同都叫張三的數(shù)據(jù),第二次插入的則會(huì)失敗。_id即為唯一索引,并且不能刪除。

稀疏索引

使用sparse可以創(chuàng)建稀疏索引

>db.users.ensureIndex({'email': 1}, {'unique': true, 'sparse': true})

索引管理

system.indexes集合中包含了每個(gè)索引的詳細(xì)信息

db.system.indexes.find()

1.ensureIndex()創(chuàng)建索引

db.users.ensureIndex({'username': 1})
后臺(tái)創(chuàng)建索引,這樣數(shù)據(jù)庫(kù)再創(chuàng)建索引的同時(shí),仍然能夠處理讀寫請(qǐng)求,可以指定background選項(xiàng)。

db.test.ensureIndex({"username":1},{"background":true})

2.getIndexes()查看索引

db.collectionName.getIndexes()
db.users.getIndexes()
[
  {
    "v" : 1,
    "key" : {
      "_id" : 1
    },
    "ns" : "test.users",
    "name" : "_id_"
  },
  {
    "v" : 1,
    "key" : {
      "username" : 1
    },
    "ns" : "test.users",
    "name" : "username_1"
  }
]

其中v字段只在內(nèi)部使用,用于標(biāo)識(shí)索引版本。

3.dropIndex刪除索引

> db.users.dropIndex("username_1")
{ "nIndexesWas" : 2, "ok" : 1 }

全選復(fù)制放進(jìn)筆記> db.users.dropIndex({"username":1})

相關(guān)文章

  • CentOS 6.5系統(tǒng)中使用yum安裝MongoDB 2.6 教程

    CentOS 6.5系統(tǒng)中使用yum安裝MongoDB 2.6 教程

    這篇文章主要介紹了CentOS 6.5系統(tǒng)中使用yum安裝MongoDB 2.6 教程,本文共分5個(gè)步驟完成MongoDB的安裝,需要的朋友可以參考下
    2015-01-01
  • 批量備份還原導(dǎo)入與導(dǎo)出MongoDB數(shù)據(jù)方式

    批量備份還原導(dǎo)入與導(dǎo)出MongoDB數(shù)據(jù)方式

    前面我們介紹了mongoDB的安裝與配置,接下來我們講一講如何使用mongo的可視化工具Navicat對(duì)mongo數(shù)據(jù)庫(kù)進(jìn)行操作和如何在終端進(jìn)行mongo數(shù)據(jù)庫(kù)對(duì)數(shù)據(jù)的批量操作
    2021-09-09
  • MongoDB 事務(wù)支持詳解

    MongoDB 事務(wù)支持詳解

    這篇文章主要介紹了MongoDB 事務(wù)支持詳解的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • MongoDB使用小結(jié):一些不常見的經(jīng)驗(yàn)分享

    MongoDB使用小結(jié):一些不常見的經(jīng)驗(yàn)分享

    最近一年忙碌于數(shù)據(jù)處理相關(guān)的工作,跟MongoDB打交道極多,以下為實(shí)踐過程中的Q&A,后續(xù)會(huì)不定期更新補(bǔ)充
    2017-03-03
  • MongoDB與MySQL常用操作語句對(duì)照

    MongoDB與MySQL常用操作語句對(duì)照

    這篇文章主要介紹了MongoDB與MySQL常用操作語句對(duì)照,本文整合了兩篇博文,相信最常用的操作都收錄在本文了,需要的朋友可以參考下
    2015-05-05
  • MongoDB通過查詢與游標(biāo)徹底玩轉(zhuǎn)分布式文件存儲(chǔ)

    MongoDB通過查詢與游標(biāo)徹底玩轉(zhuǎn)分布式文件存儲(chǔ)

    MongoDB最大的特點(diǎn)是它支持的查詢語言非常強(qiáng)大,其語法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫(kù)單表查詢的絕大部分功能,而且還支持對(duì)數(shù)據(jù)建立索引,這篇文章主要介紹了MongoDB查詢與游標(biāo),徹底玩轉(zhuǎn)分布式文件存儲(chǔ),需要的朋友可以參考下
    2023-01-01
  • MongoDB插入、更新、刪除文檔實(shí)現(xiàn)代碼

    MongoDB插入、更新、刪除文檔實(shí)現(xiàn)代碼

    本文通過實(shí)例代碼給大家簡(jiǎn)單介紹了mongodb插入、更新、刪除文檔的方法,需要的的朋友參考下吧
    2017-04-04
  • mongodb增刪改查詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    mongodb增刪改查詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了mongodb增刪改查詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • MongoDB中常用操作$addToSet、$pop和$rename

    MongoDB中常用操作$addToSet、$pop和$rename

    本文主要介紹了MongoDB中常用操作$addToSet、$pop和$rename,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • mongoDB中聚合函數(shù)java處理示例詳解

    mongoDB中聚合函數(shù)java處理示例詳解

    這篇文章主要給大家介紹了關(guān)于mongoDB中聚合函數(shù)java處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mongoDB具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論