2013-07-12 144 views
0

我目前開發的系統,使用MongoDB 2.4.4MongoDB發現緩慢與正則表達式

我有一個用戶的集合。

有一個組合索引:{ "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 我也試圖與單一的指標,沒有性能提升

該系統包含400.000測試記錄。

查詢(從org.springframework.data.mongodb.core.query.Query爪哇調試):16ms.That內

{ "LASTNAME" : { "$regex" : "^Schm"}}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 ,"LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

執行是奇妙。

該查詢未在MongoDB控制檯中顯示(不在此處發佈調試信息)。

但是,我喜歡搜索不僅從頭開始,它也應該是不區分大小寫的。

查詢:內897ms

{ "LASTNAME" : { "$regex" : "^Schm" , "$options" : "i"}}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

執行。這是不可接受的緩慢。

蒙戈控制檯顯示此:

query: { query: { LASTNAME: /^Schm/i }, 
    orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY:1, STATUS: 1 } 
} cursorid:1252405545564528 ntoreturn:25 ntoskip:0 nscanned:297651 
keyUpdates:0 numYields: 1 locks(micros) r:1391715 nreturned:25 reslen:4422 897ms 

正如人們所看到。這不是指向索引問題的scanAndOrder問題。

然後,我試圖解決它的下一個方法是什麼適合大多數情況下(插入從用戶,小寫和大寫),但也是較慢。我的期望是,它執行三次與第一次查詢一樣長。

查詢:1300ms內

{ "$or" : [ { "LASTNAME" : { "$regex" : "^Schm"}} , { "LASTNAME" : { "$regex" : "^schm"}} , { "LASTNAME" : { "$regex" : "^SCHM"}}]}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

執行。沒什麼好說的。

MongoDB的控制檯:

query: { query: { $or: [ { LASTNAME: /^Schm/ }, { LASTNAME: /^schm/ }, { LASTNAME: /^SCHM/ } ] }, 
    orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY: 1, STATUS: 1 } 
} cursorid:43560166842085 ntoreturn:25 ntoskip:0 nscanned:297651 
keyUpdates:0 numYields: 1 locks(micros) r:1531168 nreturned:25 reslen:4422 1300ms 

所以,我怎麼可以搜索不區分大小寫,近有第一搜索的速度? 最大150ms!

+0

作爲一個方面說明,我已經刪除了Java標記,因爲這個問題只與Mongo相關,而不是Java –

+0

您可以請您爲'$或'查詢發佈'explain()' –

+0

我不知道如何,使用Spring MongoTemplate。目前正在考慮切換到mongo-java-driver ... – Nabor

回答

7

只要您添加不區分大小寫,就不能再使用索引。在構建需要支持搜索的應用程序時,這是一個重要的設計問題。

爲了解決這個問題,您應該在另一個字段中存儲一個已經小寫的姓氏,並且以大小寫敏感的方式進行查詢(顯然在將所有搜索查詢傳遞給Mongo之前將其轉換爲小寫)。

編輯

它看起來像文本搜索已經在2.4被添加。閱讀關於它here,看看是否會做你所需要的。作爲一個方面說明,如果你真的關心性能(根據你的問題來判斷,這聽起來像你可能),你應該真的重新考慮對數據存儲引擎進行搜索。考慮一個替代的搜索引擎,例如ElasticSearch(或簡單的Lucene索引),以保持搜索流量離開主數據存儲。

+1

「只要您添加不區分大小寫,您就無法更長時間使用索引「< - +1」。這就像人們抱怨說他們的SQL查詢在使用'trunc()'的日期很慢。 – fge

+0

但是,爲什麼這個或解決方案如此噁心? – Nabor

+0

@Nabor無論你的'$ or'解決方案爲什麼如此緩慢(我相信這是因爲Mongo正在迴歸索引掃描,因爲你已經給它3個可能的「根」來搜索),你應該問是否不管它是否值得你的時間。您是否真的要爲查詢中的每個字母使用每個有效的套管排列構造'$ or'查詢,作爲避免不區分大小寫搜索的一種方式?這不會更快。索引與否。 –