關於mongodb的學習與探索一

前言

什麼是mongodb?MongoDB 是由C++語言編寫的,是一個基於分佈式文件存儲的開源數據庫系統。MongoDB 將數據存儲爲一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔相似於 JSON 對象。字段值能夠包含其餘文檔,數組及文檔數組。python

mongodb的基本用法

連接mongodb數據庫

在windows下,MongoDB 提供了可用於 32 位和 64 位系統的預編譯二進制包,你能夠從MongoDB官網下載安裝,MongoDB 預編譯二進制包下載地址:https://www.mongodb.com/download-center#community,安裝後自行搜索配置環境變量,其餘操做系統下也自行搜索安裝方法,如下操做默認已經配置好環境變量。git

  • 打開命令行工具,執行mongod --dbpath c:\data\db,這裏的路徑跟的是你本身設置的存儲mongodb數據的路徑。
  • 另開一個命令行工具,執行mongo,即進入mongodb命令窗口。

數據庫的基本操做經常使用命令

  • show dbs --顯示全部數據庫
  • use test --使用test數據庫
  • db.dropDatabase() --刪除當前所use的數據庫
  • show tables --顯示當前數據庫下全部集合
  • db.foo.insert({}) --向foo集合下插入數據
  • db.foo.find() --查詢foo集合下全部數據
  • db.foo.update({}) --更新數據
  • db.foo.remove({}) --刪除數據

find查詢

db.collection.find(query, projection)github

    • query :可選,使用查詢操做符指定查詢條件
    • projection:可選,使用投影操做符指定返回的鍵。查詢時返回文檔中全部鍵值, 只需省略該參數便可(默認省略)。

pretty() 方法以格式化的方式來顯示全部文檔。sql

db.collection.find(query, projection).pretty()mongodb

> db.col.find().pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程"
}
複製代碼

MongoDB一樣還支持條件語句查詢,如:數據庫

    • 等於 : { key : value }
    • 小於 : { key : { $lt : value } }
    • 小於或等於 : { key : { $lte : value } }
    • 大於 :{ key : { $gt : value } }
    • 大於或等於 : { key : { $gte : value } }
    • 不等於 : { key : { $ne : value } }

下面這個小例子表示查詢sort不等於50的數據,代碼以下所示:windows

> db.col.find({"sort":{$ne:50}}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "sort" : 20
}
複製代碼

find的條件中支持and和or查詢,也就是「並」與「或」的關係, find() 方法中傳入多個鍵(key),每一個鍵(key)以逗號隔開,表示and,or則是用數組包裹,下面直接上代碼。數組

