MongoDB入門學習(四):MongoDB的索引

        上一篇講到了MongoDB的基本操做增刪查改。對於查詢來講。必須依照咱們的查詢要求去集合中,並將查找到的結果返回。在這個過程當中事實上是對整個集合中每個文檔進行了掃描,假設知足咱們的要求就加入到結果集中最後返回。對於小集合來講。這個過程沒什麼,但是集合中數據很是大的時候,進行表掃描是一個很是恐怖的事情,因而有了索引一說,索引是用來加速查詢的。至關於書籍的文件夾。有了文件夾可以很是精準的定位要查找內容的位置,從而下降無謂的查找。css

1.索引的類型html

        建立索引可以是在單個字段上,也可以是在多個字段上,這個依據本身的實際狀況來選擇,建立索引時字段的順序也是有講究的。數據庫

建立索引是經過ensureIndex()方法。需要給該方法傳遞一個文檔形式的數據,當中指定索引的字段和順序,1表明升序。-1表明降序。數組

        1).默認索引dom

           還記得"_id"嗎,這個字段的數據是不能反覆的。它就是MongoDB的默認索引。而且不能被刪除。工具

        2).單列索引post

           在單個字段上建立的索引就是單列索引,在查詢的過程當中可以對該加速對該鍵的查詢,然而對其它鍵的查詢是沒有幫助的。spa

單列索引的順序是不會影響對該鍵的隨即查詢。建立單列索引:.net

> db.people.ensureIndex({"name" : 1})

        3).組合索引code

           還可以在多個鍵上建立組合索引,此時鍵的位置和索引的順序都會影響查詢的效率。看如下建立組合索引:

> db.people.ensureIndex({"name" : 1, "age" : 1})
> db.people.ensureIndex({"age" : 1, "name" : 1})

           第一種狀況會對name排序組織,當name同樣時在對age排序,因此對{"name" : 1}和{「name」 : 1, "age" : 1}的查詢更高效,而另一種狀況則對age排序。當age同樣再對name排序。因此對{"age" : 1}和{"age" : 1, "name" : 1}的查詢更高效。當組合索引包括很是多字段的時候。會對前幾個鍵的查詢有幫助。

        4).內嵌文檔索引

           還可以對內嵌文檔建立索引,和普通鍵建立索引同樣幾乎相同。也可以對內嵌文檔建立組合索引:

> db.people.ensureIndex({"friends.name" : 1})
> db.people.ensureIndex({"friends.name" : 1, "friends.age" : 1})

        在來看看其它幾種形式的索引:

惟一索引
> db.people.ensureIndex({"name" : 1}, {"unique" : true})
> db.people.ensureIndex({"name" : 1}, {"unique" : true, "dropDups" : true})
鬆散索引
> db.people.ensureIndex({"name" : 1}, {"sparse" : true})
多值索引
> db.people.find()
{"name" : ["mary", "rose"]}
> db.people.ensureIndex({"name" : 1})

        惟一索引unique可以保證該鍵相應的值在集合中是惟一的,假設建立惟一索引的時候,該字段原來就存在了反覆的數據,那麼就會建立失敗,可以加上dropDups字段來消除反覆數據。它會保留髮現的第一個文檔。其它有反覆數據的文檔都將被刪除。

        集合中有的文檔不存在某些字段。或者某些字段的值爲null,那麼咱們在該字段上建立索引的時候不但願讓這些空值的文檔參與。那麼就定義爲鬆散索引sparse。比方在name上建立索引時,發現有的人在數據庫中僅僅有學號。沒有名字。那麼咱們不但願把它們也包括進來。此時就定義爲鬆散索引。

        一個鍵相應的值是一個數組,在該鍵上建立索引時是一個多值索引。會爲數組中每個值生成一個索引元素。至關於分裂成了幾個獨立的索引項,但是它們仍是相應同一個文檔數據。

2.索引的管理

        索引當然是爲查詢而生,而且可以爲每個鍵都建立索引。但是索引是需要存儲空間的,因此索引不是越多越好,而且建立索引後。每次的插入,更新和刪除文檔都會產生額外的開銷,因爲數據庫中不但要運行這些操做,而且還要在集合索引中標記這些操做。因此要依據實際狀況來建立索引,索引沒用以後將其刪除。

        建立索引是ensureIndex()方法,建立完畢後可以經過getIndexes()來查看集合中建立的索引狀況:

> db.people.ensureIndex({"name" : 1, "age" : 1})
> db.people.getIndexes()
[
        {
                "v" : 1,
                "key" : {
                        "_id" : 1
                },
                "ns" : "test.people",
                "name" : "_id_"
        },
        {
                "v" : 1,
                "key" : {
                        "name" : 1,
                        "age" : 1
                },
                "ns" : "test.people",
                "name" : "name_1_age_1"
        }
]

        可以看到people集合建立了兩個索引,一個是"_id",這個是默認索引。另一個是name和age的組合索引,名字爲keyname1_dir_keyname2_dir_...,keyname表明索引的鍵,dir表明方向。1表明升序,-1表明降序。

