2012-04-13 30 views
3

** UPDATE **MongoDB中的指標如何呈現查詢慢?

我張貼的答案,因爲它是被證實是一個問題

** ORIGINAL **

首先,我向你道歉 - 我剛開始昨天使用MongoDB,而且我在這方面還很新。我有一個非常簡單的查詢,並使用PHP我發現此:

蒙戈的版本是2.0.4,在CentOS 6.2上運行(決賽)64

$start = microtime(true); 
$totalactive = $db->people->count(array('items'=> array('$gt' => 1))); 
$end = microtime(true); 
printf("Query lasted %.2f seconds\n", $end - $start); 

沒有索引,則返回:

Query lasted 0.15 seconds 

我有28萬條記錄在人們的數據庫。所以我想加入的「項目」的指標應該是有幫助的,因爲我查詢數據很多。但對我的不信,加入索引後,我得到了這個:

Query lasted 0.25 seconds 

我做錯了什麼?

相反計數的,我用的發現得到解釋,這是輸出:

> db.people.find({ 'items' : { '$gte' : 1 } }).explain(); 
{ 
"cursor" : "BtreeCursor items_1", 
"nscanned" : 206396, 
"nscannedObjects" : 206396, 
"n" : 206396, 
"millis" : 269, 
"nYields" : 0, 
"nChunkSkips" : 0, 
"isMultiKey" : false, 
"indexOnly" : false, 
"indexBounds" : { 
    "items" : [ 
     [ 
      1, 
      1.7976931348623157e+308 
     ] 
    ] 
} 
} 

如果我改變我的查詢是「$ NE」 0,它需要更多的10ms的!

這裏是收集統計:

> db.people.stats() 
{ 
"ns" : "stats.people", 
"count" : 281207, 
"size" : 23621416, 
"avgObjSize" : 84.00009957077881, 
"storageSize" : 33333248, 
"numExtents" : 8, 
"nindexes" : 2, 
"lastExtentSize" : 12083200, 
"paddingFactor" : 1, 
"flags" : 0, 
"totalIndexSize" : 21412944, 
"indexSizes" : { 
    "_id_" : 14324352, 
    "items_1" : 7088592 
}, 
"ok" : 1 
} 

我有免費的RAM爲1GB,所以我相信指數裝入內存。

這裏的人指數,如要求:

> db.people.getIndexes() 
[ 
{ 
    "v" : 1, 
    "key" : { 
     "_id" : 1 
    }, 
    "ns" : "stats.people", 
    "name" : "_id_" 
}, 
{ 
    "v" : 1, 
    "key" : { 
     "items" : 1 
    }, 
    "ns" : "stats.people", 
    "name" : "items_1" 
} 
] 
+0

這真的很有趣。嘗試使用linux'time'命令來定時多次迭代。 – 2012-04-13 02:49:26

+0

你在使用什麼版本的MongoDB? – Thilo 2012-04-13 02:57:12

+0

增加了版本,thx – ruinernix 2012-04-13 03:01:30

回答

1

這被證實是一個需要優化MongoDB的引擎中的錯誤或東西。我在蒙戈郵件列表中發佈這個和響應我從艾略特霍洛維茨

這絕對是一個錯誤,或者至少可能是更好的方式 優化的路徑接收。做了一個案例:https://jira.mongodb.org/browse/SERVER-5607

Priority: Major 
Fix Version/s: 2.3 desired 
Type: Bug 

感謝那些誰幫助確認這是一個錯誤=)

0

通過索引可以是有益的,原因有二:

  1. 只訪問收藏的一小部分時(因爲限制性過濾器可以通過索引滿足)。經驗法則不到10%。

  2. 當收集不需要在所有被訪問(因爲所有必要的數據是在索引中,既爲過濾和結果集)。這將由「indexOnly = true」指示。

對於「發現」查詢,無論這是不是真的:您正在訪問幾乎全收(206396出281207),需要各個領域的數據。所以,你會經過索引,然後再經過幾乎整個集合無論如何,擊敗指數的目的。只是閱讀整個集合會更快。

我本來期望的「計數」的查詢性能更好(因爲這可以通過只通過索引去滿足)。你能解釋一下嗎?

+0

你不能做一個計數解釋 – ruinernix 2012-04-13 02:58:57

+0

必須有一種方法...我會問:http:///stackoverflow.com/questions/10134716/how-to-get-an-explain-for-a-mongodb-count – Thilo 2012-04-13 03:03:11

+0

我喜歡你的解釋,但在這種情況下,只有索引應該使用(計數) - 我試圖做一個查找指定「items」作爲返回字段,它仍然顯示indexOnly爲false。 – ruinernix 2012-04-13 03:10:26

1

看這個:

http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ#IndexingAdviceandFAQ-5.MongoDB%27s%24neor%24ninoperator%27saren%27tefficientwithindexes

這讓我想到了這個解決方案。這個怎麼樣?

$totalactive = $db->people->count() - $db->people->count(array('items'=> array('$eq' => 1))); 
+0

這絕對是更快。對於相同的結果,我得到0.09ms而不是0.25ms/0.35ms。 – ruinernix 2012-04-13 03:19:40

+0

WOOOOOOOO !!!!那是在黑暗中拍攝的! – 2012-04-13 03:20:37

+0

但是,如果您擁有此索引,Count($ gt:1)應該通常比Count()更快。你在這個索引中是否有很多數據偏差(即大多數數據爲0或1)? – Thilo 2012-04-13 03:25:07

0

您能否提供一個這個集合中的對象的例子? 「items」字段是一個數組?如果是這樣,我會建議你添加一個新的字段「itemCount」,並把一個索引。在這個領域做$ gt將會非常快。

+0

項目是一個數字,集合非常小。它類似於:{「slots」:50,「last_update」:1334325643,「_id」:「128713871987491」,「items」:0} – ruinernix 2012-04-13 14:01:41

0

這是因爲您的查詢是近乎完整的收集掃描。查詢優化器正在挑選使用該索引,而不應該使用索引來獲得最佳性能。這是違反直覺的,但是,這是因爲光標在索引b-tree上行走並獲取樹指向的文檔,如果它必須掃描幾乎整棵樹,那麼比僅僅走集合要慢。

如果您確實需要執行此類查詢,並且您希望將該索引用於其他操作(如排序),則可以使用.hint({$natural: 1})來告訴查詢不使用索引。

巧合的是,我在博客張貼有關類似問題最近:http://wes.skeweredrook.com/testing-with-mongodb-part-1/

+0

我在mongo郵件列表上發佈了我的發現,而Eliot(10gen的首席技術官)迴應說,這確實是一個錯誤,或者是需要優化的東西。它已被添加爲一個主要問題:https://jira.mongodb.org/browse/SERVER-5607 - 我要關閉這一個。 – ruinernix 2012-04-15 13:37:27