> db.col.find({"likes": {$gt:50}, $or: [{"by": "MongoDB"},{"title": "MongoDB 教程"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一個 Nosql 數據庫",
        "by" : "MongoDB",
        "likes" : 100
}
複製代碼

下面咱們繼續討論MongoDB中條件操做符 $type,若是想獲取 "col" 集合中 title 爲 String 的數據,你可使用如下命令緩存

db.col.find({"title" : {$type : 2}})網絡

> db.col.find({"title" : {$type : 2}})
{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "likes" : 100 }
複製代碼

若是你須要在MongoDB中讀取指定數量的數據記錄,可使用MongoDB的Limit方法,limit()方法接受一個數字參數,該參數指定從MongoDB中讀取的記錄條數。

> db.col.find({},{"title":1,_id:0}).limit(2)
{ "title" : "PHP 教程" }
{ "title" : "Java 教程" }
複製代碼

咱們除了可使用limit()方法來讀取指定數量的數據外,還可使用skip()方法來跳過指定數量的數據,skip方法一樣接受一個數字參數做爲跳過的記錄條數。

>db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
{ "title" : "Java 教程" }
複製代碼

在MongoDB中使用使用sort()方法對數據進行排序,sort()方法能夠經過參數指定排序的字段,並使用 1 和 -1 來指定排序的方式,其中 1 爲升序排列,而-1是用於降序排列。

>db.col.find({},{"title":1,_id:0}).sort({"likes":-1})
{ "title" : "PHP 教程" }
{ "title" : "Java 教程" }
{ "title" : "MongoDB 教程" }
複製代碼

注意:當查詢時同時使用sort,skip,limit,不管位置前後,最早執行順序 sort再skip再limit。

MongoDB 索引

索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。

這種掃描全集合的查詢效率是很是低的,特別在處理大量的數據時,查詢能夠要花費幾十秒甚至幾分鐘,這對網站的性能是很是致命的。

索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構。

索引優勢:加快索引相關的查詢;

索引缺點:增長磁盤空間消耗,下降寫入性能。

索引的基本操做

getIndexes() =>查看索引

ensureIndex() =>建立索引

dropIndex("name_1") =>刪除索引

_id索引

_id索引是絕大多數集合默認創建的索引。對於每一個插入的數據,mongodb都會自動生成一條惟一的_id字段。如

>db.col.insert({"title":1})
{ "title" : "1","_id" : ObjectId("5a2de799328eaf1eb0af7849") }
複製代碼
單鍵索引

單鍵索引是最普通的索引,與_id索引不一樣,單鍵索引不會自動建立

>db.col.ensureIndex({"title":1})
複製代碼
多鍵索引

多鍵索引與單鍵索引建立形式相同,區別在於字段的值。單鍵索引,值爲一個單一的值,例如字符串、數字或者日期;多鍵索引的值具備多個記錄,例如數組。

>db.col.ensureIndex({"title":1})
複製代碼
複合索引

對多個鍵建立的索引,好比,須要對Mail的user與folderId建立降序索引:

>db.col.ensureIndex({"title":1."name": -1})
複製代碼
過時索引

過時索引是在一段時間後會過時的索引,在索引過時後,相應的數據會被刪除,這適合存儲一些在一段時間後會失效的數據好比用戶的登陸信息、存儲的日誌等。

>db.col.ensureIndex({"title":1}, { expireAfterSeconds:60 })
複製代碼

須要注意的是,過時索引會存在偏差,大概60s刷新一次;存儲在過時索引字段的值必須是指定的時間類型,不能是時間戳;若是指定了Date數組,則按照最小的時間進行刪除; 過時索引不能是複合索引。

全文索引

全文索引是對字符串與字符串數組建立全文可搜索的索引,使用狀況以下所示

{author: '', title: '', article: ''}

全文索引最經常使用的創建方法有三種,其中value必須是"text",對單個字段創建全文索引可選第一種,對多個字段可選第二種,對全部字段可選最後一種,其中要注意的是,在mongodb中只能存在一種全文索引。

db.col.ensureIndex({"key":"text"})

db.col.ensureIndex({"key1":"text","key2":"text"})

db.col.ensureIndex({"$**":"text"})

> db.col.ensureIndex({name:"text"})
> db.col.ensureIndex({name:"text",title:"text"})
> db.col.ensureIndex({"$**":"text"})
複製代碼

那麼如何使用全文索引查詢呢?

db.col.find({text:{search:"aaa"}}) =>查詢包含aaa

db.col.find({text:{search:"aaa bb"}}) =>查詢包含aaa或者包含bb

db.col.find({text:{search:"aaa bb -cc"}}) =>查詢包含aaa或者bb,可是不包含cc

db.col.find({text:{search:""aaa""bb""}}) =>查詢包含aaa和bb

> db.test.find({$text:{$search:"aa"}})
{ "_id" : ObjectId("5a321f7f071884f56c1baba4"), "name" : "aa bb cc" }
{ "_id" : ObjectId("5a321f83071884f56c1baba5"), "name" : "aa bb" } 
複製代碼

全文索引的另外一個黑科技,那就是全文索引類似度了,全文索引類似度指的是meta操做符:{score:{meta:"textScore"}}寫在查詢條件後面能夠返回結果的類似度,與sort一塊兒使用,能夠達到很好的效果。

> db.test.find({$text:{$search:"aa"}},{score:{$meta:"textScore"}})
{ "_id" : ObjectId("5a321f7f071884f56c1baba4"), "name" : "aa bb cc", "score" : 0.6666666666666666 }
{ "_id" : ObjectId("5a321f83071884f56c1baba5"), "name" : "aa bb", "score" : 0.75 }
複製代碼

全文索引雖然很是強大,可是一樣存在着一些限制,例如:每次查詢,只能指定一個text查詢;text查詢不能出如今nor查詢中;查詢中若是包含了text,hint再也不起做用。

地理位置索引

地理位置索引指的是將一些點的位置存儲在mongodb中,建立索引後,能夠按照位置來查找其餘的點。

地理位置索引分爲兩類,一種是2d索引表示平面地理位置索引,即用於存儲和查找平面上的點,另外一種是2dsphere索引表示球面地理位置索引,用於存儲和查找球面上的點。

查找方式也可大體分爲兩種:

1.查找距離某個點必定距離內的點;

2.查找包含在某區域內的點

下面咱們先來講說2d索引,建立方式以下所示:

db.col.ensureIndex({ w : "2d"})

位置表示方式:經緯度[經度,緯度]

取值範圍:經度[-180,180]緯度[-90,90]

查詢方式:

(1)near查詢:查詢距離某個點最近的點,默認返回一百個離我最近的點,可以使用maxDistance來限制最大範圍

> db.col.find({w:{$near:[1,1],$maxDistance:20}})
{ "_id" : ObjectId("5a32297d071884f56c1baba8"), "w" : [ 1, 1 ] }
{ "_id" : ObjectId("5a322981071884f56c1baba9"), "w" : [ 1, 11 ] }
{ "_id" : ObjectId("5a322986071884f56c1babaa"), "w" : [ 1, 21 ] }
複製代碼

(2)$geoWithin查詢:查詢某個形狀內的點,其中形狀的表示有如下幾種:

box:矩形,使用{box : [ [ x1, y1 ] , [ x2, y2 ] ] }

> db.col.find({ w:{$geoWithin:{$box:[ [1,1],[2,3] ]}} })
{ "_id" : ObjectId("5a32297d071884f56c1baba8"), "w" : [ 1, 1 ] }
複製代碼

center:圓形,使用{center: [[ x1, y1 ], r] }表示

> db.col.find({ w:{$geoWithin:{$center:[ [1,1],10 ]}} })
{ "_id" : ObjectId("5a32297d071884f56c1baba8"), "w" : [ 1, 1 ] }
{ "_id" : ObjectId("5a322981071884f56c1baba9"), "w" : [ 1, 11 ] }
複製代碼

polygon: 多邊形,使用{polygon: [ [ x1, y1 ], [ x2, y2 ], [ x3, y3 ] ] }表示

> db.col.find({ w:{$geoWithin:{$polygon:[ [1,1],[20,10],[6,20] ]}} })
{ "_id" : ObjectId("5a32297d071884f56c1baba8"), "w" : [ 1, 1 ] }
複製代碼

(3)geoNear查詢:geoNear使用runCommand命令進行使用,經常使用使用以下

db.runCommand( { geoNear: col, near: [x, y], minDistance: (對2d索引無效), maxDistancen: , num: 返回條數 } )

> db.runCommand({ geoNear: "col", near:[1,2], maxDistance: 10, num: 1 })
{
        "results" : [
                {
                        "dis" : 1,
                        "obj" : {
                                "_id" : ObjectId("5a32297d071884f56c1baba8"),
                                "w" : [
                                        1,
                                        1
                                ]
                        }
                }
        ],
        "stats" : {
                "nscanned" : 4,
                "objectsLoaded" : 1,
                "avgDistance" : 1,
                "maxDistance" : 1,
                "time" : 0
        },
        "ok" : 1
}
複製代碼

接着咱們來聊聊2dsphere索引,2dsphere表示球面地理位置索引,建立方式以下所示:

db.col.ensureIndex({ w: 2dsphere })

位置表示方式:GeoJSON:描述一個點,一條直線,多邊形等形狀。格式以下所示:

{ type: '', coordinates: [ coordinates ] }

查詢方式與2d索引查詢方式相似,而且支持$minDistance,這一塊的比較複雜,有興趣的小夥伴可自行搜索。

索引的經常使用屬性
Parameter Type Description
background Boolean 建索引過程會阻塞其它數據庫操做,background可指定之後臺方式建立索引,即增長 "background" 可選參數。 "background" 默認值爲false。
unique Boolean 創建的索引是否惟一。指定爲true建立惟一索引。默認值爲false.
name string 索引的名稱。若是未指定,MongoDB的經過鏈接索引的字段名和排序順序生成一個索引名稱。
dropDups Boolean 在創建惟一索引時是否刪除重複記錄,指定 true 建立惟一索引。默認值爲 false.
sparse Boolean 對文檔中不存在的字段數據不啓用索引;這個參數須要特別注意,若是設置爲true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值爲 false.
expireAfterSeconds integer 指定一個以秒爲單位的數值,完成 TTL設定,設定集合的生存時間
v index version 索引的版本號。默認的索引版本取決於mongod建立索引時運行的版本。
weights document 索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其餘索引字段的得分權重。
索引構建狀況分析

索引的好處:加快索引相關的查詢。

索引的弊端:增長磁盤空間消耗,下降寫入性能。 可經過如下四種途徑來評判當前索引構建狀況:

(1)mongostat工具

此工具是mongodb自帶的一個檢測工具,提供了關於mongod和mongos的當前運行狀態概覽,啓動命令格式爲:

mongostat -h 127.0.0.1:27017 -u root -p 123456

若是沒有設置用戶名和密碼可省略-u及之後代碼

F:\mongodb\bin>mongostat -h 127.0.0.1:27017
insert query update delete getmore command dirty used flushes vsize   res qrw arw net_in net_out conn                time
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   157b   45.1k    2 Dec 14 16:14:29.989
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   157b   45.2k    2 Dec 14 16:14:30.990
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   158b   45.5k    2 Dec 14 16:14:31.986
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   157b   45.2k    2 Dec 14 16:14:32.987
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   157b   45.2k    2 Dec 14 16:14:33.989
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   158b   45.3k    2 Dec 14 16:14:34.988
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  269M 14.0M 0|0 0|0   157b   45.3k    2 Dec 14 16:14:35.988

複製代碼

字段解釋:

名字段 說明
insert/s 官方解釋是每秒插入數據庫的對象數量,若是是slave,則數值前有*,則表示複製集操做
query/s 每秒的查詢操做次數
update/s 每秒的更新操做次數
delete/s 每秒的刪除操做次數
getmore/s 每秒查詢cursor(遊標)時的getmore操做數
command 每秒執行的命令數,在主從系統中會顯示兩個值(例如 3|0),分表表明 本地|複製 命令。注: 一秒內執行的命令數好比批量插入,只認爲是一條命令(因此意義應該不大)
dirty 僅僅針對WiredTiger引擎,官網解釋是髒數據字節的緩存百分比
used 僅僅針對WiredTiger引擎,官網解釋是正在使用中的緩存百分比
flushes For WiredTiger引擎:指checkpoint的觸發次數在一個輪詢間隔期間;For MMAPv1 引擎:每秒執行fsync將數據寫入硬盤的次數。注:通常都是0,間斷性會是1, 經過計算兩個1之間的間隔時間,能夠大體瞭解多長時間flush一次。flush開銷是很大的,若是頻繁的flush,可能就要找找緣由了
vsize 虛擬內存使用量,單位MB (這是 在mongostat 最後一次調用的總數據)
res 物理內存使用量,單位MB (這是 在mongostat 最後一次調用的總數據)。注:這個和你用top看到的同樣, vsize通常不會有大的變更, res會慢慢的上升,若是res常常忽然降低,去查查是否有別的程序狂吃內存。
qr 客戶端等待從MongoDB實例讀數據的隊列長度
qw 客戶端等待從MongoDB實例寫入數據的隊列長度。
ar 執行讀操做的活躍客戶端數量
aw 執行寫操做的活客戶端數量。注:若是這兩個數值很大,那麼就是DB被堵住了,DB的處理速度不及請求速度。看看是否有開銷很大的慢查詢。若是查詢一切正常,確實是負載很大,就須要加機器了
netIn MongoDB實例的網絡進流量
netOut MongoDB實例的網絡出流量。注:此兩項字段表名網絡帶寬壓力,通常狀況下,不會成爲瓶頸
conn 打開鏈接的總數,是qr,qw,ar,aw的總和

注:MongoDB爲每個鏈接建立一個線程,線程的建立與釋放也會有開銷,因此儘可能要適當配置鏈接數的啓動參數,maxIncomingConnections,阿里工程師建議在5000如下,基本知足多數場景。

profile集合

> db.system.profile.find()
複製代碼

這種方式是將全部日誌新建了一個數據庫存儲進去的,對性能有較大影響,不推薦這種方式。

日誌

咱們也能夠在mongodb的日誌中查看操做的詳細信息,而且能夠經過conf/mongod.conf中的verbose參數進行配置,verbose的有v-vvvvv五個等級,等級越高,日誌越詳細,能夠經過log/mongod.log文件查看mongodb的日誌信息。

explain

explain()可以提供大量與查詢相關的信息。對於速度比較慢的查詢來講,這是最重要的診斷工具之一。經過查看一個查詢的explain()輸出信息,能夠知道查詢使用了哪一個索引,以及是如何使用的。

最多見的explain()的輸出有兩種類型:使用索引的查詢和沒有使用索引的查詢。

  1. 沒有使用索引時
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 1001,
    "nscanned" : 1001,
    "nscannedObjectsAllPlans" : 1001,
    "nscannedAllPlans" : 1001,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 7,
    "nChunkSkips" : 0,
    "millis" : 1,
    "server" : "user:27017",
    "filterSet" : false
}
複製代碼
  1. 使用索引時
{
    "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" : [
            [
                "user1000",
                "user1000"
            ]
        ]
    },
    "server" : "user:27017",
    "filterSet" : false
}
複製代碼

下面咱們以有索引的結果爲例,來依次看一下這些字段表明的意思。

  • "cursor" : "BtreeCursor username_1" BtreeCursor表示本次查詢使用了索引,具體來講,是使用了「username」上的索引{「username」:1}。若是查詢要對結果進行逆序遍歷,或者使用了多鍵索引,就能夠在這個字段中看到「reverse」和「multi」這樣的值。

  • "isMultiKey" : false 用於說明本次是否使用了多鍵索引。

  • "n" : 1 本次查詢返回的文檔數量

  • "nscannedObjects" : 1 這是MongoDB按照索引指針去磁盤上查找實際文檔的次數。若是查詢包含的查詢條件不是索引的一部分,或者說要求返回不在索引內的字段,MongoDB就必須依次查找每一個索引條目指向的文檔。

  • "nscanned" : 1 若是有使用索引,那麼這個數字就是查找過的索引條目數量,若是本次查詢是一次全表掃描,那麼這個數字就表明檢查過的文檔數目。

  • "scanAndOrder" : false MongoDB是否在內存中對結果集進行了排序

  • "indexOnly" : false MongoDB是否只使用索引就能完成這次查詢。在本例中,MongoDB只使用索引就找到了所有的匹配文檔,從「nscanned」和「n」相等就能夠看出來。然而,本次查詢要就返回匹配文檔中的全部字段,而索引只包含「username」這個字段,若是就本次查詢修改成{"_id":0, "username":1},那麼本次查詢就能夠被索引覆蓋了,"indexOnly"的值就會是true。

  • "nYields" : 0 爲了讓寫入請求可以順利執行,本次查詢暫停暫停的次數。若是有寫入請求需求處理,查詢會週期性的釋放他們的鎖,以便寫入可以順利執行。然而,在本次查詢中,沒有寫入請求,所以查詢沒有暫停過。

  • "millis" : 0 數據庫執行本次查詢所耗費的毫秒數。這個數字越小,說明效率越高。

  • "indexBounds" : {...} 這個字段描述了索引的使用狀況,給出了索引的遍歷範圍。因爲這次查詢是精確匹配,因此因此只要查「user1000」這個值就能夠了。

歡迎各路大佬對文章錯誤的地方進行指正,萬分感謝,共同窗習進步。博主的GitHub地址,能夠在GitHub提Issues或者直接在文章下面評論區留言。
相關文章
相關標籤/搜索