1

MongoDB コレクションの文字列の配列に対して正規表現クエリを実行しようとしています。ドキュメントでのみこの制限を見つけることができました:

$regex は、正規表現が文字列の先頭 (つまり ^) のアンカーを持ち、大文字と小文字を区別する一致である 場合にのみ、インデックスを効率的に使用できます。

テストをしましょう:

> 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"
}

クエリが遅いです。一方、このクエリは最適です: (ただし、私のユースケースには適していません)

> 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"
}

インデックスがある場合、正規表現クエリがすべての (サブ) レコードをスキャンするのはなぜですか? 私は何が欠けていますか?

4

1 に答える 1

1

テスト ケースには、正規表現とインデックスの使用には役立たない特性がいくつかあります。

  • 各ドキュメントには、「a_」で始まる 2 つの値の配列が含まれます。正規表現/^a_(0)?_12$/は、a で始まり、その後にオプションの「0」が続く文字列を探しているため、すべてのインデックス エントリ (200k 値) の比較につながります。
  • あなたの正規表現は、すべてのドキュメントが持つ値 ( a_1_2) にも一致するため、インデックスに関係なくすべてのドキュメントに一致することになります

マルチキー (配列インデックス) があるため、インデックス比較の数は、100k ドキュメントの完全なテーブル スキャンを実行するよりも実際には悪化します。$naturalヒントでテストして、以下を確認できます。

db.test.find({f: /^a_(0|)12$/ }).hint({$natural:1}).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 100000,
    "nscanned" : 100000,
    "nscannedObjectsAllPlans" : 100000,
    "nscannedAllPlans" : 100000,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 192,
    "indexBounds" : {

    },
}

よりランダムなデータまたはより選択的な正規表現を使用すると、比較が少なくなります。

于 2013-03-22T00:15:30.403 に答える