我想對MongoDB集合中的字符串數組執行正則表達式查詢。我只能找到這個限制在docs:爲什麼在MongoDB中對索引數組的正則表達式前綴查詢很慢?
$正則表達式只能有效地使用索引時正則表達式 有一個字符串的錨開始時(即^),是一個 情況敏感匹配。
讓我們做一個試驗:
> for (var i=0; i<100000; i++) db.test.insert({f: ['a_0_'+i, 'a_1_2']})
> db.test.count()
100000
> db.test.ensureIndex({f: 1})
> db.test.find({f: /^a_(0)?_12$/ })
{ "_id" : ObjectId("514ac59886f004fe03ef2a96"), "f" : [ "a_0_12", "a_1_2" ] }
> db.test.find({f: /^a_(0)?_12$/ }).explain()
{
"cursor" : "BtreeCursor f_1 multi",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 200000,
"nscanned" : 200000,
"nscannedObjectsAllPlans" : 200000,
"nscannedAllPlans" : 200000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 482,
"indexBounds" : {
"f" : [
[
"a_",
"a`"
],
[
/^a_(0)?_12$/,
/^a_(0)?_12$/
]
]
},
"server" : "someserver:27017"
}
查詢是sloooow。在另一方面,這種查詢是最優的:(但不適合我的使用情況)
> db.test.find({f: 'a_0_12' }).explain()
{
"cursor" : "BtreeCursor f_1",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"f" : [
[
"a_0_12",
"a_0_12"
]
]
},
"server" : "someserver:27017"
}
爲什麼正則表達式查詢掃描所有(子)記錄時,它有一個指數?我錯過了什麼?
它不能快。除了他們爲「開始」所做的簡單優化之外,搜索需要查看每個使用這些字符的文檔並在每個文檔上運行正則表達式。 – WiredPrairie 2013-03-21 10:43:13
爲什麼會這樣?至少對於這個正則表達式,我沒有理由不能優化它。誠然,正則表達式狀態引擎需要與搜索結合,但我認爲這就是MongoDB正在做的事情。如果沒有,它是否僅僅在「(」和使用索引之前,一個一個地遍歷和檢查對方選項?)這只是......好吧,「不是最優的」。:)有人可以證實這一點? – johndodo 2013-03-21 14:20:24
Mongodb索引包含字段'f'的全文字符串值。沒什麼比這更重要的了。它檢查字符串的起始位置,然後它需要在與根相匹配的每個文檔上運行RegEx。 'a_'是它可以用作根的唯一部分。每個與根相匹配的文檔必須針對正則表達式的其餘部分運行。您可以通過將第二部分作爲另一個字段存儲在文檔中而不是將其嵌入到字符串中來優化它。 (然後在兩個鍵上創建一個複合索引)。 – WiredPrairie 2013-03-21 19:15:37