Mam kolekcję dokumentów użytkownika, gdzie każdy użytkownik może mieć dowolny zestaw właściwości. Każdy użytkownik jest powiązany z dokumentem aplikacji. Oto przykładowy użytkownik:
{
"appId": "XXXXXXX",
"properties": [
{ "name": "age", "value": 30 },
{ "name": "gender", "value": "female" },
{ "name": "alive", "value": true }
]
}
Chciałbym móc znajdować/liczyć użytkowników na podstawie wartości ich właściwości. Na przykład znajdź dla mnie wszystkich użytkowników aplikacji X, które mają właściwość Y> 10, a Z jest prawdziwe.
Mam złożony, multikolorowy indeks na tej kolekcji db.users.ensureIndex({ "appId": 1, "properties.name": 1, "properties.value": 1})
. Wskaźnik ten działa dobrze dla pojedynczych zapytań stanie, ex:
db.users.find({
appId: 'XXXXXX',
properties: {
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
}
})
Powyższe zapytanie zakończy w < 300ms z kolekcją użytkowników 1m. Jednak gdy próbuję dodać drugi warunek, wydajność znacznie spada (7-8s), a wynik explain()
wskazuje, że cały indeks jest skanowany w celu spełnienia zapytania ("nscanned" : 2752228
).
Zapytanie
db.users.find({
appId: 'XXXXXX',
properties: {
$all: [
{
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
},
{
$elemMatch: {
name: 'alive',
value: true
}
}
]
}
})
Wyjaśnić
{
"cursor" : "BtreeCursor appId_1_properties.name_1_properties.value_1",
"isMultiKey" : true,
"n" : 256,
"nscannedObjects" : 1000000,
"nscanned" : 2752228,
"nscannedObjectsAllPlans" : 1018802,
"nscannedAllPlans" : 2771030,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 21648,
"nChunkSkips" : 0,
"millis" : 7425,
"indexBounds" : {
"appId" : [
[
"XXXXX",
"XXXXX"
]
],
"properties.name" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"properties.value" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"filterSet" : false
}
Zakładam, to dlatego, że Mongo jest w stanie stworzyć odpowiednie granice, ponieważ szukam obu wartości logicznych i całkowitych.
Moje pytanie brzmi: czy istnieje lepszy sposób na uporządkowanie moich danych lub zmodyfikowanie zapytania w celu poprawy wydajności i lepszego wykorzystania mojego indeksu? Czy można nakazać mongo traktować każdy warunek osobno, generować odpowiednie granice, a następnie wykonywać przecięcia wyników, zamiast skanować wszystkie dokumenty? A może mongo po prostu nie nadaje się do tego typu przypadków?
używasz wersji 2.6 MongoDB , dobrze? Nie mogę tego odtworzyć - w 3.0-rc8 zapytanie jest szybkie, tzn. Nie skanuje obiektów. – mnemosyn
@mnemosyn tak, używam v2.6.7 – michaels
Cóż, może 3.0-rc8 może rozwiązać twój problem? Przynajmniej jeśli chcesz użyć kandydata do wydania w wersji produkcyjnej ... – mnemosyn