国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

MongoDB指南---12、使用explain()和hint()、何時不應該使用索引

LiangJ / 2058人閱讀

摘要:表示本次查詢使用了索引,具體來說,是使用了和上的索引,。建立索引時,或者是每執行次查詢之后,查詢優化器都會重新評估查詢計劃。上一篇文章指南使用復合索引操作符如何使用索引索引對象和數組索引基數下一篇文章指南索引類型

上一篇文章:MongoDB指南---11、使用復合索引、$操作符如何使用索引、索引對象和數組、索引基數
下一篇文章:MongoDB指南---13、索引類型
使用explain()和hint()

從上面的內容可以看出,explain()能夠提供大量與查詢相關的信息。對于速度比較慢的查詢來說,這是最重要的診斷工具之一。通過查看一個查詢的explain()輸出信息,可以知道查詢使用了哪個索引,以及是如何使用的。對于任意查詢,都可以在最后添加一個explain()調用(與調用sort()或者limit()一樣,不過explain()必須放在最后)。
最常見的explain()輸出有兩種類型:使用索引的查詢和沒有使用索引的查詢。對于特殊類型的索引,生成的查詢計劃可能會有些許不同,但是大部分字段都是相似的。另外,分片返回的是多個explain()的聚合(第13章會介紹),因為查詢會在多個服務器上執行。
不使用索引的查詢的exlpain()是最基本的explain()類型。如果一個查詢不使用索引,是因為它使用了"BasicCursor"(基本游標)。反過來說,大部分使用索引的查詢使用的是BtreeCursor(某些特殊類型的索引,比如地理空間索引,使用的是它們自己類型的游標)。
對于使用了復合索引的查詢,最簡單情況下的explain()輸出如下所示:

> db.users.find({"age" : 42}).explain()
{
    "cursor" : "BtreeCursor age_1_username_1",
    "isMultiKey" : false,
    "n" : 8332,
    "nscannedObjects" : 8332,
    "nscanned" : 8332,
    "nscannedObjectsAllPlans" : 8332,
    "nscannedAllPlans" : 8332,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 91,
    "indexBounds" : {
        "age" : [
            [
                42,
                42
            ]
        ],
        "username" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "ubuntu:27017"
}

從輸出信息中可以看到它使用的索引是age_1_username_1。"millis"表明了這個查詢的執行速度,時間是從服務器收到請求開始一直到發出響應為止。然而,這個數值不一定真的是你希望看到的值。如果MongoDB嘗試了多個查詢計劃,那么"millis"顯示的是這些查詢計劃花費的總時間,而不是最優查詢計劃所花的時間。
接下來是實際返回的文檔數量:"n"。它無法反映出MongoDB在執行這個查詢的過程中所做的工作:搜索了多少索引條目和文檔。索引條目是使用"nscanned"描述的。"nscannedObjects"字段的值就是所掃描的文檔數量。最后,如果要對結果集進行排序,而MongoDB無法對排序使用索引,那么"scanAndOrder"的值就會是true。也就是說,MongoDB不得不在內存中對結果進行排序,這是非常慢的,而且結果集的數量要比較小。
現在你已經知道這些基礎知識了,接下來依次詳細介紹這些字段。

"cursor" : "BtreeCursor age_1_username_1"

BtreeCursor表示本次查詢使用了索引,具體來說,是使用了"age"和"username"上的索引{"age" : 1, "username" : 1}。如果查詢要對結果進行逆序遍歷,或者是使用了多鍵索引,就可以在這個字段中看到"reverse"和"multi"這樣的值。

"isMultiKey" : false

用于說明本次查詢是否使用了多鍵索引(詳見5.1.4節)。

"n" : 8332

本次查詢返回的文檔數量。

"nscannedObjects" : 8332

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

"nscanned" : 8332

如果有使用索引,那么這個數字就是查找過的索引條目數量。如果本次查詢是一次全表掃描,那么這個數字就表示檢查過的文檔數量。

"scanAndOrder" : false

MongoDB是否在內存中對結果集進行了排序。

"indexOnly" : false

MongoDB是否只使用索引就能完成此次查詢(詳見“覆蓋索引”部分)。
在本例中,MongoDB只使用索引就找到了全部的匹配文檔,從"nscanned"和"n"相等就可以看出來。然而,本次查詢要求返回匹配文檔中的所有字段,而索引只包含"age"和"username"兩個字段。如果將本次查詢修改為({"_id" : 0, "age" : 1, "username" : 1}),那么本次查詢就可以被索引覆蓋了,"indexOnly"的值就會是true。

"nYields" : 0

為了讓寫入請求能夠順利執行,本次查詢暫停的次數。如果有寫入請求需要處理,查詢會周期性地釋放它們的鎖,以便寫入能夠順利執行。然而,在本次查詢中,沒有寫入請求,因為查詢沒有暫停過。

"millis" : 91

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

"indexBounds" : {...}

這個字段描述了索引的使用情況,給出了索引的遍歷范圍。由于查詢中的第一個語句是精確匹配,因此索引只需要查找42這個值就可以了。本次查詢沒有指定第二個索引鍵,因此這個索引鍵上沒有限制,數據庫會在"age"為42的條目中將用戶名介于負無窮("$minElement" : 1)和正無窮("$maxElement" : 1)的條目都找出來。
再來看一個稍微復雜點的例子:假如有一個{"user name" : 1, "age" : 1}上的索引和一個 {"age" : 1, "username" : 1}上的索引。同時查詢"username"和"age"時,會發生什么情況?呃,這取決于具體的查詢:

> db.c.find({age : {$gt : 10}, username : "sally"}).explain()
{
    "cursor" : "BtreeCursor username_1_age_1",
    "indexBounds" : [
        [
            {
                "username" : "sally",
                "age" : 10
            },
            {
                "username" : "sally",
                "age" : 1.7976931348623157e+308
            }
        ]
    ],
    "nscanned" : 13,
    "nscannedObjects" : 13,
    "n" : 13,
    "millis" : 5
}

由于在要在"username"上執行精確匹配,在"age"上進行范圍查詢,因此,數據庫選擇使用{"username" : 1, "age" : 1}索引,這與查詢語句的順序相反。另一方面來說,如果需要對"age"精確匹配而對"username"進行范圍查詢,MongoDB就會使用另一個索引:

> db.c.find({"age" : 14, "username" : /.*/}).explain()
{
    "cursor" : "BtreeCursor age_1_username_1 multi",
    "indexBounds" : [
        [
            {
                "age" : 14,
                "username" : ""
            },
            {
                "age" : 14,
                "username" : {
                }
            }
        ],
        [
            {
                "age" : 14,
                "username" : /.*/
            },
            {
                "age" : 14,
                "username" : /.*/
            }
        ]
    ],
    "nscanned" : 2,
    "nscannedObjects" : 2,
    "n" : 2,
    "millis" : 2
}

如果發現MongoDB使用的索引與自己希望它使用的索引不一致,可以使用hit()強制MongoDB使用特定的索引。例如,如果希望MongoDB在上個例子的查詢中使用{"username" : 1, "age" : 1}索引,可以這么做:

> db.c.find({"age" : 14, "username" : /.*/}).hint({"username" : 1, "age" : 1})

如果查詢沒有使用你希望它使用的索引,于是你使用hint強制MongoDB使用某個索引,那么應該在應用程序部署之前在所指定的索引上執行explain()。如果強制MongoDB在某個查詢上使用索引,而這個查詢不知道如何使用這個索引,這樣會導致查詢效率降低,還不如不使用索引來得快。

查詢優化器

MongoDB的查詢優化器與其他數據庫稍有不同。基本來說,如果一個索引能夠精確匹配一個查詢(要查詢"x",剛好在"x"上有一個索引),那么查詢優化器就會使用這個索引。不然的話,可能會有幾個索引都適合你的查詢。MongoDB會從這些可能的索引子集中為每次查詢計劃選擇一個,這些查詢計劃是并行執行的。最早返回100個結果的就是勝者,其他的查詢計劃就會被中止。
這個查詢計劃會被緩存,這個查詢接下來都會使用它,直到集合數據發生了比較大的變動。如果在最初的計劃評估之后集合發生了比較大的數據變動,查詢優化器就會重新挑選可行的查詢計劃。建立索引時,或者是每執行1000次查詢之后,查詢優化器都會重新評估查詢計劃。
explain()輸出信息里的"allPlans"字段顯示了本次查詢嘗試過的每個查詢計劃。

 何時不應該使用索引

提取較小的子數據集時,索引非常高效。也有一些查詢不使用索引會更快。結果集在原集合中所占的比例越大,索引的速度就越慢,因為使用索引需要進行兩次查找:一次是查找索引條目,一次是根據索引指針去查找相應的文檔。而全表掃描只需要進行一次查找:查找文檔。在最壞的情況下(返回集合內的所有文檔),使用索引進行的查找次數會是全表掃描的兩倍,效率會明顯比全表掃描低很多。
可惜,并沒有一個嚴格的規則可以告訴我們,如何根據數據大小、索引大小、文檔大小以及結果集的平均大小來判斷什么時候索引很有用,什么時候索引會降低查詢速度(如表5-1所示)。一般來說,如果查詢需要返回集合內30%的文檔(或者更多),那就應該對索引和全表掃描的速度進行比較。然而,這個數字可能會在2%~60%之間變動。
表5-1 影響索引效率的屬性

索引通常適用的情況 全表掃描通常適用的情況
集合較大 集合較小
文檔較大 文檔較小
選擇性查詢 非選擇性查詢

假如我們有一個收集統計信息的分析系統。應用程序要根據給定賬戶去系統中查詢所有文檔,根據從初始一直到一小時之前的數據生成圖表:

> db.entries.find({"created_at" : {"$lt" : hourAgo}})

我們在"created_at"上創建索引以提高查詢速度。
最初運行時,結果集非常小,可以立即返回。幾個星期過去以后,數據開始多起來了,一個月之后,這個查詢耗費的時間越來越長。
對于大部分應用程序來說,這很可能就是那個“錯誤的”查詢:真的需要在查詢中返回數據集中的大部分內容嗎?大部分應用程序(尤其是擁有非常大的數據集的應用程序)都不需要。然而,也有一些合理的情況,可能需要得到大部分或者全部的數據:也許需要將這些數據導出到報表系統,或者是放在批量任務中。在這些情況下,應該盡可能快地返回數據集中的內容。
可以用{"$natural" : 1}強制數據庫做全表掃描。6.1節會介紹$natural,它可以指定文檔按照磁盤上的順序排列。特別地,$natural可以強制MongoDB做全表掃描:

> db.entries.find({"created_at" : {"$lt" : hourAgo}}).hint({"$natural" : 1})

使用"$natural"排序有一個副作用:返回的結果是按照磁盤上的順序排列的。對于一個活躍的集合來說,這是沒有意義的:隨著文檔體積的增加或者縮小,文檔會在磁盤上進行移動,新的文檔會被寫入到這些文檔留下的空白位置。但是,對于只需要進行插入的工作來說,如果要得到最新的(或者最早的)文檔,使用$natural就非常有用了。

上一篇文章:MongoDB指南---11、使用復合索引、$操作符如何使用索引、索引對象和數組、索引基數
下一篇文章:MongoDB指南---13、索引類型

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/19579.html

相關文章

  • MongoDB指南---12使用explain()hint()、何時應該使用索引

    摘要:表示本次查詢使用了索引,具體來說,是使用了和上的索引,。建立索引時,或者是每執行次查詢之后,查詢優化器都會重新評估查詢計劃。上一篇文章指南使用復合索引操作符如何使用索引索引對象和數組索引基數下一篇文章指南索引類型 上一篇文章:MongoDB指南---11、使用復合索引、$操作符如何使用索引、索引對象和數組、索引基數下一篇文章:MongoDB指南---13、索引類型 使用explain...

    DTeam 評論0 收藏0
  • MongoDB指南---13、索引類型、索引管理

    摘要:復合唯一索引也可以創建復合的唯一索引。中的稀疏索引與關系型數據庫中的稀疏索引是完全不同的概念。但是這里不會指明索引是否是多鍵索引。上一篇文章指南使用和何時不應該使用索引下一篇文章指南特殊的索引和集合固定集合索引全文本索引 上一篇文章:MongoDB指南---12、使用explain()和hint()、何時不應該使用索引下一篇文章:MongoDB指南---14、特殊的索引和集合:固定集合...

    Enlightenment 評論0 收藏0
  • MongoDB指南---13、索引類型、索引管理

    摘要:復合唯一索引也可以創建復合的唯一索引。中的稀疏索引與關系型數據庫中的稀疏索引是完全不同的概念。但是這里不會指明索引是否是多鍵索引。上一篇文章指南使用和何時不應該使用索引下一篇文章指南特殊的索引和集合固定集合索引全文本索引 上一篇文章:MongoDB指南---12、使用explain()和hint()、何時不應該使用索引下一篇文章:MongoDB指南---14、特殊的索引和集合:固定集合...

    seanHai 評論0 收藏0
  • MongoDB指南---11、使用復合索引、$操作符如何使用索引索引對象數組、索引基數

    摘要:操作符如何使用索引有一些查詢完全無法使用索引,也有一些查詢能夠比其他查詢更高效地使用索引。有時能夠使用索引,但是通常它并不知道要如何使用索引。索引對象和數組允許深入文檔內部,對嵌套字段和數組建立索引。 上一篇文章:MongoDB指南---10、索引、復合索引 簡介下一篇文章:MongoDB指南---12、使用explain()和hint()、何時不應該使用索引 1、使用復合索引 在多...

    saucxs 評論0 收藏0
  • MongoDB指南---11、使用復合索引、$操作符如何使用索引索引對象數組、索引基數

    摘要:操作符如何使用索引有一些查詢完全無法使用索引,也有一些查詢能夠比其他查詢更高效地使用索引。有時能夠使用索引,但是通常它并不知道要如何使用索引。索引對象和數組允許深入文檔內部,對嵌套字段和數組建立索引。 上一篇文章:MongoDB指南---10、索引、復合索引 簡介下一篇文章:MongoDB指南---12、使用explain()和hint()、何時不應該使用索引 1、使用復合索引 在多...

    tomlingtm 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<