Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB $query operator ignores index?

Tags:

mongodb

I created a test MongoDB collection "sampleCollection" with documents which looks like:

 "_id" : ObjectId("510929e041cb2179b41ace1c"),
 "stringField" : "Random string0",
 "longField" : NumberLong(886)

and has index on field "stringField". When I execute

db.sampleCollection.find({"stringField":"Random string0"}).explain()

everything is ok:

 "cursor" : "BtreeCursor stringField_1",
 "isMultiKey" : false,
 "n" : 2,
 "nscannedObjects" : 2,
 "nscanned" : 2,
 "nscannedObjectsAllPlans" : 2,
 "nscannedAllPlans" : 2,
 "scanAndOrder" : false,
 "indexOnly" : false,
 "nYields" : 0,
 "nChunkSkips" : 0,
 "millis" : 0,
 "indexBounds" : {
         "stringField" : [
                 [
                         "Random string0",
                         "Random string0"
                 ]
         ]
 }

but

db.sampleCollection.find({$query:{"stringField":"Random string0"}}).explain()

gets me

"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 4,
"nscanned" : 4,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {

}

This is not looks like a problem, but I'm using org.springframework.data.mongodb framework in production and usage of query constructions is an only way to write repositories. And thus I have a db which completely ignores indexed data.

Is it correct? Or I misunderstood something?

like image 544
FakeUser Avatar asked Jan 30 '13 16:01

FakeUser


People also ask

Does MongoDB $in use index?

MongoDB uses indexing in order to make the query processing more efficient. If there is no indexing, then the MongoDB must scan every document in the collection and retrieve only those documents that match the query.

What is not supported index in MongoDB?

Hashed Indexes To support hash based sharding, MongoDB provides a hashed index type, which indexes the hash of the value of a field. These indexes have a more random distribution of values along their range, but only support equality matches and cannot support range-based queries.

How does the $in operator work MongoDB?

For comparison of different BSON type values, see the specified BSON comparison order. If the field holds an array, then the $in operator selects the documents whose field holds an array that contains at least one element that matches a value in the specified array (for example, <value1> , <value2> , and so on).

Is it possible to index text with MongoDB?

MongoDB provides text indexes to support text search queries on string content. Text indexes can include any field whose value is a string or an array of string elements. A collection can only have one text search index, but that index can cover multiple fields.


1 Answers

That was funny i cannot decide to say it is a bug or not it is up to you:

There are two available syntax: http://docs.mongodb.org/manual/reference/operator/query/

When you using:

db.collection.find( { age : 25 } )

also will

db.collection.find( { age : 25 } ).explain()
db.collection.find( { age : 25 } ).hint(someindex)

work fine.

When you using your solution (the other syntax):

db.collection.find( { $query: { age : 25 } } )

the output of

db.sampleCollection.find({$query:{"stringField":"Random string0"}}).explain()

Will show like the query not using the index

if you also use .hint for the index it will omit the result. :) (That is i do not really understand)

Fortunately there is another syntax for these operations too: you can use:

db.sampleCollection.find({$query:{"stringField":"Random string0"}, $explain:1})

it will have the right output and showed for me the usage of the index. Also there is similar syntax for $hint.

You can check the documentation here: http://docs.mongodb.org/manual/reference/meta-query-operators/

I found this really interesting so i turned on the profiler:

i made a test collection (queryTst) with around 250k docs each with only _id and an age field in the structure with an index on age.

For this query:

db.queryTst.find({$query:{"age":16},$explain:1})

i got:

{
    "cursor" : "BtreeCursor age_1",
    "isMultiKey" : false,
    "n" : 2,
    "nscannedObjects" : 2,
    "nscanned" : 2,
    "nscannedObjectsAllPlans" : 2,
    "nscannedAllPlans" : 2,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "age" : [
            [
                16,
                16
            ]
        ]
    },
    "allPlans" : [
        {
            "cursor" : "BtreeCursor age_1",
            "n" : 2,
            "nscannedObjects" : 2,
            "nscanned" : 2,
            "indexBounds" : {
                "age" : [
                    [
                        16,
                        16
                    ]
                ]
            }
        }
    ],
    "oldPlan" : {
        "cursor" : "BtreeCursor age_1",
        "indexBounds" : {
            "age" : [
                [
                    16,
                    16
                ]
            ]
        }
    },
    "server" : ""
}

for this:

 db.queryTst.find({$query:{"age":16},$explain:1}).explain()

i got:

"cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 250011,
    "nscanned" : 250011,
    "nscannedObjectsAllPlans" : 250011,
    "nscannedAllPlans" : 250011,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 103,
    "indexBounds" : {

    },

in the profiler log: for the first

{
    "ts" : ISODate("2013-01-30T20:35:40.526Z"),
    "op" : "query",
    "ns" : "test.queryTst",
    "query" : {
        "$query" : {
            "age" : 16
        },
        "$explain" : 1
    },
    "ntoreturn" : 0,
    "ntoskip" : 0,
    "nscanned" : 2,
    "keyUpdates" : 0,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(368),
            "w" : NumberLong(0)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(8),
            "w" : NumberLong(5)
        }
    },
    "nreturned" : 1,
    "responseLength" : 567,
    "millis" : 0,
    "client" : "127.0.0.1",
    "user" : ""
}

for the second:

{
    "ts" : ISODate("2013-01-30T20:35:47.715Z"),
    "op" : "query",
    "ns" : "test.queryTst",
    "query" : {
        "query" : {
            "$query" : {
                "age" : 16
            },
            "$explain" : 1
        },
        "$explain" : true
    },
    "ntoreturn" : 0,
    "ntoskip" : 0,
    "nscanned" : 250011,
    "keyUpdates" : 0,
    "numYield" : 0,
    "lockStats" : {
        "timeLockedMicros" : {
            "r" : NumberLong(104092),
            "w" : NumberLong(0)
        },
        "timeAcquiringMicros" : {
            "r" : NumberLong(13),
            "w" : NumberLong(5)
        }
    },
    "nreturned" : 1,
    "responseLength" : 373,
    "millis" : 104,
    "client" : "127.0.0.1",
    "user" : ""
}

which somehow means to me that is the explain() cause the table scan in the mixed syntax.

like image 137
attish Avatar answered Nov 03 '22 02:11

attish