Ho una raccolta di documenti utente, in cui ogni utente può disporre di un insieme arbitrario di proprietà. Ogni utente è associato a un documento dell'app. Ecco un utente di esempio:
{
"appId": "XXXXXXX",
"properties": [
{ "name": "age", "value": 30 },
{ "name": "gender", "value": "female" },
{ "name": "alive", "value": true }
]
}
Vorrei poter trovare/contare gli utenti in base ai valori delle loro proprietà. Ad esempio, trovami tutti gli utenti dell'app X che hanno proprietà Y> 10 e Z è uguale a true.
Ho un composto, indice multikey su questa collezione db.users.ensureIndex({ "appId": 1, "properties.name": 1, "properties.value": 1})
. Questo indice sta lavorando bene per singola condizione query, es:
db.users.find({
appId: 'XXXXXX',
properties: {
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
}
})
La query sopra completa in < 300ms con un insieme di utenti 1M. Tuttavia, quando provo ad aggiungere una seconda condizione, le prestazioni si riducono notevolmente (7-8s) e l'output explain()
indica che l'intero indice viene sottoposto a scansione per soddisfare la query ("nscanned" : 2752228
).
Query
db.users.find({
appId: 'XXXXXX',
properties: {
$all: [
{
$elemMatch: {
name: 'age',
value: {
$gt: 10
}
}
},
{
$elemMatch: {
name: 'alive',
value: true
}
}
]
}
})
Spiegare
{
"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
}
Presumo che ciò è dovuto al fatto Mongo non è in grado di creare limiti adeguati dal momento che sono alla ricerca di entrambi i valori booleani e interi.
La mia domanda è questa: c'è un modo migliore per strutturare i miei dati o modificare la mia query per migliorare le prestazioni e sfruttare meglio il mio indice? È possibile indicare a mongo di trattare ogni condizione separatamente, generare limiti appropriati e quindi eseguire l'intersezione dei risultati, invece di eseguire la scansione di tutti i documenti? O il mongo non è adatto a questo tipo di casi d'uso?
si utilizza una versione 2.6 di MongoDB , destra? Non riesco a riprodurre questo - in 3.0-rc8, la query è veloce, cioè non esegue la scansione degli oggetti. – mnemosyn
@mnemosyn sì, sto usando v2.6.7 – michaels
Beh, forse 3.0-rc8 può risolvere il tuo problema? Almeno se sei disposto ad usare un candidato in produzione in produzione ... – mnemosyn