固然咱們也可以本身定義索引的名稱:

> db.people.ensureIndex({"name" : 1, "age" : 1}, {"name" : "myIndex"})
> db.people.getIndexes()
[
        {
                "v" : 1,
                "key" : {
                        "_id" : 1
                },
                "ns" : "test.people",
                "name" : "_id_"
        },
        {
                "v" : 1,
                "key" : {
                        "name" : 1,
                        "age" : 1
                },
                "ns" : "test.people",
                "name" : "myIndex"
        }
]

        刪除索引是經過dropIndex():

方式一:
> db.people.dropIndex({"name" : 1, "age" : 1})
{ "nIndexesWas" : 2, "ok" : 1 }
方式二:
> db.runCommand({"dropIndexes" : "people", "index" : "myIndex"})
{ "nIndexesWas" : 2, "ok" : 1 }

        索引的元信息存儲在每個數據庫的system.indexes集合中。不能對其進行插入和刪除文檔的操做。僅僅能經過ensureIndex和dropIndex進行。

> db.system.indexes.find()
{ "v" : 1, "key" : { "_id" : 1 }, "ns" : "test.people", "name" : "_id_" }
{ "v" : 1, "key" : { "name" : 1, "age" : 1 }, "ns" : "test.people", "name" : "myIndex" }

        清空集合中全部的文檔是不會將索引刪除的,原來建立的索引依舊存在,但是直接刪除集合的話,該集合的索引也是會被刪除的。

3.索引的效率

        假設咱們定義了很是多的索引,那麼MongoDB會依據咱們的查詢選項又一次排序,並智能的選擇一個最優的來使用。比方咱們建立了{"name" : 1, "age" : 1}和{"age" : 1, "class" : 1}兩個索引,但是咱們的查詢項爲find({"age" : 10, "name" : "mary"}),那麼MongoDB會本身主動又一次排序爲find({"name" : "mary", "age" : 10}),而且利用索引{"name" : 1, "age" : 1}來查詢。

        MongoDB提供了explain工具來幫助咱們得到查詢方面的很是多實用信息,僅僅要對遊標調用這種方法就可以獲得查詢的細節。如下給math集合中加入10W個文檔。再來看看使用索引先後的效率對照:

> var arr = [];
> for(var i = 0; i < 100000; i++){
... var doc = {};
... var value = Math.floor(Math.random() * 1000);
... doc["number"] = value;
... arr.push(doc);
... }
100000
> db.math.insert(arr)
> db.math.count()
100000
> db.math.find().limit(10)
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe5"), "number" : 462 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe6"), "number" : 123 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe7"), "number" : 90 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe8"), "number" : 46 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fe9"), "number" : 244 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fea"), "number" : 972 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61feb"), "number" : 925 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fec"), "number" : 110 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fed"), "number" : 739 }
{ "_id" : ObjectId("53a7f7c6e4fd24348ce61fee"), "number" : 945 }

        經過for循環給arr數組中加入10W條數據。而後再批量插入這些數據到math集合中。查看前10條數據,因爲是隨即生成的值。因此number字段的值會有反覆值。咱們就來查詢462這個值:

建立索引前:
> db.math.find({"number" : 462}).explain()
{
        "cursor" : "BasicCursor",
        "isMultiKey" : false,
        "n" : 94,
        "nscannedObjects" : 100000,
        "nscanned" : 100000,
        "nscannedObjectsAllPlans" : 100000,
        "nscannedAllPlans" : 100000,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 35,
        "indexBounds" : {

        },
        "server" : "server0.169:9352"
}
建立索引後:
> db.math.ensureIndex({"number" : 1})
> db.math.find({"number" : 462}).explain()
{
        "cursor" : "BtreeCursor number_1",
        "isMultiKey" : false,
        "n" : 94,
        "nscannedObjects" : 94,
        "nscanned" : 94,
        "nscannedObjectsAllPlans" : 94,
        "nscannedAllPlans" : 94,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "number" : [
                        [
                                462,
                                462
                        ]
                ]
        },
        "server" : "server0.169:9352"
}

        這裏來看一下實用的信息,"cursor"指用的哪一個索引。"nscanned"表明查找了多少個文檔。"n"指返回文檔的數量。"millis"表示查詢所花時間。單位是毫秒。可以看出建立索引前沒有使用索引。在全部的文檔中查詢的,花費了35毫秒。而建立索引後,使用了number_1索引查詢。索引存儲在B樹結構中,僅僅在94個文檔中查詢,差點兒不花時間。

        假設有很是多索引的話,MongoDB會本身主動選一個來查詢,你也可以經過hint來強制使用某個索引,這裏強制使用{"age" : 1, "name" : 1}這個索引:

> db.people.find({"age" : {"$gt" : 10}, "name" : "mary"}).hint({"age" : 1, "name" : 1})
相關文章
相關標籤/搜索